From 4df6d396b2ee928165fcba0a3bcaf634efde41cd Mon Sep 17 00:00:00 2001 From: Aleksander Nowakowski Date: Tue, 17 Feb 2015 16:00:25 +0100 Subject: [PATCH] nRF Toolbox v1.11.4 Project migrated to Android Studio and released on GitHub. --- .gitignore | 8 + .idea/.name | 1 + .idea/compiler.xml | 23 + .idea/copyright/BSD.xml | 9 + .idea/copyright/profiles_settings.xml | 7 + .idea/encodings.xml | 5 + .idea/gradle.xml | 22 + .idea/misc.xml | 10 + .idea/modules.xml | 11 + .idea/scopes/scope_settings.xml | 5 + .idea/vcs.xml | 8 + README.md | 52 + app/.gitignore | 1 + app/app.iml | 94 ++ app/build.gradle | 29 + app/libs/achartengine-1.1.0.jar | Bin 0 -> 120675 bytes app/libs/nrf-logger-v2.0.jar | Bin 0 -> 29046 bytes app/proguard-rules.pro | 17 + app/sources/nrf-logger-v2.0-source.jar | Bin 0 -> 20458 bytes .../android/nrftoolbox/ApplicationTest.java | 35 + app/src/main/AndroidManifest.xml | 212 +++ app/src/main/assets/fonts/trebuc.ttf | Bin 0 -> 136172 bytes app/src/main/assets/fonts/trebucbd.ttf | Bin 0 -> 126376 bytes .../android/nrftoolbox/AppHelpFragment.java | 73 + .../android/nrftoolbox/FeaturesActivity.java | 190 +++ .../nrftoolbox/SplashscreenActivity.java | 55 + .../nrftoolbox/adapter/AppAdapter.java | 122 ++ .../app/ExpandableListActivity.java | 297 ++++ .../android/nrftoolbox/bpm/BPMActivity.java | 169 ++ .../android/nrftoolbox/bpm/BPMManager.java | 316 ++++ .../nrftoolbox/bpm/BPMManagerCallbacks.java | 77 + .../android/nrftoolbox/csc/CSCActivity.java | 185 +++ .../android/nrftoolbox/csc/CSCManager.java | 321 ++++ .../nrftoolbox/csc/CSCManagerCallbacks.java | 32 + .../android/nrftoolbox/csc/CSCService.java | 252 +++ .../csc/settings/SettingsActivity.java | 50 + .../csc/settings/SettingsFragment.java | 75 + .../android/nrftoolbox/dfu/DfuActivity.java | 923 +++++++++++ .../nrftoolbox/dfu/DfuInitiatorActivity.java | 78 + .../android/nrftoolbox/dfu/DfuService.java | 48 + .../nrftoolbox/dfu/NotificationActivity.java | 49 + .../dfu/adapter/FileBrowserAppsAdapter.java | 73 + .../dfu/fragment/UploadCancelFragment.java | 91 ++ .../dfu/fragment/ZipInfoFragment.java | 39 + .../dfu/settings/AboutDfuPreference.java | 57 + .../dfu/settings/SettingsActivity.java | 50 + .../dfu/settings/SettingsFragment.java | 100 ++ .../gls/ExpandableRecordAdapter.java | 206 +++ .../nrftoolbox/gls/GlucoseActivity.java | 222 +++ .../nrftoolbox/gls/GlucoseManager.java | 698 +++++++++ .../gls/GlucoseManagerCallbacks.java | 49 + .../android/nrftoolbox/gls/GlucoseRecord.java | 118 ++ .../android/nrftoolbox/hrs/HRSActivity.java | 235 +++ .../android/nrftoolbox/hrs/HRSManager.java | 251 +++ .../nrftoolbox/hrs/HRSManagerCallbacks.java | 48 + .../android/nrftoolbox/hrs/LineGraphView.java | 121 ++ .../android/nrftoolbox/hts/HTSActivity.java | 132 ++ .../android/nrftoolbox/hts/HTSManager.java | 306 ++++ .../nrftoolbox/hts/HTSManagerCallbacks.java | 39 + .../android/nrftoolbox/hts/HTSService.java | 174 +++ .../nrftoolbox/profile/BleManager.java | 57 + .../profile/BleManagerCallbacks.java | 88 ++ .../profile/BleProfileActivity.java | 396 +++++ .../BleProfileExpandableListActivity.java | 391 +++++ .../nrftoolbox/profile/BleProfileService.java | 388 +++++ .../BleProfileServiceReadyActivity.java | 645 ++++++++ .../proximity/LinklossFragment.java | 57 + .../proximity/ProximityActivity.java | 236 +++ .../proximity/ProximityManager.java | 469 ++++++ .../proximity/ProximityManagerCallbacks.java | 28 + .../proximity/ProximityService.java | 184 +++ .../android/nrftoolbox/rsc/RSCActivity.java | 179 +++ .../android/nrftoolbox/rsc/RSCManager.java | 279 ++++ .../nrftoolbox/rsc/RSCManagerCallbacks.java | 32 + .../android/nrftoolbox/rsc/RSCService.java | 236 +++ .../nrftoolbox/scanner/DeviceListAdapter.java | 217 +++ .../scanner/ExtendedBluetoothDevice.java | 65 + .../nrftoolbox/scanner/ScannerFragment.java | 281 ++++ .../scanner/ScannerServiceParser.java | 169 ++ .../android/nrftoolbox/uart/UARTActivity.java | 240 +++ .../nrftoolbox/uart/UARTButtonAdapter.java | 117 ++ .../nrftoolbox/uart/UARTControlFragment.java | 137 ++ .../nrftoolbox/uart/UARTEditDialog.java | 169 ++ .../nrftoolbox/uart/UARTInterface.java | 29 + .../uart/UARTLocalLogContentProvider.java | 38 + .../nrftoolbox/uart/UARTLogAdapter.java | 88 ++ .../nrftoolbox/uart/UARTLogFragment.java | 299 ++++ .../android/nrftoolbox/uart/UARTManager.java | 187 +++ .../nrftoolbox/uart/UARTManagerCallbacks.java | 32 + .../android/nrftoolbox/uart/UARTService.java | 188 +++ .../nrftoolbox/utility/DebugLogger.java | 60 + .../widget/TrebuchetBoldTextView.java | 56 + .../nrftoolbox/widget/TrebuchetTextView.java | 56 + app/src/main/res/animator/click_animator.xml | 44 + app/src/main/res/color/text_color_primary.xml | 27 + app/src/main/res/drawable-hdpi/battery.png | Bin 0 -> 392 bytes .../res/drawable-hdpi/drawer_shadow.9.png | Bin 0 -> 161 bytes .../res/drawable-hdpi/ic_action_bluetooth.png | Bin 0 -> 545 bytes .../main/res/drawable-hdpi/ic_bpm_feature.png | Bin 0 -> 2697 bytes .../main/res/drawable-hdpi/ic_csc_feature.png | Bin 0 -> 5152 bytes .../main/res/drawable-hdpi/ic_dfu_feature.png | Bin 0 -> 3079 bytes app/src/main/res/drawable-hdpi/ic_drawer.png | Bin 0 -> 2755 bytes .../res/drawable-hdpi/ic_glucose_feature.png | Bin 0 -> 1373 bytes app/src/main/res/drawable-hdpi/ic_help.png | Bin 0 -> 1544 bytes .../main/res/drawable-hdpi/ic_hrs_feature.png | Bin 0 -> 2573 bytes .../main/res/drawable-hdpi/ic_hts_feature.png | Bin 0 -> 2299 bytes .../main/res/drawable-hdpi/ic_launcher.png | Bin 0 -> 3948 bytes .../main/res/drawable-hdpi/ic_menu_about.png | Bin 0 -> 759 bytes .../res/drawable-hdpi/ic_menu_settings.png | Bin 0 -> 1540 bytes .../res/drawable-hdpi/ic_permission_log.png | Bin 0 -> 1386 bytes .../drawable-hdpi/ic_proximity_feature.png | Bin 0 -> 2271 bytes .../main/res/drawable-hdpi/ic_rsc_feature.png | Bin 0 -> 2525 bytes .../main/res/drawable-hdpi/ic_rssi_0_bar.png | Bin 0 -> 1038 bytes .../main/res/drawable-hdpi/ic_rssi_1_bar.png | Bin 0 -> 1125 bytes .../main/res/drawable-hdpi/ic_rssi_2_bars.png | Bin 0 -> 1318 bytes .../main/res/drawable-hdpi/ic_rssi_3_bars.png | Bin 0 -> 1356 bytes .../res/drawable-hdpi/ic_stat_notify_csc.png | Bin 0 -> 872 bytes .../res/drawable-hdpi/ic_stat_notify_dfu.png | Bin 0 -> 993 bytes .../res/drawable-hdpi/ic_stat_notify_hts.png | Bin 0 -> 551 bytes .../ic_stat_notify_proximity.png | Bin 0 -> 782 bytes .../res/drawable-hdpi/ic_stat_notify_rsc.png | Bin 0 -> 502 bytes .../res/drawable-hdpi/ic_stat_notify_uart.png | Bin 0 -> 696 bytes .../item_background_light_n.9.png | Bin 0 -> 116 bytes .../item_background_light_p.9.png | Bin 0 -> 122 bytes .../list_divider_holo_light.9.png | Bin 0 -> 76 bytes .../main/res/drawable-hdpi/nordic_logo.png | Bin 0 -> 29716 bytes .../drawable-hdpi/proximity_lock_closed.png | Bin 0 -> 2675 bytes .../res/drawable-hdpi/proximity_lock_open.png | Bin 0 -> 2697 bytes app/src/main/res/drawable-hdpi/shadow_l.png | Bin 0 -> 110 bytes app/src/main/res/drawable-hdpi/shadow_r.png | Bin 0 -> 169 bytes .../drawable-land-xhdpi/background_image.jpg | Bin 0 -> 27426 bytes .../res/drawable-land-xhdpi/nordic_logo.png | Bin 0 -> 55949 bytes .../main/res/drawable-mdpi/ic_launcher.png | Bin 0 -> 4518 bytes .../drawable-sw600dp-xhdpi/nordic_logo.png | Bin 0 -> 51335 bytes app/src/main/res/drawable-v21/button.xml | 34 + .../main/res/drawable-v21/ic_feature_bg.xml | 36 + .../drawable-v21/uart_button_activated.xml | 32 + .../drawable-v21/uart_button_background.xml | 30 + .../res/drawable-v21/uart_button_normal.xml | 32 + app/src/main/res/drawable-xhdpi/app_drive.png | Bin 0 -> 2573 bytes .../res/drawable-xhdpi/app_file_manager.png | Bin 0 -> 3463 bytes .../res/drawable-xhdpi/app_google_play.png | Bin 0 -> 2247 bytes .../drawable-xhdpi/app_total_commander.png | Bin 0 -> 1596 bytes .../res/drawable-xhdpi/background_image.jpg | Bin 0 -> 22961 bytes .../btn_default_focused_holo_light.9.png | Bin 0 -> 476 bytes .../res/drawable-xhdpi/drawer_shadow.9.png | Bin 0 -> 174 bytes .../drawable-xhdpi/ic_action_bluetooth.png | Bin 0 -> 685 bytes .../res/drawable-xhdpi/ic_bpm_feature.png | Bin 0 -> 2076 bytes .../res/drawable-xhdpi/ic_csc_feature.png | Bin 0 -> 4224 bytes .../res/drawable-xhdpi/ic_dfu_feature.png | Bin 0 -> 4987 bytes app/src/main/res/drawable-xhdpi/ic_drawer.png | Bin 0 -> 2767 bytes .../res/drawable-xhdpi/ic_glucose_feature.png | Bin 0 -> 2091 bytes app/src/main/res/drawable-xhdpi/ic_help.png | Bin 0 -> 1796 bytes .../res/drawable-xhdpi/ic_hrs_feature.png | Bin 0 -> 3695 bytes .../res/drawable-xhdpi/ic_hts_feature.png | Bin 0 -> 1817 bytes .../main/res/drawable-xhdpi/ic_launcher.png | Bin 0 -> 5056 bytes .../res/drawable-xhdpi/ic_mcp_feature_fg.png | Bin 0 -> 1506 bytes .../main/res/drawable-xhdpi/ic_menu_about.png | Bin 0 -> 951 bytes .../res/drawable-xhdpi/ic_menu_settings.png | Bin 0 -> 1641 bytes .../res/drawable-xhdpi/ic_permission_log.png | Bin 0 -> 1446 bytes .../drawable-xhdpi/ic_proximity_feature.png | Bin 0 -> 3156 bytes .../res/drawable-xhdpi/ic_rsc_feature.png | Bin 0 -> 3436 bytes .../res/drawable-xhdpi/ic_stat_notify_csc.png | Bin 0 -> 1196 bytes .../res/drawable-xhdpi/ic_stat_notify_dfu.png | Bin 0 -> 1272 bytes .../res/drawable-xhdpi/ic_stat_notify_hts.png | Bin 0 -> 615 bytes .../ic_stat_notify_proximity.png | Bin 0 -> 928 bytes .../res/drawable-xhdpi/ic_stat_notify_rsc.png | Bin 0 -> 751 bytes .../drawable-xhdpi/ic_stat_notify_uart.png | Bin 0 -> 922 bytes app/src/main/res/drawable-xhdpi/ic_uart_1.png | Bin 0 -> 493 bytes .../res/drawable-xhdpi/ic_uart_1_small.png | Bin 0 -> 355 bytes app/src/main/res/drawable-xhdpi/ic_uart_2.png | Bin 0 -> 1278 bytes .../res/drawable-xhdpi/ic_uart_2_small.png | Bin 0 -> 903 bytes app/src/main/res/drawable-xhdpi/ic_uart_3.png | Bin 0 -> 1344 bytes .../res/drawable-xhdpi/ic_uart_3_small.png | Bin 0 -> 968 bytes app/src/main/res/drawable-xhdpi/ic_uart_4.png | Bin 0 -> 742 bytes .../res/drawable-xhdpi/ic_uart_4_small.png | Bin 0 -> 559 bytes app/src/main/res/drawable-xhdpi/ic_uart_5.png | Bin 0 -> 982 bytes .../res/drawable-xhdpi/ic_uart_5_small.png | Bin 0 -> 735 bytes app/src/main/res/drawable-xhdpi/ic_uart_6.png | Bin 0 -> 1516 bytes .../res/drawable-xhdpi/ic_uart_6_small.png | Bin 0 -> 1021 bytes app/src/main/res/drawable-xhdpi/ic_uart_7.png | Bin 0 -> 901 bytes .../res/drawable-xhdpi/ic_uart_7_small.png | Bin 0 -> 630 bytes app/src/main/res/drawable-xhdpi/ic_uart_8.png | Bin 0 -> 1646 bytes .../res/drawable-xhdpi/ic_uart_8_small.png | Bin 0 -> 1181 bytes app/src/main/res/drawable-xhdpi/ic_uart_9.png | Bin 0 -> 1473 bytes .../res/drawable-xhdpi/ic_uart_9_small.png | Bin 0 -> 1015 bytes .../main/res/drawable-xhdpi/ic_uart_about.png | Bin 0 -> 1215 bytes .../drawable-xhdpi/ic_uart_about_small.png | Bin 0 -> 860 bytes .../main/res/drawable-xhdpi/ic_uart_down.png | Bin 0 -> 726 bytes .../res/drawable-xhdpi/ic_uart_down_small.png | Bin 0 -> 582 bytes .../res/drawable-xhdpi/ic_uart_feature.png | Bin 0 -> 5357 bytes .../res/drawable-xhdpi/ic_uart_forward.png | Bin 0 -> 648 bytes .../drawable-xhdpi/ic_uart_forward_small.png | Bin 0 -> 613 bytes .../main/res/drawable-xhdpi/ic_uart_left.png | Bin 0 -> 886 bytes .../res/drawable-xhdpi/ic_uart_left_small.png | Bin 0 -> 744 bytes .../main/res/drawable-xhdpi/ic_uart_pause.png | Bin 0 -> 297 bytes .../drawable-xhdpi/ic_uart_pause_small.png | Bin 0 -> 244 bytes .../main/res/drawable-xhdpi/ic_uart_play.png | Bin 0 -> 669 bytes .../res/drawable-xhdpi/ic_uart_play_small.png | Bin 0 -> 531 bytes .../res/drawable-xhdpi/ic_uart_rewind.png | Bin 0 -> 694 bytes .../drawable-xhdpi/ic_uart_rewind_small.png | Bin 0 -> 601 bytes .../main/res/drawable-xhdpi/ic_uart_right.png | Bin 0 -> 861 bytes .../drawable-xhdpi/ic_uart_right_small.png | Bin 0 -> 727 bytes .../res/drawable-xhdpi/ic_uart_settings.png | Bin 0 -> 1661 bytes .../drawable-xhdpi/ic_uart_settings_small.png | Bin 0 -> 1231 bytes .../main/res/drawable-xhdpi/ic_uart_stop.png | Bin 0 -> 262 bytes .../res/drawable-xhdpi/ic_uart_stop_small.png | Bin 0 -> 224 bytes .../main/res/drawable-xhdpi/ic_uart_up.png | Bin 0 -> 681 bytes .../res/drawable-xhdpi/ic_uart_up_small.png | Bin 0 -> 631 bytes .../item_background_light_n.9.png | Bin 0 -> 116 bytes .../item_background_light_p.9.png | Bin 0 -> 122 bytes .../list_divider_holo_light.9.png | Bin 0 -> 83 bytes .../main/res/drawable-xhdpi/nordic_logo.png | Bin 0 -> 66984 bytes .../res/drawable-xhdpi/nordic_logo_horiz.png | Bin 0 -> 23546 bytes .../drawable-xhdpi/proximity_lock_closed.png | Bin 0 -> 2637 bytes .../drawable-xhdpi/proximity_lock_open.png | Bin 0 -> 2636 bytes app/src/main/res/drawable-xhdpi/shadow_l.png | Bin 0 -> 110 bytes app/src/main/res/drawable-xhdpi/shadow_r.png | Bin 0 -> 169 bytes app/src/main/res/drawable-xhdpi/zip.png | Bin 0 -> 86140 bytes .../res/drawable-xxhdpi/background_title.png | Bin 0 -> 13468 bytes .../main/res/drawable-xxhdpi/ic_launcher.png | Bin 0 -> 7311 bytes .../main/res/drawable/app_file_browser.xml | 28 + app/src/main/res/drawable/background.xml | 34 + app/src/main/res/drawable/button.xml | 28 + app/src/main/res/drawable/button_n.xml | 34 + app/src/main/res/drawable/button_p.xml | 34 + app/src/main/res/drawable/ic_feature_bg.xml | 28 + app/src/main/res/drawable/ic_feature_bg_n.xml | 27 + app/src/main/res/drawable/ic_feature_bg_p.xml | 27 + .../main/res/drawable/ic_feature_small_bg.xml | 28 + .../res/drawable/ic_feature_small_bg_n.xml | 29 + .../res/drawable/ic_feature_small_bg_p.xml | 29 + .../res/drawable/ic_mcp_feature_small.xml | 26 + app/src/main/res/drawable/ic_rssi_bar.xml | 28 + .../res/drawable/item_background_light.xml | 28 + app/src/main/res/drawable/start_edit_mode.xml | 28 + app/src/main/res/drawable/stop_edit_mode.xml | 28 + app/src/main/res/drawable/uart_button.xml | 44 + .../res/drawable/uart_button_background.xml | 32 + .../main/res/drawable/uart_button_small.xml | 44 + .../uart_dialog_button_background.xml | 30 + .../res/layout-land/activity_feature_bpm.xml | 286 ++++ .../res/layout-land/activity_feature_csc.xml | 281 ++++ .../res/layout-land/activity_feature_dfu.xml | 251 +++ .../res/layout-land/activity_feature_gls.xml | 207 +++ .../res/layout-land/activity_feature_hrs.xml | 141 ++ .../res/layout-land/activity_feature_hts.xml | 102 ++ .../activity_feature_proximity.xml | 115 ++ .../res/layout-land/activity_feature_rsc.xml | 311 ++++ .../res/layout-land/activity_feature_uart.xml | 57 + .../res/layout-land/feature_uart_button.xml | 29 + .../fragment_feature_uart_control.xml | 94 ++ .../activity_feature_bpm.xml | 288 ++++ .../activity_feature_csc.xml | 244 +++ .../activity_feature_dfu.xml | 245 +++ .../activity_feature_hrs.xml | 142 ++ .../feature_uart_button.xml | 28 + .../activity_feature_rsc.xml | 279 ++++ app/src/main/res/layout-v21/feature_icon.xml | 46 + .../layout-v21/fragment_device_selection.xml | 48 + .../main/res/layout/activity_feature_bpm.xml | 275 ++++ .../main/res/layout/activity_feature_csc.xml | 244 +++ .../main/res/layout/activity_feature_dfu.xml | 246 +++ .../main/res/layout/activity_feature_gls.xml | 207 +++ .../res/layout/activity_feature_gls_item.xml | 54 + .../layout/activity_feature_gls_subitem.xml | 46 + .../main/res/layout/activity_feature_hrs.xml | 136 ++ .../main/res/layout/activity_feature_hts.xml | 102 ++ .../res/layout/activity_feature_proximity.xml | 110 ++ .../main/res/layout/activity_feature_rsc.xml | 279 ++++ .../main/res/layout/activity_feature_uart.xml | 43 + app/src/main/res/layout/activity_features.xml | 66 + .../main/res/layout/activity_splashscreen.xml | 36 + app/src/main/res/layout/app_file_browser.xml | 43 + .../main/res/layout/app_file_browser_item.xml | 35 + app/src/main/res/layout/device_list_empty.xml | 27 + app/src/main/res/layout/device_list_row.xml | 55 + app/src/main/res/layout/device_list_title.xml | 26 + app/src/main/res/layout/dialog_about_text.xml | 26 + app/src/main/res/layout/drawer.xml | 72 + app/src/main/res/layout/drawer_plugin.xml | 45 + .../res/layout/expandable_list_content.xml | 24 + app/src/main/res/layout/feature_icon.xml | 44 + .../main/res/layout/feature_uart_button.xml | 28 + .../res/layout/feature_uart_dialog_edit.xml | 60 + .../layout/feature_uart_dialog_edit_icon.xml | 28 + .../res/layout/fragment_device_selection.xml | 49 + .../layout/fragment_feature_uart_control.xml | 102 ++ .../res/layout/fragment_feature_uart_log.xml | 69 + app/src/main/res/layout/fragment_zip_info.xml | 38 + app/src/main/res/layout/log_item.xml | 40 + app/src/main/res/menu-port/uart_menu.xml | 34 + .../main/res/menu-port/uart_menu_config.xml | 34 + app/src/main/res/menu/csc_menu.xml | 37 + app/src/main/res/menu/dfu_menu.xml | 37 + app/src/main/res/menu/gls_more.xml | 40 + app/src/main/res/menu/help.xml | 32 + app/src/main/res/menu/uart_menu.xml | 30 + app/src/main/res/menu/uart_menu_config.xml | 30 + .../res/raw/ble_app_hrs_dfu_s110_v7_1_0.hex | 1080 +++++++++++++ .../ble_app_hrs_dfu_s110_v7_1_0_ext_init.dat | Bin 0 -> 16 bytes .../main/res/raw/ble_app_hrs_s110_v6_0_0.hex | 1231 +++++++++++++++ .../main/res/raw/ble_app_hrs_s110_v7_0_0.hex | 1376 +++++++++++++++++ .../main/res/raw/ble_app_rscs_s110_v6_0_0.hex | 1198 ++++++++++++++ .../main/res/raw/ble_app_rscs_s110_v7_0_0.hex | 1344 ++++++++++++++++ .../main/res/raw/blinky_arm_s110_v7_0_0.hex | 61 + app/src/main/res/raw/blinky_s110_v7_1_0.hex | 46 + .../res/raw/blinky_s110_v7_1_0_ext_init.dat | Bin 0 -> 16 bytes app/src/main/res/raw/dfu_mac_3_0.sh | 203 +++ app/src/main/res/raw/dfu_win_3_0.bat | 249 +++ app/src/main/res/raw/readme.txt | 58 + app/src/main/res/values-land-v21/dimens.xml | 29 + app/src/main/res/values-land/dimens.xml | 33 + app/src/main/res/values-land/strings_bpm.xml | 26 + app/src/main/res/values-land/strings_csc.xml | 26 + app/src/main/res/values-land/strings_dfu.xml | 26 + app/src/main/res/values-land/strings_gls.xml | 26 + app/src/main/res/values-land/strings_hrs.xml | 26 + app/src/main/res/values-land/strings_hts.xml | 26 + .../res/values-land/strings_proximity.xml | 26 + app/src/main/res/values-land/strings_rsc.xml | 26 + .../res/values-sw600dp-land-v21/dimens.xml | 31 + app/src/main/res/values-sw600dp/dimens.xml | 41 + .../main/res/values-sw600dp/strings_bpm.xml | 26 + .../main/res/values-sw600dp/strings_csc.xml | 26 + .../main/res/values-sw600dp/strings_dfu.xml | 26 + .../main/res/values-sw600dp/strings_gls.xml | 26 + .../main/res/values-sw600dp/strings_hrs.xml | 26 + .../main/res/values-sw600dp/strings_hts.xml | 28 + .../main/res/values-sw600dp/strings_rsc.xml | 26 + .../main/res/values-sw720dp-land/dimens.xml | 37 + app/src/main/res/values-v21/dimens.xml | 33 + app/src/main/res/values-v21/styles.xml | 60 + app/src/main/res/values/color.xml | 37 + app/src/main/res/values/dimens.xml | 47 + app/src/main/res/values/strings.xml | 73 + app/src/main/res/values/strings_bpm.xml | 48 + app/src/main/res/values/strings_csc.xml | 158 ++ app/src/main/res/values/strings_dfu.xml | 119 ++ app/src/main/res/values/strings_gls.xml | 163 ++ app/src/main/res/values/strings_hrs.xml | 46 + app/src/main/res/values/strings_hts.xml | 37 + app/src/main/res/values/strings_proximity.xml | 42 + app/src/main/res/values/strings_rsc.xml | 53 + app/src/main/res/values/strings_uart.xml | 52 + app/src/main/res/values/styles.xml | 117 ++ app/src/main/res/xml/settings_csc.xml | 35 + app/src/main/res/xml/settings_dfu.xml | 50 + build.gradle | 19 + gradle.properties | 18 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 49896 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 164 ++ gradlew.bat | 90 ++ nRFToolbox.iml | 21 + settings.gradle | 1 + 356 files changed, 28833 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/.name create mode 100644 .idea/compiler.xml create mode 100644 .idea/copyright/BSD.xml create mode 100644 .idea/copyright/profiles_settings.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/scopes/scope_settings.xml create mode 100644 .idea/vcs.xml create mode 100644 README.md create mode 100644 app/.gitignore create mode 100644 app/app.iml create mode 100644 app/build.gradle create mode 100644 app/libs/achartengine-1.1.0.jar create mode 100644 app/libs/nrf-logger-v2.0.jar create mode 100644 app/proguard-rules.pro create mode 100644 app/sources/nrf-logger-v2.0-source.jar create mode 100644 app/src/androidTest/java/no/nordicsemi/android/nrftoolbox/ApplicationTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/assets/fonts/trebuc.ttf create mode 100644 app/src/main/assets/fonts/trebucbd.ttf create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/AppHelpFragment.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/FeaturesActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/SplashscreenActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/adapter/AppAdapter.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/app/ExpandableListActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsFragment.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuInitiatorActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuService.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/NotificationActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/adapter/FileBrowserAppsAdapter.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/UploadCancelFragment.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/ZipInfoFragment.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/AboutDfuPreference.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsFragment.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/ExpandableRecordAdapter.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseRecord.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/LineGraphView.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManagerCallbacks.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/LinklossFragment.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ExtendedBluetoothDevice.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerServiceParser.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTButtonAdapter.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTControlFragment.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTInterface.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLocalLogContentProvider.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogAdapter.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/DebugLogger.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetBoldTextView.java create mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetTextView.java create mode 100644 app/src/main/res/animator/click_animator.xml create mode 100644 app/src/main/res/color/text_color_primary.xml create mode 100644 app/src/main/res/drawable-hdpi/battery.png create mode 100644 app/src/main/res/drawable-hdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-hdpi/ic_action_bluetooth.png create mode 100644 app/src/main/res/drawable-hdpi/ic_bpm_feature.png create mode 100644 app/src/main/res/drawable-hdpi/ic_csc_feature.png create mode 100644 app/src/main/res/drawable-hdpi/ic_dfu_feature.png create mode 100644 app/src/main/res/drawable-hdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable-hdpi/ic_glucose_feature.png create mode 100644 app/src/main/res/drawable-hdpi/ic_help.png create mode 100644 app/src/main/res/drawable-hdpi/ic_hrs_feature.png create mode 100644 app/src/main/res/drawable-hdpi/ic_hts_feature.png create mode 100644 app/src/main/res/drawable-hdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-hdpi/ic_menu_about.png create mode 100644 app/src/main/res/drawable-hdpi/ic_menu_settings.png create mode 100644 app/src/main/res/drawable-hdpi/ic_permission_log.png create mode 100644 app/src/main/res/drawable-hdpi/ic_proximity_feature.png create mode 100644 app/src/main/res/drawable-hdpi/ic_rsc_feature.png create mode 100644 app/src/main/res/drawable-hdpi/ic_rssi_0_bar.png create mode 100644 app/src/main/res/drawable-hdpi/ic_rssi_1_bar.png create mode 100644 app/src/main/res/drawable-hdpi/ic_rssi_2_bars.png create mode 100644 app/src/main/res/drawable-hdpi/ic_rssi_3_bars.png create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_csc.png create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_dfu.png create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_hts.png create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_proximity.png create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_rsc.png create mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_uart.png create mode 100644 app/src/main/res/drawable-hdpi/item_background_light_n.9.png create mode 100644 app/src/main/res/drawable-hdpi/item_background_light_p.9.png create mode 100644 app/src/main/res/drawable-hdpi/list_divider_holo_light.9.png create mode 100644 app/src/main/res/drawable-hdpi/nordic_logo.png create mode 100644 app/src/main/res/drawable-hdpi/proximity_lock_closed.png create mode 100644 app/src/main/res/drawable-hdpi/proximity_lock_open.png create mode 100644 app/src/main/res/drawable-hdpi/shadow_l.png create mode 100644 app/src/main/res/drawable-hdpi/shadow_r.png create mode 100644 app/src/main/res/drawable-land-xhdpi/background_image.jpg create mode 100644 app/src/main/res/drawable-land-xhdpi/nordic_logo.png create mode 100644 app/src/main/res/drawable-mdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-sw600dp-xhdpi/nordic_logo.png create mode 100644 app/src/main/res/drawable-v21/button.xml create mode 100644 app/src/main/res/drawable-v21/ic_feature_bg.xml create mode 100644 app/src/main/res/drawable-v21/uart_button_activated.xml create mode 100644 app/src/main/res/drawable-v21/uart_button_background.xml create mode 100644 app/src/main/res/drawable-v21/uart_button_normal.xml create mode 100644 app/src/main/res/drawable-xhdpi/app_drive.png create mode 100644 app/src/main/res/drawable-xhdpi/app_file_manager.png create mode 100644 app/src/main/res/drawable-xhdpi/app_google_play.png create mode 100644 app/src/main/res/drawable-xhdpi/app_total_commander.png create mode 100644 app/src/main/res/drawable-xhdpi/background_image.jpg create mode 100644 app/src/main/res/drawable-xhdpi/btn_default_focused_holo_light.9.png create mode 100644 app/src/main/res/drawable-xhdpi/drawer_shadow.9.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_bluetooth.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_bpm_feature.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_csc_feature.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_dfu_feature.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_drawer.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_glucose_feature.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_help.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_hrs_feature.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_hts_feature.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_mcp_feature_fg.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_menu_about.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_menu_settings.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_permission_log.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_proximity_feature.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_rsc_feature.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_csc.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_dfu.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_hts.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_proximity.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_rsc.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_uart.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_1.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_1_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_2.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_2_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_3.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_3_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_4.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_4_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_5.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_5_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_6.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_6_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_7.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_7_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_8.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_8_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_9.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_9_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_about.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_about_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_down.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_down_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_feature.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_forward.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_forward_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_left.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_left_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_pause.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_pause_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_play.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_play_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_rewind.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_rewind_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_right.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_right_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_settings.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_settings_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_stop.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_stop_small.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_up.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_up_small.png create mode 100644 app/src/main/res/drawable-xhdpi/item_background_light_n.9.png create mode 100644 app/src/main/res/drawable-xhdpi/item_background_light_p.9.png create mode 100644 app/src/main/res/drawable-xhdpi/list_divider_holo_light.9.png create mode 100644 app/src/main/res/drawable-xhdpi/nordic_logo.png create mode 100644 app/src/main/res/drawable-xhdpi/nordic_logo_horiz.png create mode 100644 app/src/main/res/drawable-xhdpi/proximity_lock_closed.png create mode 100644 app/src/main/res/drawable-xhdpi/proximity_lock_open.png create mode 100644 app/src/main/res/drawable-xhdpi/shadow_l.png create mode 100644 app/src/main/res/drawable-xhdpi/shadow_r.png create mode 100644 app/src/main/res/drawable-xhdpi/zip.png create mode 100644 app/src/main/res/drawable-xxhdpi/background_title.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/drawable/app_file_browser.xml create mode 100644 app/src/main/res/drawable/background.xml create mode 100644 app/src/main/res/drawable/button.xml create mode 100644 app/src/main/res/drawable/button_n.xml create mode 100644 app/src/main/res/drawable/button_p.xml create mode 100644 app/src/main/res/drawable/ic_feature_bg.xml create mode 100644 app/src/main/res/drawable/ic_feature_bg_n.xml create mode 100644 app/src/main/res/drawable/ic_feature_bg_p.xml create mode 100644 app/src/main/res/drawable/ic_feature_small_bg.xml create mode 100644 app/src/main/res/drawable/ic_feature_small_bg_n.xml create mode 100644 app/src/main/res/drawable/ic_feature_small_bg_p.xml create mode 100644 app/src/main/res/drawable/ic_mcp_feature_small.xml create mode 100644 app/src/main/res/drawable/ic_rssi_bar.xml create mode 100644 app/src/main/res/drawable/item_background_light.xml create mode 100644 app/src/main/res/drawable/start_edit_mode.xml create mode 100644 app/src/main/res/drawable/stop_edit_mode.xml create mode 100644 app/src/main/res/drawable/uart_button.xml create mode 100644 app/src/main/res/drawable/uart_button_background.xml create mode 100644 app/src/main/res/drawable/uart_button_small.xml create mode 100644 app/src/main/res/drawable/uart_dialog_button_background.xml create mode 100644 app/src/main/res/layout-land/activity_feature_bpm.xml create mode 100644 app/src/main/res/layout-land/activity_feature_csc.xml create mode 100644 app/src/main/res/layout-land/activity_feature_dfu.xml create mode 100644 app/src/main/res/layout-land/activity_feature_gls.xml create mode 100644 app/src/main/res/layout-land/activity_feature_hrs.xml create mode 100644 app/src/main/res/layout-land/activity_feature_hts.xml create mode 100644 app/src/main/res/layout-land/activity_feature_proximity.xml create mode 100644 app/src/main/res/layout-land/activity_feature_rsc.xml create mode 100644 app/src/main/res/layout-land/activity_feature_uart.xml create mode 100644 app/src/main/res/layout-land/feature_uart_button.xml create mode 100644 app/src/main/res/layout-land/fragment_feature_uart_control.xml create mode 100644 app/src/main/res/layout-sw600dp-land/activity_feature_bpm.xml create mode 100644 app/src/main/res/layout-sw600dp-land/activity_feature_csc.xml create mode 100644 app/src/main/res/layout-sw600dp-land/activity_feature_dfu.xml create mode 100644 app/src/main/res/layout-sw600dp-land/activity_feature_hrs.xml create mode 100644 app/src/main/res/layout-sw600dp-land/feature_uart_button.xml create mode 100644 app/src/main/res/layout-sw720dp-land/activity_feature_rsc.xml create mode 100644 app/src/main/res/layout-v21/feature_icon.xml create mode 100644 app/src/main/res/layout-v21/fragment_device_selection.xml create mode 100644 app/src/main/res/layout/activity_feature_bpm.xml create mode 100644 app/src/main/res/layout/activity_feature_csc.xml create mode 100644 app/src/main/res/layout/activity_feature_dfu.xml create mode 100644 app/src/main/res/layout/activity_feature_gls.xml create mode 100644 app/src/main/res/layout/activity_feature_gls_item.xml create mode 100644 app/src/main/res/layout/activity_feature_gls_subitem.xml create mode 100644 app/src/main/res/layout/activity_feature_hrs.xml create mode 100644 app/src/main/res/layout/activity_feature_hts.xml create mode 100644 app/src/main/res/layout/activity_feature_proximity.xml create mode 100644 app/src/main/res/layout/activity_feature_rsc.xml create mode 100644 app/src/main/res/layout/activity_feature_uart.xml create mode 100644 app/src/main/res/layout/activity_features.xml create mode 100644 app/src/main/res/layout/activity_splashscreen.xml create mode 100644 app/src/main/res/layout/app_file_browser.xml create mode 100644 app/src/main/res/layout/app_file_browser_item.xml create mode 100644 app/src/main/res/layout/device_list_empty.xml create mode 100644 app/src/main/res/layout/device_list_row.xml create mode 100644 app/src/main/res/layout/device_list_title.xml create mode 100644 app/src/main/res/layout/dialog_about_text.xml create mode 100644 app/src/main/res/layout/drawer.xml create mode 100644 app/src/main/res/layout/drawer_plugin.xml create mode 100644 app/src/main/res/layout/expandable_list_content.xml create mode 100644 app/src/main/res/layout/feature_icon.xml create mode 100644 app/src/main/res/layout/feature_uart_button.xml create mode 100644 app/src/main/res/layout/feature_uart_dialog_edit.xml create mode 100644 app/src/main/res/layout/feature_uart_dialog_edit_icon.xml create mode 100644 app/src/main/res/layout/fragment_device_selection.xml create mode 100644 app/src/main/res/layout/fragment_feature_uart_control.xml create mode 100644 app/src/main/res/layout/fragment_feature_uart_log.xml create mode 100644 app/src/main/res/layout/fragment_zip_info.xml create mode 100644 app/src/main/res/layout/log_item.xml create mode 100644 app/src/main/res/menu-port/uart_menu.xml create mode 100644 app/src/main/res/menu-port/uart_menu_config.xml create mode 100644 app/src/main/res/menu/csc_menu.xml create mode 100644 app/src/main/res/menu/dfu_menu.xml create mode 100644 app/src/main/res/menu/gls_more.xml create mode 100644 app/src/main/res/menu/help.xml create mode 100644 app/src/main/res/menu/uart_menu.xml create mode 100644 app/src/main/res/menu/uart_menu_config.xml create mode 100644 app/src/main/res/raw/ble_app_hrs_dfu_s110_v7_1_0.hex create mode 100644 app/src/main/res/raw/ble_app_hrs_dfu_s110_v7_1_0_ext_init.dat create mode 100644 app/src/main/res/raw/ble_app_hrs_s110_v6_0_0.hex create mode 100644 app/src/main/res/raw/ble_app_hrs_s110_v7_0_0.hex create mode 100644 app/src/main/res/raw/ble_app_rscs_s110_v6_0_0.hex create mode 100644 app/src/main/res/raw/ble_app_rscs_s110_v7_0_0.hex create mode 100644 app/src/main/res/raw/blinky_arm_s110_v7_0_0.hex create mode 100644 app/src/main/res/raw/blinky_s110_v7_1_0.hex create mode 100644 app/src/main/res/raw/blinky_s110_v7_1_0_ext_init.dat create mode 100644 app/src/main/res/raw/dfu_mac_3_0.sh create mode 100644 app/src/main/res/raw/dfu_win_3_0.bat create mode 100644 app/src/main/res/raw/readme.txt create mode 100644 app/src/main/res/values-land-v21/dimens.xml create mode 100644 app/src/main/res/values-land/dimens.xml create mode 100644 app/src/main/res/values-land/strings_bpm.xml create mode 100644 app/src/main/res/values-land/strings_csc.xml create mode 100644 app/src/main/res/values-land/strings_dfu.xml create mode 100644 app/src/main/res/values-land/strings_gls.xml create mode 100644 app/src/main/res/values-land/strings_hrs.xml create mode 100644 app/src/main/res/values-land/strings_hts.xml create mode 100644 app/src/main/res/values-land/strings_proximity.xml create mode 100644 app/src/main/res/values-land/strings_rsc.xml create mode 100644 app/src/main/res/values-sw600dp-land-v21/dimens.xml create mode 100644 app/src/main/res/values-sw600dp/dimens.xml create mode 100644 app/src/main/res/values-sw600dp/strings_bpm.xml create mode 100644 app/src/main/res/values-sw600dp/strings_csc.xml create mode 100644 app/src/main/res/values-sw600dp/strings_dfu.xml create mode 100644 app/src/main/res/values-sw600dp/strings_gls.xml create mode 100644 app/src/main/res/values-sw600dp/strings_hrs.xml create mode 100644 app/src/main/res/values-sw600dp/strings_hts.xml create mode 100644 app/src/main/res/values-sw600dp/strings_rsc.xml create mode 100644 app/src/main/res/values-sw720dp-land/dimens.xml create mode 100644 app/src/main/res/values-v21/dimens.xml create mode 100644 app/src/main/res/values-v21/styles.xml create mode 100644 app/src/main/res/values/color.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/strings_bpm.xml create mode 100644 app/src/main/res/values/strings_csc.xml create mode 100644 app/src/main/res/values/strings_dfu.xml create mode 100644 app/src/main/res/values/strings_gls.xml create mode 100644 app/src/main/res/values/strings_hrs.xml create mode 100644 app/src/main/res/values/strings_hts.xml create mode 100644 app/src/main/res/values/strings_proximity.xml create mode 100644 app/src/main/res/values/strings_rsc.xml create mode 100644 app/src/main/res/values/strings_uart.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/main/res/xml/settings_csc.xml create mode 100644 app/src/main/res/xml/settings_dfu.xml create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 nRFToolbox.iml create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..db1555f0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.gradle +/local.properties +/.idea/workspace.xml +/.idea/dictionaries/*.xml +/.idea/libraries +.DS_Store +/build +/key* \ No newline at end of file diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 00000000..41bcebb2 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +nRFToolbox \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 00000000..217af471 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,23 @@ + + + + + + diff --git a/.idea/copyright/BSD.xml b/.idea/copyright/BSD.xml new file mode 100644 index 00000000..178eefff --- /dev/null +++ b/.idea/copyright/BSD.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/.idea/copyright/profiles_settings.xml b/.idea/copyright/profiles_settings.xml new file mode 100644 index 00000000..564653ff --- /dev/null +++ b/.idea/copyright/profiles_settings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 00000000..e206d70d --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 00000000..cff9e6e6 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,22 @@ + + + + + + + diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..59436c98 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..27665145 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/.idea/scopes/scope_settings.xml b/.idea/scopes/scope_settings.xml new file mode 100644 index 00000000..922003b8 --- /dev/null +++ b/.idea/scopes/scope_settings.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..0f416569 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 00000000..61ae4fa0 --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +# nRF Toolbox + +The nRF Toolbox is a container app that stores your Nordic Semiconductor apps for Bluetooth Smart in one location. + +It contains applications demonstrating Bluetooth Smart profiles: +* **Cycling Speed and Cadence**, +* **Running Speed and Cadence**, +* **Heart Rate Monitor**, +* **Blood Pressure Monitor**, +* **Health Thermometer Monitor**, +* **Glucose Monitor**, +* **Proximity Monitor**. + +Since version 1.10.0 the *nRF Toolbox* supports also the **Nordic UART Service** which may be used for bidirectional text communication between devices. The UI allows one to create configurable remote control with UART interface. + +### Device Firmware Update + +The **Device Firmware Update (DFU)** profile allows one to update the application, bootloader and/or the Soft Device image over-the-air (OTA). It is compatible with Nordic Semiconductor nRF51822 devices that have the S110 SoftDevice and bootloader enabled. Since the 1.11.0 version nRF Toolbox allows to send the required init packet. More information about the init packet may be found here: [init packet handling](https://github.com/NordicSemiconductor/nRF-Master-Control-Panel/tree/master/init%20packet%20handling). + +The DFU has the following features: +- Scans for devices that are in DFU mode. +- Connects to devices in DFU mode and uploads the selected firmware (soft device, bootloader and/or application). +- Allows HEX or BIN file upload through your phone or tablet. +- Allows to update a soft device and bootloader from ZIP in one connection. +- Pause, resume, and cancel file uploads. +- Works in portrait and landscape orientation. +- Includes pre-installed examples that consist of the Bluetooth Smart heart rate service and running speed and cadence service. + +### Dependencies + +In order to compile the project the **DFU Library is required**. This project may be found here: https://github.com/NordicSemiconductor/Android-DFU-Library. +Please clone the nRF Toolbox and the DFU Library to the same root folder. The dependency is already configured in the gradle and set to *..:DFULibrary:dfu* module. + +The nRF Toolbox uses also the nRF Logger API library, that may be foud here: https://github.com/NordicSemiconductor/nRF-Logger-API. The library (jar file) and is located in the *libs* folder and a jar with its source code in the *source* folder in the *app* module. This library allows the app to create log entries in the [nRF Logger](https://play.google.com/store/apps/details?id=no.nordicsemi.android.log) application. Please, read the library documentation on GitHub for more information anout usage and permission. + +The graph in HRM profile is created using the [AChartEngine v1.1.0](http://www.achartengine.org) contributed based on the [Apache 2.0 license](http://www.apache.org/licenses/LICENSE-2.0). + +### Note +- Android 4.3 or newer is required. +- Tested on Nexus 4, Nexus 7, Samsung S3 and S4 with Android 4.3 and on Nexus 4, Nexus 5, Nexus 7, Nexus 9 with Android 4.4.4 and 5. +- Compatible with nRF51822 devices that have S110 v5.2.1+ and the bootloader from nRF51 SDK v4.4.1+ +- nRF51822 Development kits can be ordered from http://www.nordicsemi.com/eng/Buy-Online. +- The nRF51 SDK and S110 SoftDevice are available online at http://www.nordicsemi.com for developers who have purchased an nRF51822 product. + +### Known problems +- Nexus 4 and Nexus 7 with Android 4.3 does not allow to unbound devices. +- Reconnection to bondable devices may not work on several tested phones. +- Nexus 4, 5 and 7 with Android 4.4 fails when reconnecting when Gatt Server is running. +- Reset of Bluetooth adapter may be required if other error appear. + +### Know problems with DFU settings: +- Setting Package Receipt Notification to OFF or less than ~400 will not work on some phones, f.e. Nexus 4, Nexus 7. On Nexus 5 with Android 4.4.4 it increases upload speed to 18kb/4.3 sec. \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/app.iml b/app/app.iml new file mode 100644 index 00000000..9ec727f7 --- /dev/null +++ b/app/app.iml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 00000000..2e44289b --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.application' + +android { + signingConfigs { + } + compileSdkVersion 21 + buildToolsVersion "21.1.2" + defaultConfig { + applicationId "no.nordicsemi.android.nrftoolbox" + minSdkVersion 18 + targetSdkVersion 21 + versionCode 27 + versionName "1.11.4" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:21.0.3' + compile project(':..:DFULibrary:dfu') + compile files('libs/achartengine-1.1.0.jar') + compile files('libs/nrf-logger-v2.0.jar') +} diff --git a/app/libs/achartengine-1.1.0.jar b/app/libs/achartengine-1.1.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..93203186752536ba06ef8fc087cc43ba7ab2dca4 GIT binary patch literal 120675 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∓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 literal 0 HcmV?d00001 diff --git a/app/libs/nrf-logger-v2.0.jar b/app/libs/nrf-logger-v2.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..8d37a964baae3847c39b4bc0ef56de97b5ee9ae0 GIT binary patch literal 29046 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 ve^l>2Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..e7146ead --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/fonts/trebuc.ttf b/app/src/main/assets/fonts/trebuc.ttf new file mode 100644 index 0000000000000000000000000000000000000000..84891986b0c8eb556779e4f9f839b05cf67b9348 GIT binary patch literal 136172 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 z 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 appList = pm.queryIntentActivities(utilsIntent, 0); + for (final ResolveInfo info : appList) { + final View item = inflater.inflate(R.layout.drawer_plugin, container, false); + final ImageView icon = (ImageView) item.findViewById(android.R.id.icon); + final TextView label = (TextView) item.findViewById(android.R.id.text1); + + label.setText(info.loadLabel(pm)); + icon.setImageDrawable(info.loadIcon(pm)); + item.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(final View v) { + final Intent intent = new Intent(); + intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name)); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + startActivity(intent); + mDrawerLayout.closeDrawers(); + } + }); + container.addView(item); + } + } + + private boolean ensureBLEExists() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show(); + return false; + } + return true; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/SplashscreenActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/SplashscreenActivity.java new file mode 100644 index 00000000..6e35d024 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/SplashscreenActivity.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; + +public class SplashscreenActivity extends Activity { + /** Splash screen duration time in milliseconds */ + private static final int DELAY = 1000; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splashscreen); + + // Jump to SensorsActivity after DELAY milliseconds + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + final Intent intent = new Intent(SplashscreenActivity.this, FeaturesActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + startActivity(intent); + finish(); + } + }, DELAY); + } + + @Override + public void onBackPressed() { + // do nothing. Protect from exiting the application when splash screen is shown + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/adapter/AppAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/adapter/AppAdapter.java new file mode 100644 index 00000000..e01978e9 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/adapter/AppAdapter.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.adapter; + +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import no.nordicsemi.android.nrftoolbox.R; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +public class AppAdapter extends BaseAdapter { + private static final String CATEGORY = "no.nordicsemi.android.nrftoolbox.LAUNCHER"; + private static final String MCP_PACKAGE = "no.nordicsemi.android.mcp"; + + private final Context mContext; + private final PackageManager mPackageManager; + private final LayoutInflater mInflater; + private final List mApplications; + + public AppAdapter(final Context context) { + mContext = context; + mInflater = LayoutInflater.from(context); + + // get nRF installed app plugins from package manager + final PackageManager pm = mPackageManager = context.getPackageManager(); + final Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(CATEGORY); + + final List appList = mApplications = pm.queryIntentActivities(intent, 0); + // TODO remove the following loop after some time, when there will be no more MCP 1.1 at the market. + for (final ResolveInfo info : appList) { + if (MCP_PACKAGE.equals(info.activityInfo.packageName)) { + appList.remove(info); + break; + } + } + Collections.sort(appList, new ResolveInfo.DisplayNameComparator(pm)); + } + + @Override + public int getCount() { + return mApplications.size(); + } + + @Override + public Object getItem(int position) { + return mApplications.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = convertView; + if (view == null) { + view = mInflater.inflate(R.layout.feature_icon, parent, false); + + final ViewHolder holder = new ViewHolder(); + holder.view = view; + holder.icon = (ImageView) view.findViewById(R.id.icon); + holder.label = (TextView) view.findViewById(R.id.label); + view.setTag(holder); + } + + final ResolveInfo info = mApplications.get(position); + final PackageManager pm = mPackageManager; + + final ViewHolder holder = (ViewHolder) view.getTag(); + holder.icon.setImageDrawable(info.loadIcon(pm)); + holder.label.setText(info.loadLabel(pm).toString().toUpperCase(Locale.US)); + holder.view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final Intent intent = new Intent(); + intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name)); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + mContext.startActivity(intent); + } + }); + + return view; + } + + private class ViewHolder { + private View view; + private ImageView icon; + private TextView label; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/app/ExpandableListActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/app/ExpandableListActivity.java new file mode 100644 index 00000000..7d8638f9 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/app/ExpandableListActivity.java @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package no.nordicsemi.android.nrftoolbox.app; + +import java.util.List; +import java.util.Map; + +import no.nordicsemi.android.nrftoolbox.R; +import android.app.Activity; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.View; +import android.view.View.OnCreateContextMenuListener; +import android.widget.ExpandableListAdapter; +import android.widget.ExpandableListView; +import android.widget.SimpleCursorTreeAdapter; +import android.widget.SimpleExpandableListAdapter; + +/** + * An activity that displays an expandable list of items by binding to a data source implementing the ExpandableListAdapter, and exposes event handlers when the + * user selects an item. + *

+ * ExpandableListActivity hosts a {@link android.widget.ExpandableListView ExpandableListView} object that can be bound to different data sources that provide a + * two-levels of data (the top-level is group, and below each group are children). Binding, screen layout, and row layout are discussed in the following + * sections. + *

+ * Screen Layout + *

+ *

+ * ExpandableListActivity has a default layout that consists of a single, full-screen, centered expandable list. However, if you desire, you can customize the + * screen layout by setting your own view layout with setContentView() in onCreate(). To do this, your own view MUST contain an ExpandableListView object with + * the id "@android:id/list" (or {@link android.R.id#list} if it's in code) + *

+ * Optionally, your custom view can contain another view object of any type to display when the list view is empty. This "empty list" notifier must have an id + * "android:empty". Note that when an empty view is present, the expandable list view will be hidden when there is no data to display. + *

+ * The following code demonstrates an (ugly) custom screen layout. It has a list with a green background, and an alternate red "no data" message. + *

+ * + *
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ *         android:orientation="vertical"
+ *         android:layout_width="match_parent" 
+ *         android:layout_height="match_parent"
+ *         android:paddingLeft="8dp"
+ *         android:paddingRight="8dp">
+ * 
+ *     <ExpandableListView android:id="@id/android:list"
+ *               android:layout_width="match_parent" 
+ *               android:layout_height="match_parent"
+ *               android:background="#00FF00"
+ *               android:layout_weight="1"
+ *               android:drawSelectorOnTop="false"/>
+ * 
+ *     <TextView android:id="@id/android:empty"
+ *               android:layout_width="match_parent" 
+ *               android:layout_height="match_parent"
+ *               android:background="#FF0000"
+ *               android:text="No data"/>
+ * </LinearLayout>
+ * 
+ * + *

+ * Row Layout + *

+ * The {@link ExpandableListAdapter} set in the {@link ExpandableListActivity} via {@link #setListAdapter(ExpandableListAdapter)} provides the {@link View}s for + * each row. This adapter has separate methods for providing the group {@link View}s and child {@link View}s. There are a couple provided + * {@link ExpandableListAdapter}s that simplify use of adapters: {@link SimpleCursorTreeAdapter} and {@link SimpleExpandableListAdapter}. + *

+ * With these, you can specify the layout of individual rows for groups and children in the list. These constructor takes a few parameters that specify layout + * resources for groups and children. It also has additional parameters that let you specify which data field to associate with which object in the row layout + * resource. The {@link SimpleCursorTreeAdapter} fetches data from {@link Cursor}s and the {@link SimpleExpandableListAdapter} fetches data from {@link List}s + * of {@link Map}s. + *

+ *

+ * Android provides some standard row layout resources. These are in the {@link android.R.layout} class, and have names such as simple_list_item_1, + * simple_list_item_2, and two_line_list_item. The following layout XML is the source for the resource two_line_list_item, which displays two data fields,one + * above the other, for each list row. + *

+ * + *
+ * <?xml version="1.0" encoding="utf-8"?>
+ * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ *     android:layout_width="match_parent"
+ *     android:layout_height="wrap_content"
+ *     android:orientation="vertical">
+ * 
+ *     <TextView android:id="@+id/text1"
+ *         android:textSize="16sp"
+ *         android:textStyle="bold"
+ *         android:layout_width="match_parent"
+ *         android:layout_height="wrap_content"/>
+ * 
+ *     <TextView android:id="@+id/text2"
+ *         android:textSize="16sp"
+ *         android:layout_width="match_parent"
+ *         android:layout_height="wrap_content"/>
+ * </LinearLayout>
+ * 
+ * + *

+ * You must identify the data bound to each TextView object in this layout. The syntax for this is discussed in the next section. + *

+ *

+ * Binding to Data + *

+ *

+ * You bind the ExpandableListActivity's ExpandableListView object to data using a class that implements the {@link android.widget.ExpandableListAdapter + * ExpandableListAdapter} interface. Android provides two standard list adapters: {@link android.widget.SimpleExpandableListAdapter SimpleExpandableListAdapter} + * for static data (Maps), and {@link android.widget.SimpleCursorTreeAdapter SimpleCursorTreeAdapter} for Cursor query results. + *

+ * + * @see #setListAdapter + * @see android.widget.ExpandableListView + */ +public class ExpandableListActivity extends ActionBarActivity implements + OnCreateContextMenuListener, + ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener, + ExpandableListView.OnGroupExpandListener { + ExpandableListAdapter mAdapter; + ExpandableListView mList; + boolean mFinishedStart = false; + + /** + * Override this to populate the context menu when an item is long pressed. menuInfo will contain an + * {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo} whose packedPosition is a packed position that should be used with + * {@link ExpandableListView#getPackedPositionType(long)} and the other similar methods. + *

+ * {@inheritDoc} + */ + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + } + + /** + * Override this for receiving callbacks when a child has been clicked. + *

+ * {@inheritDoc} + */ + @Override + public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, + int childPosition, long id) { + return false; + } + + /** + * Override this for receiving callbacks when a group has been collapsed. + */ + @Override + public void onGroupCollapse(int groupPosition) { + } + + /** + * Override this for receiving callbacks when a group has been expanded. + */ + @Override + public void onGroupExpand(int groupPosition) { + } + + /** + * Ensures the expandable list view has been created before Activity restores all of the view states. + * + * @see Activity#onRestoreInstanceState(Bundle) + */ + @Override + protected void onRestoreInstanceState(Bundle state) { + ensureList(); + super.onRestoreInstanceState(state); + } + + /** + * Updates the screen state (current list and other views) when the content changes. + * + * @see ActionBarActivity#onSupportContentChanged() + */ + @Override + public void onSupportContentChanged() { + super.onContentChanged(); + View emptyView = findViewById(R.id.empty); + mList = (ExpandableListView) findViewById(R.id.list); + if (mList == null) { + throw new RuntimeException( + "Your content must have a ExpandableListView whose id attribute is " + + "'R.id.list'"); + } + if (emptyView != null) { + mList.setEmptyView(emptyView); + } + mList.setOnChildClickListener(this); + mList.setOnGroupExpandListener(this); + mList.setOnGroupCollapseListener(this); + + if (mFinishedStart) { + setListAdapter(mAdapter); + } + mFinishedStart = true; + } + + /** + * Provide the adapter for the expandable list. + */ + public void setListAdapter(ExpandableListAdapter adapter) { + synchronized (this) { + ensureList(); + mAdapter = adapter; + mList.setAdapter(adapter); + } + } + + /** + * Get the activity's expandable list view widget. This can be used to get the selection, set the selection, and many other useful functions. + * + * @see ExpandableListView + */ + public ExpandableListView getExpandableListView() { + ensureList(); + return mList; + } + + /** + * Get the ExpandableListAdapter associated with this activity's ExpandableListView. + */ + public ExpandableListAdapter getExpandableListAdapter() { + return mAdapter; + } + + private void ensureList() { + if (mList != null) { + return; + } + setContentView(R.layout.expandable_list_content); + } + + /** + * Gets the ID of the currently selected group or child. + * + * @return The ID of the currently selected group or child. + */ + public long getSelectedId() { + return mList.getSelectedId(); + } + + /** + * Gets the position (in packed position representation) of the currently selected group or child. Use {@link ExpandableListView#getPackedPositionType}, + * {@link ExpandableListView#getPackedPositionGroup}, and {@link ExpandableListView#getPackedPositionChild} to unpack the returned packed position. + * + * @return A packed position representation containing the currently selected group or child's position and type. + */ + public long getSelectedPosition() { + return mList.getSelectedPosition(); + } + + /** + * Sets the selection to the specified child. If the child is in a collapsed group, the group will only be expanded and child subsequently selected if + * shouldExpandGroup is set to true, otherwise the method will return false. + * + * @param groupPosition + * The position of the group that contains the child. + * @param childPosition + * The position of the child within the group. + * @param shouldExpandGroup + * Whether the child's group should be expanded if it is collapsed. + * @return Whether the selection was successfully set on the child. + */ + public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) { + return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup); + } + + /** + * Sets the selection to the specified group. + * + * @param groupPosition + * The position of the group that should be selected. + */ + public void setSelectedGroup(int groupPosition) { + mList.setSelectedGroup(groupPosition); + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java new file mode 100644 index 00000000..67970cef --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.bpm; + +import java.util.Calendar; +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileActivity; +import android.os.Bundle; +import android.widget.TextView; + +public class BPMActivity extends BleProfileActivity implements BPMManagerCallbacks { + @SuppressWarnings("unused") + private static final String TAG = "BPMActivity"; + + private TextView mSystolicView; + private TextView mSystolicUnitView; + private TextView mDiastolicView; + private TextView mDiastolicUnitView; + private TextView mMeanAPView; + private TextView mMeanAPUnitView; + private TextView mPulseView; + private TextView mTimestampView; + + @Override + protected void onCreateView(Bundle savedInstanceState) { + setContentView(R.layout.activity_feature_bpm); + setGUI(); + } + + private void setGUI() { + mSystolicView = (TextView) findViewById(R.id.systolic); + mSystolicUnitView = (TextView) findViewById(R.id.systolic_unit); + mDiastolicView = (TextView) findViewById(R.id.diastolic); + mDiastolicUnitView = (TextView) findViewById(R.id.diastolic_unit); + mMeanAPView = (TextView) findViewById(R.id.mean_ap); + mMeanAPUnitView = (TextView) findViewById(R.id.mean_ap_unit); + mPulseView = (TextView) findViewById(R.id.pulse); + mTimestampView = (TextView) findViewById(R.id.timestamp); + } + + @Override + protected int getDefaultDeviceName() { + return R.string.bpm_default_name; + } + + @Override + protected int getAboutTextId() { + return R.string.bpm_about_text; + } + + @Override + protected UUID getFilterUUID() { + return BPMManager.BP_SERVICE_UUID; + } + + @Override + protected BleManager initializeManager() { + final BPMManager manager = BPMManager.getBPMManager(); + manager.setGattCallbacks(this); + return manager; + } + + @Override + protected void setDefaultUI() { + mSystolicView.setText(R.string.not_available_value); + mSystolicUnitView.setText(null); + mDiastolicView.setText(R.string.not_available_value); + mDiastolicUnitView.setText(null); + mMeanAPView.setText(R.string.not_available_value); + mMeanAPUnitView.setText(null); + mPulseView.setText(R.string.not_available_value); + mTimestampView.setText(R.string.not_available); + } + + @Override + public void onServicesDiscovered(final boolean optionalServicesFound) { + // this may notify user or show some views + } + + @Override + public void onBloodPressureMeasurementIndicationsEnabled() { + // this may notify user + } + + @Override + public void onIntermediateCuffPressureNotificationEnabled() { + // this may notify user + } + + @Override + public void onBloodPressureMeasurementRead(final float systolic, final float diastolic, final float meanArterialPressure, final int unit) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mSystolicView.setText(Float.toString(systolic)); + mDiastolicView.setText(Float.toString(diastolic)); + mMeanAPView.setText(Float.toString(meanArterialPressure)); + + mSystolicUnitView.setText(unit == UNIT_mmHG ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa); + mDiastolicUnitView.setText(unit == UNIT_mmHG ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa); + mMeanAPUnitView.setText(unit == UNIT_mmHG ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa); + } + }); + } + + @Override + public void onIntermediateCuffPressureRead(final float cuffPressure, final int unit) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mSystolicView.setText(Float.toString(cuffPressure)); + mDiastolicView.setText(R.string.not_available_value); + mMeanAPView.setText(R.string.not_available_value); + + mSystolicUnitView.setText(unit == UNIT_mmHG ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa); + mDiastolicUnitView.setText(null); + mMeanAPUnitView.setText(null); + } + }); + } + + @Override + public void onPulseRateRead(final float pulseRate) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (pulseRate >= 0) + mPulseView.setText(Float.toString(pulseRate)); + else + mPulseView.setText(R.string.not_available_value); + } + }); + } + + @Override + public void onTimestampRead(final Calendar calendar) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (calendar != null) + mTimestampView.setText(getString(R.string.bpm_timestamp, calendar)); + else + mTimestampView.setText(R.string.not_available); + } + }); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java new file mode 100644 index 00000000..717ffca1 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.bpm; + +import java.util.Calendar; +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothProfile; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +public class BPMManager implements BleManager { + private final String TAG = "BPMManager"; + + private BPMManagerCallbacks mCallbacks; + private BluetoothGatt mBluetoothGatt; + private Context mContext; + + public final static UUID BP_SERVICE_UUID = UUID.fromString("00001810-0000-1000-8000-00805f9b34fb"); + public final static UUID BATTERY_SERVICE = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); + /** Blood Pressure Measurement characteristic */ + private static final UUID BPM_CHARACTERISTIC_UUID = UUID.fromString("00002A35-0000-1000-8000-00805f9b34fb"); + /** Intermediate Cuff Pressure characteristic */ + private static final UUID ICP_CHARACTERISTIC_UUID = UUID.fromString("00002A36-0000-1000-8000-00805f9b34fb"); + /** Battery Level characteristic */ + private final static UUID BATTERY_LEVEL_CHARACTERISTIC = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); + /** Client configuration descriptor that will allow us to enable notifications and indications */ + private static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + + private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change"; + private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services"; + private final static String ERROR_WRITE_DESCRIPTOR = "Error on writing descriptor"; + private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information"; + + private BluetoothGattCharacteristic mBPMCharacteristic, mICPCharacteristic, mBatteryCharacteristic; + + private static BPMManager managerInstance = null; + + /** + * Returns the singleton implementation of BPMManager + */ + public static synchronized BPMManager getBPMManager() { + if (managerInstance == null) { + managerInstance = new BPMManager(); + } + return managerInstance; + } + + /** + * Callbacks for activity {@link BPMActivity} that implements {@link BPMManagerCallbacks} interface activity use this method to register itself for receiving callbacks + */ + @Override + public void setGattCallbacks(final BPMManagerCallbacks callbacks) { + mCallbacks = callbacks; + } + + @Override + public void connect(final Context context, final BluetoothDevice device) { + mBluetoothGatt = device.connectGatt(context, false, mGattCallback); + mContext = context; + } + + @Override + public void disconnect() { + if (mBluetoothGatt != null) { + mBluetoothGatt.disconnect(); + } + } + + private final BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); + final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1); + + DebugLogger.d(TAG, "Bond state changed for: " + device.getAddress() + " new state: " + bondState + " previous: " + previousBondState); + + // skip other devices + if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) + return; + + if (bondState == BluetoothDevice.BOND_BONDED) { + // We've read Battery Level, now let'so enable ICP notifications or BPM indications + if (mICPCharacteristic != null) + enableIntermediateCuffPressureNotification(mBluetoothGatt); + else + enableBloodPressureMeasurementIndication(mBluetoothGatt); + + mContext.unregisterReceiver(this); + mCallbacks.onBonded(); + } + } + }; + + /** + * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving notification, etc + */ + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + mCallbacks.onDeviceConnected(); + // start discovering services + gatt.discoverServices(); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + mCallbacks.onDeviceDisconnected(); + gatt.close(); + } + } else { + mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status); + } + } + + @Override + public void onServicesDiscovered(final BluetoothGatt gatt, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + for (BluetoothGattService service : gatt.getServices()) { + if (BP_SERVICE_UUID.equals(service.getUuid())) { + mBPMCharacteristic = service.getCharacteristic(BPM_CHARACTERISTIC_UUID); + mICPCharacteristic = service.getCharacteristic(ICP_CHARACTERISTIC_UUID); + } else if (BATTERY_SERVICE.equals(service.getUuid())) { + mBatteryCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC); + } + } + // Validate the device + if (mBPMCharacteristic == null) { + mCallbacks.onDeviceNotSupported(); + gatt.disconnect(); + return; + } + mCallbacks.onServicesDiscovered(mICPCharacteristic != null); + + // We have discovered services, let's start notifications and indications, one by one: battery, icp (if exists), bpm + if (mBatteryCharacteristic != null) { + readBatteryLevel(gatt); + } else if (mICPCharacteristic != null) { + enableIntermediateCuffPressureNotification(gatt); + } else { + enableBloodPressureMeasurementIndication(gatt); + } + } else { + DebugLogger.e(TAG, "onServicesDiscovered error " + status); + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (BATTERY_LEVEL_CHARACTERISTIC.equals(characteristic.getUuid())) { + final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); + mCallbacks.onBatteryValueReceived(batteryValue); + + // We've read Battery Level, now let'so enable ICP notifications or BPM indications + if (mICPCharacteristic != null) + enableIntermediateCuffPressureNotification(gatt); + else + enableBloodPressureMeasurementIndication(gatt); + } + } else { + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { + // ICP or BPM characteristic returned value + + // first byte - flags + int offset = 0; + final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset++); + // See BPMManagerCallbacks.UNIT_* for unit options + final int unit = flags & 0x01; + final boolean timestampPresent = (flags & 0x02) > 0; + final boolean pulseRatePresent = (flags & 0x04) > 0; + + if (BPM_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) { + // following bytes - systolic, diastolic and mean arterial pressure + final float systolic = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset); + final float diastolic = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset + 2); + final float meanArterialPressure = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset + 4); + offset += 6; + mCallbacks.onBloodPressureMeasurementRead(systolic, diastolic, meanArterialPressure, unit); + } else if (ICP_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) { + // following bytes - cuff pressure. Diastolic and MAP are unused + final float cuffPressure = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset); + offset += 6; + mCallbacks.onIntermediateCuffPressureRead(cuffPressure, unit); + } + + // parse timestamp if present + if (timestampPresent) { + final Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset)); + calendar.set(Calendar.MONTH, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 2) + 1); // months are 1-based + calendar.set(Calendar.DAY_OF_MONTH, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 3)); + calendar.set(Calendar.HOUR_OF_DAY, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 4)); + calendar.set(Calendar.MINUTE, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 5)); + calendar.set(Calendar.SECOND, characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 6)); + offset += 7; + mCallbacks.onTimestampRead(calendar); + } else + mCallbacks.onTimestampRead(null); + + // parse pulse rate if present + if (pulseRatePresent) { + final float pulseRate = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset); + offset += 2; + mCallbacks.onPulseRateRead(pulseRate); + } else + mCallbacks.onPulseRateRead(-1.0f); + } + + @Override + public void onDescriptorWrite(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (BPM_CHARACTERISTIC_UUID.equals(descriptor.getCharacteristic().getUuid())) + mCallbacks.onBloodPressureMeasurementIndicationsEnabled(); + + if (ICP_CHARACTERISTIC_UUID.equals(descriptor.getCharacteristic().getUuid())) { + mCallbacks.onIntermediateCuffPressureNotificationEnabled(); + enableBloodPressureMeasurementIndication(gatt); + } + } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { + if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) { + mCallbacks.onBondingRequired(); + + final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + mContext.registerReceiver(mBondingBroadcastReceiver, filter); + } else { + DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); + mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status); + } + } else { + mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status); + } + } + + /** + * Reads battery level on the device + */ + private void readBatteryLevel(final BluetoothGatt gatt) { + DebugLogger.d(TAG, "readBatteryLevel()"); + gatt.readCharacteristic(mBatteryCharacteristic); + } + }; + + /** + * Enabling notification on Intermediate Cuff Pressure Characteristic + */ + private void enableIntermediateCuffPressureNotification(final BluetoothGatt gatt) { + DebugLogger.d(TAG, "enableIntermediateCuffPressureNotification()"); + gatt.setCharacteristicNotification(mICPCharacteristic, true); + final BluetoothGattDescriptor descriptor = mICPCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + gatt.writeDescriptor(descriptor); + } + + /** + * Enabling indications on Blood Pressure Measurement Characteristic + */ + private void enableBloodPressureMeasurementIndication(final BluetoothGatt gatt) { + DebugLogger.d(TAG, "enableBloodPressureMeasurementIndication()"); + gatt.setCharacteristicNotification(mBPMCharacteristic, true); + final BluetoothGattDescriptor descriptor = mBPMCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); + gatt.writeDescriptor(descriptor); + } + + @Override + public void closeBluetoothGatt() { + try { + mContext.unregisterReceiver(mBondingBroadcastReceiver); + } catch (Exception e) { + // the receiver must have been not registered or unregistered before + } + + if (mBluetoothGatt != null) { + mBluetoothGatt.close(); + mBPMCharacteristic = null; + mBatteryCharacteristic = null; + mBluetoothGatt = null; + } + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java new file mode 100644 index 00000000..e08d41bc --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.bpm; + +import java.util.Calendar; + +import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; + +public interface BPMManagerCallbacks extends BleManagerCallbacks { + public static final int UNIT_mmHG = 0; + public static final int UNIT_kPa = 1; + + /** + * Called when the Blood Pressure Measurement characteristic indication has been enabled + */ + public void onBloodPressureMeasurementIndicationsEnabled(); + + /** + * Called when the Intermediate Cuff Pressure characteristic notification has been enabled + */ + public void onIntermediateCuffPressureNotificationEnabled(); + + /** + * Called when new BPM value has been obtained from the sensor + * + * @param systolic + * @param diastolic + * @param meanArterialPressure + * @param unit + * one of the following {@link #UNIT_kPa} or {@link #UNIT_mmHG} + */ + public void onBloodPressureMeasurementRead(final float systolic, final float diastolic, final float meanArterialPressure, final int unit); + + /** + * Called when new ICP value has been obtained from the device + * + * @param cuffPressure + * @param unit + * one of the following {@link #UNIT_kPa} or {@link #UNIT_mmHG} + */ + public void onIntermediateCuffPressureRead(final float cuffPressure, final int unit); + + /** + * Called when new pulse rate value has been obtained from the device. If there was no pulse rate in the packet the parameter will be equal -1.0f + * + * @param pulseRate + * pulse rate or -1.0f + */ + public void onPulseRateRead(final float pulseRate); + + /** + * Called when the timestamp value has been read from the device. If there was no timestamp information the parameter will be null + * + * @param calendar + * the timestamp or null + */ + public void onTimestampRead(final Calendar calendar); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java new file mode 100644 index 00000000..170f96d5 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.csc; + +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.csc.settings.SettingsActivity; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; +import android.view.Menu; +import android.widget.TextView; + +public class CSCActivity extends BleProfileServiceReadyActivity { + private TextView mSpeedView; + private TextView mCadenceView; + private TextView mDistanceView; + private TextView mDistanceUnitView; + private TextView mTotalDistanceView; + private TextView mGearRatioView; + + @Override + protected void onCreateView(final Bundle savedInstanceState) { + setContentView(R.layout.activity_feature_csc); + setGui(); + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + private void setGui() { + mSpeedView = (TextView) findViewById(R.id.speed); + mCadenceView = (TextView) findViewById(R.id.cadence); + mDistanceView = (TextView) findViewById(R.id.distance); + mDistanceUnitView = (TextView) findViewById(R.id.distance_unit); + mTotalDistanceView = (TextView) findViewById(R.id.distance_total); + mGearRatioView = (TextView) findViewById(R.id.ratio); + } + + @Override + protected void setDefaultUI() { + mSpeedView.setText(R.string.not_available_value); + mCadenceView.setText(R.string.not_available_value); + mDistanceView.setText(R.string.not_available_value); + mDistanceUnitView.setText(R.string.csc_distance_unit_m); + mTotalDistanceView.setText(R.string.not_available_value); + mGearRatioView.setText(R.string.not_available_value); + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.csc_feature_title; + } + + @Override + protected int getDefaultDeviceName() { + return R.string.csc_default_name; + } + + @Override + protected int getAboutTextId() { + return R.string.csc_about_text; + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.csc_menu, menu); + return true; + } + + @Override + protected boolean onOptionsItemSelected(final int itemId) { + switch (itemId) { + case R.id.action_settings: + final Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + break; + } + return true; + } + + @Override + protected Class getServiceClass() { + return CSCService.class; + } + + @Override + protected UUID getFilterUUID() { + return CSCManager.CYCLING_SPEED_AND_CADENCE_SERVICE_UUID; + } + + @Override + protected void onServiceBinded(final CSCService.CSCBinder binder) { + // not used + } + + @Override + protected void onServiceUnbinded() { + // not used + } + + @Override + public void onServicesDiscovered(final boolean optionalServicesFound) { + // not used + } + + private void onMeasurementReceived(final float speed, final float distance, final float totalDistance) { + mSpeedView.setText(String.format("%.1f", speed)); + if (distance < 1000) { // 1 km in m + mDistanceView.setText(String.format("%.0f", distance)); + mDistanceUnitView.setText(R.string.csc_distance_unit_m); + } else { + mDistanceView.setText(String.format("%.2f", distance / 1000.0f)); + mDistanceUnitView.setText(R.string.csc_distance_unit_km); + } + + mTotalDistanceView.setText(String.format("%.2f", totalDistance / 1000.0f)); + } + + private void onGearRatioUpdate(final float ratio, final int cadence) { + mGearRatioView.setText(String.format("%.1f", ratio)); + mCadenceView.setText(String.format("%d", cadence)); + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + + if (CSCService.BROADCAST_WHEEL_DATA.equals(action)) { + final float speed = intent.getFloatExtra(CSCService.EXTRA_SPEED, 0.0f); + final float distance = intent.getFloatExtra(CSCService.EXTRA_DISTANCE, CSCManagerCallbacks.NOT_AVAILABLE); + final float totalDistance = intent.getFloatExtra(CSCService.EXTRA_TOTAL_DISTANCE, CSCManagerCallbacks.NOT_AVAILABLE); + // Update GUI + onMeasurementReceived(speed, distance, totalDistance); + } else if (CSCService.BROADCAST_CRANK_DATA.equals(action)) { + final float ratio = intent.getFloatExtra(CSCService.EXTRA_GEAR_RATIO, 0); + final int cadence = intent.getIntExtra(CSCService.EXTRA_CADENCE, 0); + // Update GUI + onGearRatioUpdate(ratio, cadence); + } + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(CSCService.BROADCAST_WHEEL_DATA); + intentFilter.addAction(CSCService.BROADCAST_CRANK_DATA); + return intentFilter; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java new file mode 100644 index 00000000..d685d097 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.csc; + +import java.util.List; +import java.util.UUID; + +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothProfile; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +public class CSCManager implements BleManager { + private static final String TAG = "RSCManager"; + + private CSCManagerCallbacks mCallbacks; + private BluetoothGatt mBluetoothGatt; + private Context mContext; + private ILogSession mLogSession; + + private static final byte WHEEL_REVOLUTIONS_DATA_PRESENT = 0x01; // 1 bit + private static final byte CRANK_REVOLUTION_DATA_PRESENT = 0x02; // 1 bit + + public final static UUID CYCLING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001816-0000-1000-8000-00805f9b34fb"); + /** Cycling Speed and Cadence Measurement characteristic */ + private static final UUID CSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A5B-0000-1000-8000-00805f9b34fb"); + + private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); + /** Battery Level characteristic */ + private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); + /** Client configuration descriptor that will allow us to enable notifications and indications */ + private static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + + private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change"; + private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services"; + private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information"; + private final static String ERROR_WRITE_DESCRIPTOR = "Error on writing descriptor"; + private final static String ERROR_READ_CHARACTERISTIC = "Error on reading characteristic"; + + private BluetoothGattCharacteristic mCSCMeasurementCharacteristic, mBatteryCharacteristic; + private boolean mBatteryLevelNotificationsEnabled; + + public CSCManager(final Context context) { + // Register bonding broadcast receiver + final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + context.registerReceiver(mBondingBroadcastReceiver, filter); + } + + @Override + public void setGattCallbacks(final CSCManagerCallbacks callbacks) { + mCallbacks = callbacks; + } + + public void setLogger(final ILogSession session) { + mLogSession = session; + } + + @Override + public void connect(final Context context, final BluetoothDevice device) { + mContext = context; + + Logger.i(mLogSession, "[CSC] Gatt server started"); + if (mBluetoothGatt == null) { + mBluetoothGatt = device.connectGatt(mContext, true, mGattCallback); + } else { + mBluetoothGatt.connect(); + } + } + + @Override + public void disconnect() { + if (mBluetoothGatt != null) { + mBluetoothGatt.disconnect(); + } + } + + /** + * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc + */ + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + DebugLogger.d(TAG, "Device connected"); + mBluetoothGatt.discoverServices(); + //This will send callback to RSCActivity when device get connected + mCallbacks.onDeviceConnected(); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + DebugLogger.d(TAG, "Device disconnected"); + + // TODO It should check whether the user has requested disconnection or was it link loss. On Samsung S4 the DevKit reconnects itself just after linkloss but the Service is already dead. + mCallbacks.onDeviceDisconnected(); + closeBluetoothGatt(); + } + } else { + mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status); + } + } + + @Override + public void onServicesDiscovered(final BluetoothGatt gatt, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + final List services = gatt.getServices(); + for (BluetoothGattService service : services) { + if (service.getUuid().equals(CYCLING_SPEED_AND_CADENCE_SERVICE_UUID)) { + DebugLogger.d(TAG, "Cycling Speed and Cadence service is found"); + mCSCMeasurementCharacteristic = service.getCharacteristic(CSC_MEASUREMENT_CHARACTERISTIC_UUID); + } else if (service.getUuid().equals(BATTERY_SERVICE_UUID)) { + DebugLogger.d(TAG, "Battery service is found"); + mBatteryCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID); + } + } + if (mCSCMeasurementCharacteristic == null) { + mCallbacks.onDeviceNotSupported(); + gatt.disconnect(); + } else { + mCallbacks.onServicesDiscovered(false /* more characteristics not supported */); + + // We have discovered services, let's start notifications and indications, one by one: battery, csc measurement + if (mBatteryCharacteristic != null) { + // Some devices has Battery Level characteristic without READ property + if ((mBatteryCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) > 0) + readBatteryLevel(gatt); + else if ((mBatteryCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) + enableBatteryLevelNotification(gatt); + else + enableCSCMeasurementNotification(gatt); + } else { + enableCSCMeasurementNotification(gatt); + } + } + } else { + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (characteristic.getUuid().equals(BATTERY_LEVEL_CHARACTERISTIC_UUID)) { + int batteryValue = characteristic.getValue()[0]; + mCallbacks.onBatteryValueReceived(batteryValue); + + if (!mBatteryLevelNotificationsEnabled) + enableCSCMeasurementNotification(gatt); + } + } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { + if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { + DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); + mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status); + } + } else { + mCallbacks.onError(ERROR_READ_CHARACTERISTIC, status); + } + } + + @Override + public void onDescriptorWrite(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (descriptor.getCharacteristic().getUuid().equals(BATTERY_LEVEL_CHARACTERISTIC_UUID)) { + enableCSCMeasurementNotification(gatt); + } + } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { + if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { + DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); + mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status); + } + } else { + mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status); + } + } + + @Override + public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { + // Decode the new data + int offset = 0; + final int flags = characteristic.getValue()[offset]; // 1 byte + offset += 1; + + final boolean wheelRevPresent = (flags & WHEEL_REVOLUTIONS_DATA_PRESENT) > 0; + final boolean crankRevPreset = (flags & CRANK_REVOLUTION_DATA_PRESENT) > 0; + + int wheelRevolutions = 0; + int lastWheelEventTime = 0; + if (wheelRevPresent) { + wheelRevolutions = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, offset); + offset += 4; + + lastWheelEventTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); // 1/1024 s + offset += 2; + + // Notify listener about the new measurement + mCallbacks.onWheelMeasurementReceived(wheelRevolutions, lastWheelEventTime); + } + + int crankRevolutions = 0; + int lastCrankEventTime = 0; + if (crankRevPreset) { + crankRevolutions = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); + offset += 2; + + lastCrankEventTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); + offset += 2; + + // Notify listener about the new measurement + mCallbacks.onCrankMeasurementReceived(crankRevolutions, lastCrankEventTime); + } + } + }; + + private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); + final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1); + + // skip other devices + if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) + return; + + DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState); + + if (bondState == BluetoothDevice.BOND_BONDING) { + mCallbacks.onBondingRequired(); + return; + } + if (bondState == BluetoothDevice.BOND_BONDED) { + mCallbacks.onBonded(); + } + } + }; + + public void readBatteryLevel() { + readBatteryLevel(mBluetoothGatt); + } + + /** + * Reading the current value of the battery level + */ + private void readBatteryLevel(final BluetoothGatt gatt) { + if (mBatteryCharacteristic != null) { + if ((mBatteryCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) > 0) { + DebugLogger.d(TAG, "reading battery characteristic"); + gatt.readCharacteristic(mBatteryCharacteristic); + } + } else { + DebugLogger.w(TAG, "Battery Level Characteristic is null"); + } + } + + /** + * Enabling notification on Battery Level Characteristic + */ + private void enableBatteryLevelNotification(final BluetoothGatt gatt) { + mBatteryLevelNotificationsEnabled = true; + gatt.setCharacteristicNotification(mBatteryCharacteristic, true); + final BluetoothGattDescriptor descriptor = mBatteryCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + gatt.writeDescriptor(descriptor); + } + + /** + * Enabling notification on CSC Measurement Characteristic + */ + private void enableCSCMeasurementNotification(final BluetoothGatt gatt) { + gatt.setCharacteristicNotification(mCSCMeasurementCharacteristic, true); + final BluetoothGattDescriptor descriptor = mCSCMeasurementCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + gatt.writeDescriptor(descriptor); + } + + @Override + public void closeBluetoothGatt() { + try { + mContext.unregisterReceiver(mBondingBroadcastReceiver); + } catch (Exception e) { + // the receiver must have been not registered or unregistered before + } + if (mBluetoothGatt != null) { + mBluetoothGatt.close(); + mBluetoothGatt = null; + } + mBatteryLevelNotificationsEnabled = false; + mCallbacks = null; + mLogSession = null; + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java new file mode 100644 index 00000000..08a39000 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.csc; + +import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; + +public interface CSCManagerCallbacks extends BleManagerCallbacks { + public static final int NOT_AVAILABLE = -1; + + public void onWheelMeasurementReceived(final int wheelRevolutions, final int wheelCrankEventTime); + + public void onCrankMeasurementReceived(final int crankRevolutions, final int lastCrankEventTime); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java new file mode 100644 index 00000000..61921c75 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.csc; + +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.FeaturesActivity; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.csc.settings.SettingsFragment; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.os.IBinder; +import android.preference.PreferenceManager; +import android.support.v4.content.LocalBroadcastManager; + +public class CSCService extends BleProfileService implements CSCManagerCallbacks { + private static final String TAG = "CSCService"; + + public static final String BROADCAST_WHEEL_DATA = "no.nordicsemi.android.nrftoolbox.csc.BROADCAST_WHEEL_DATA"; + public static final String EXTRA_SPEED = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_SPEED"; + /** Distance in meters */ + public static final String EXTRA_DISTANCE = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_DISTANCE"; + /** Total distance in meters */ + public static final String EXTRA_TOTAL_DISTANCE = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_TOTAL_DISTANCE"; + + public static final String BROADCAST_CRANK_DATA = "no.nordicsemi.android.nrftoolbox.csc.BROADCAST_CRANK_DATA"; + public static final String EXTRA_GEAR_RATIO = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_GEAR_RATIO"; + public static final String EXTRA_CADENCE = "no.nordicsemi.android.nrftoolbox.csc.EXTRA_CADENCE"; + + private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.csc.ACTION_DISCONNECT"; + + private CSCManager mManager; + private boolean mBinded; + + private int mFirstWheelRevolutions = -1; + private int mLastWheelRevolutions = -1; + private int mLastWheelEventTime = -1; + private float mWheelCadence = -1; + private int mLastCrankRevolutions = -1; + private int mLastCrankEventTime = -1; + + private final static int NOTIFICATION_ID = 200; + private final static int OPEN_ACTIVITY_REQ = 0; + private final static int DISCONNECT_REQ = 1; + + private final LocalBinder mBinder = new CSCBinder(); + + /** + * This local binder is an interface for the binded activity to operate with the RSC sensor + */ + public class CSCBinder extends LocalBinder { + // empty + } + + @Override + protected LocalBinder getBinder() { + return mBinder; + } + + @Override + protected BleManager initializeManager() { + return mManager = new CSCManager(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DISCONNECT); + registerReceiver(mDisconnectActionBroadcastReceiver, filter); + } + + @Override + public void onDestroy() { + // when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService + cancelNotification(); + unregisterReceiver(mDisconnectActionBroadcastReceiver); + + super.onDestroy(); + } + + @Override + public IBinder onBind(final Intent intent) { + mBinded = true; + return super.onBind(intent); + } + + @Override + public void onRebind(final Intent intent) { + mBinded = true; + // when the activity rebinds to the service, remove the notification + cancelNotification(); + + // read the battery level when back in the Activity + if (isConnected()) + mManager.readBatteryLevel(); + } + + @Override + public boolean onUnbind(final Intent intent) { + mBinded = false; + // when the activity closes we need to show the notification that user is connected to the sensor + createNotification(R.string.csc_notification_connected_message, 0); + return super.onUnbind(intent); + } + + @Override + protected void onServiceStarted() { + // logger is now available. Assign it to the manager + mManager.setLogger(getLogSession()); + } + + @Override + public void onWheelMeasurementReceived(final int wheelRevolutions, final int lastWheelEventTime) { + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + final int circumference = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_WHEEL_SIZE, String.valueOf(SettingsFragment.SETTINGS_WHEEL_SIZE_DEFAULT))); // [mm] + + if (mFirstWheelRevolutions < 0) + mFirstWheelRevolutions = wheelRevolutions; + + if (mLastWheelEventTime == lastWheelEventTime) + return; + + if (mLastWheelRevolutions >= 0) { + float timeDifference = 0; + if (lastWheelEventTime < mLastWheelEventTime) + timeDifference = (65535 + lastWheelEventTime - mLastWheelEventTime) / 1024.0f; // [s] + else + timeDifference = (lastWheelEventTime - mLastWheelEventTime) / 1024.0f; // [s] + final float distanceDifference = (wheelRevolutions - mLastWheelRevolutions) * circumference / 1000.0f; // [m] + final float totalDistance = (float) wheelRevolutions * (float) circumference / 1000.0f; // [m] + final float distance = (float) (wheelRevolutions - mFirstWheelRevolutions) * (float) circumference / 1000.0f; // [m] + final float speed = distanceDifference / timeDifference; + mWheelCadence = (wheelRevolutions - mLastWheelRevolutions) * 60.0f / timeDifference; + + final Intent broadcast = new Intent(BROADCAST_WHEEL_DATA); + broadcast.putExtra(EXTRA_SPEED, speed); + broadcast.putExtra(EXTRA_DISTANCE, distance); + broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + mLastWheelRevolutions = wheelRevolutions; + mLastWheelEventTime = lastWheelEventTime; + } + + @Override + public void onCrankMeasurementReceived(int crankRevolutions, int lastCrankEventTime) { + if (mLastCrankEventTime == lastCrankEventTime) + return; + + if (mLastCrankRevolutions >= 0) { + float timeDifference = 0; + if (lastCrankEventTime < mLastCrankEventTime) + timeDifference = (65535 + lastCrankEventTime - mLastCrankEventTime) / 1024.0f; // [s] + else + timeDifference = (lastCrankEventTime - mLastCrankEventTime) / 1024.0f; // [s] + + final float crankCadence = (crankRevolutions - mLastCrankRevolutions) * 60.0f / timeDifference; + if (crankCadence > 0) { + final float gearRatio = mWheelCadence / crankCadence; + + final Intent broadcast = new Intent(BROADCAST_CRANK_DATA); + broadcast.putExtra(EXTRA_GEAR_RATIO, gearRatio); + broadcast.putExtra(EXTRA_CADENCE, (int) crankCadence); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + } + mLastCrankRevolutions = crankRevolutions; + mLastCrankEventTime = lastCrankEventTime; + } + + /** + * Creates the notification + * + * @param messageResId + * the message resource id. The message must have one String parameter,
+ * f.e. <string name="name">%s is connected</string> + * @param defaults + * signals that will be used to notify the user + */ + private void createNotification(final int messageResId, final int defaults) { + final Intent parentIntent = new Intent(this, FeaturesActivity.class); + parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final Intent targetIntent = new Intent(this, CSCActivity.class); + + final Intent disconnect = new Intent(ACTION_DISCONNECT); + final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT); + + // both activities above have launchMode="singleTask" in the AndoridManifest.xml file, so if the task is already running, it will be resumed + final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT); + final Notification.Builder builder = new Notification.Builder(this).setContentIntent(pendingIntent); + builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); + builder.setSmallIcon(R.drawable.ic_stat_notify_csc); + builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); + builder.addAction(R.drawable.ic_action_bluetooth, getString(R.string.csc_notification_action_disconnect), disconnectAction); + + final Notification notification = builder.build(); + final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID, notification); + } + + /** + * Cancels the existing notification. If there is no active notification this method does nothing + */ + private void cancelNotification() { + final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + nm.cancel(NOTIFICATION_ID); + } + + /** + * This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification. + */ + private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + Logger.i(getLogSession(), "[CSC] Disconnect action pressed"); + if (isConnected()) + getBinder().disconnect(); + else + stopSelf(); + } + }; + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsActivity.java new file mode 100644 index 00000000..a88e50a0 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsActivity.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.csc.settings; + +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.view.MenuItem; + +public class SettingsActivity extends ActionBarActivity { + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + // Display the fragment as the main content. + getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsFragment.java new file mode 100644 index 00000000..e4e0f39a --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsFragment.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.csc.settings; + +import no.nordicsemi.android.nrftoolbox.R; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; + +public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener { + public static final String SETTINGS_WHEEL_SIZE = "settings_wheel_size"; + public static final int SETTINGS_WHEEL_SIZE_DEFAULT = 2340; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.settings_csc); + + // set initial values + updateWheelSizeSummary(); + } + + @Override + public void onResume() { + super.onResume(); + + // attach the preference change listener. It will update the summary below interval preference + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + super.onPause(); + + // unregister listener + getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { + if (SETTINGS_WHEEL_SIZE.equals(key)) { + updateWheelSizeSummary(); + } + } + + private void updateWheelSizeSummary() { + final PreferenceScreen screen = getPreferenceScreen(); + final SharedPreferences preferences = getPreferenceManager().getSharedPreferences(); + + final String value = preferences.getString(SETTINGS_WHEEL_SIZE, String.valueOf(SETTINGS_WHEEL_SIZE_DEFAULT)); + screen.findPreference(SETTINGS_WHEEL_SIZE).setSummary(getString(R.string.csc_settings_wheel_diameter_summary, value)); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java new file mode 100644 index 00000000..1dfee403 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java @@ -0,0 +1,923 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.dfu; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.app.AlertDialog; +import android.app.FragmentManager; +import android.app.LoaderManager.LoaderCallbacks; +import android.app.NotificationManager; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.CursorLoader; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.Loader; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.os.Environment; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.provider.MediaStore; +import android.support.v4.content.LocalBroadcastManager; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.webkit.MimeTypeMap; +import android.widget.Button; +import android.widget.ListView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import no.nordicsemi.android.error.GattError; +import no.nordicsemi.android.nrftoolbox.AppHelpFragment; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.dfu.adapter.FileBrowserAppsAdapter; +import no.nordicsemi.android.nrftoolbox.dfu.fragment.UploadCancelFragment; +import no.nordicsemi.android.nrftoolbox.dfu.fragment.ZipInfoFragment; +import no.nordicsemi.android.nrftoolbox.dfu.settings.SettingsActivity; +import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; + +/** + * DfuActivity is the main DFU activity It implements DFUManagerCallbacks to receive callbacks from DFUManager class It implements + * DeviceScannerFragment.OnDeviceSelectedListener callback to receive callback when device is selected from scanning dialog The activity supports portrait and + * landscape orientations + */ +public class DfuActivity extends ActionBarActivity implements LoaderCallbacks, ScannerFragment.OnDeviceSelectedListener, + UploadCancelFragment.CancelFragmentListener { + private static final String TAG = "DfuActivity"; + + private static final String PREFS_SAMPLES_VERSION = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_SAMPLES_VERSION"; + private static final int CURRENT_SAMPLES_VERSION = 2; + + private static final String PREFS_DEVICE_NAME = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_DEVICE_NAME"; + private static final String PREFS_FILE_NAME = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_FILE_NAME"; + private static final String PREFS_FILE_TYPE = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_FILE_TYPE"; + private static final String PREFS_FILE_SIZE = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_FILE_SIZE"; + + private static final String DATA_DEVICE = "device"; + private static final String DATA_FILE_TYPE = "file_type"; + private static final String DATA_FILE_TYPE_TMP = "file_type_tmp"; + private static final String DATA_FILE_PATH = "file_path"; + private static final String DATA_FILE_STREAM = "file_stream"; + private static final String DATA_INIT_FILE_PATH = "init_file_path"; + private static final String DATA_INIT_FILE_STREAM = "init_file_stream"; + private static final String DATA_STATUS = "status"; + + private static final String EXTRA_URI = "uri"; + + private static final int ENABLE_BT_REQ = 0; + private static final int SELECT_FILE_REQ = 1; + private static final int SELECT_INIT_FILE_REQ = 2; + + private TextView mDeviceNameView; + private TextView mFileNameView; + private TextView mFileTypeView; + private TextView mFileSizeView; + private TextView mFileStatusView; + private TextView mTextPercentage; + private TextView mTextUploading; + private ProgressBar mProgressBar; + + private Button mSelectFileButton, mUploadButton, mConnectButton; + + private BluetoothDevice mSelectedDevice; + private String mFilePath; + private Uri mFileStreamUri; + private String mInitFilePath; + private Uri mInitFileStreamUri; + private int mFileType; + private int mFileTypeTmp; // This value is being used when user is selecting a file not to overwrite the old value (in case he/she will cancel selecting file) + private boolean mStatusOk; + + private final BroadcastReceiver mDfuUpdateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + // DFU is in progress or an error occurred + final String action = intent.getAction(); + + if (DfuService.BROADCAST_PROGRESS.equals(action)) { + final int progress = intent.getIntExtra(DfuService.EXTRA_DATA, 0); + final int currentPart = intent.getIntExtra(DfuService.EXTRA_PART_CURRENT, 1); + final int totalParts = intent.getIntExtra(DfuService.EXTRA_PARTS_TOTAL, 1); + updateProgressBar(progress, currentPart, totalParts, false); + } else if (DfuService.BROADCAST_ERROR.equals(action)) { + final int error = intent.getIntExtra(DfuService.EXTRA_DATA, 0); + updateProgressBar(error, 0, 0, true); + + // We have to wait a bit before canceling notification. This is called before DfuService creates the last notification. + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + // if this activity is still open and upload process was completed, cancel the notification + final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + manager.cancel(DfuService.NOTIFICATION_ID); + } + }, 200); + } + } + }; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_feature_dfu); + isBLESupported(); + if (!isBLEEnabled()) { + showBLEDialog(); + } + setGUI(); + + ensureSamplesExist(); + + // restore saved state + mFileType = DfuService.TYPE_APPLICATION; // Default + if (savedInstanceState != null) { + mFileType = savedInstanceState.getInt(DATA_FILE_TYPE); + mFileTypeTmp = savedInstanceState.getInt(DATA_FILE_TYPE_TMP); + mFilePath = savedInstanceState.getString(DATA_FILE_PATH); + mFileStreamUri = savedInstanceState.getParcelable(DATA_FILE_STREAM); + mInitFilePath = savedInstanceState.getString(DATA_INIT_FILE_PATH); + mInitFileStreamUri = savedInstanceState.getParcelable(DATA_INIT_FILE_STREAM); + mSelectedDevice = savedInstanceState.getParcelable(DATA_DEVICE); + mStatusOk = mStatusOk || savedInstanceState.getBoolean(DATA_STATUS); + mUploadButton.setEnabled(mSelectedDevice != null && mStatusOk); + } + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(DATA_FILE_TYPE, mFileType); + outState.putInt(DATA_FILE_TYPE_TMP, mFileTypeTmp); + outState.putString(DATA_FILE_PATH, mFilePath); + outState.putParcelable(DATA_FILE_STREAM, mFileStreamUri); + outState.putString(DATA_INIT_FILE_PATH, mInitFilePath); + outState.putParcelable(DATA_INIT_FILE_STREAM, mInitFileStreamUri); + outState.putParcelable(DATA_DEVICE, mSelectedDevice); + outState.putBoolean(DATA_STATUS, mStatusOk); + } + + private void setGUI() { + final ActionBar actionBar = getSupportActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + + mDeviceNameView = (TextView) findViewById(R.id.device_name); + mFileNameView = (TextView) findViewById(R.id.file_name); + mFileTypeView = (TextView) findViewById(R.id.file_type); + mFileSizeView = (TextView) findViewById(R.id.file_size); + mFileStatusView = (TextView) findViewById(R.id.file_status); + mSelectFileButton = (Button) findViewById(R.id.action_select_file); + + mUploadButton = (Button) findViewById(R.id.action_upload); + mConnectButton = (Button) findViewById(R.id.action_connect); + mTextPercentage = (TextView) findViewById(R.id.textviewProgress); + mTextUploading = (TextView) findViewById(R.id.textviewUploading); + mProgressBar = (ProgressBar) findViewById(R.id.progressbar_file); + + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + if (isDfuServiceRunning()) { + // Restore image file information + mDeviceNameView.setText(preferences.getString(PREFS_DEVICE_NAME, "")); + mFileNameView.setText(preferences.getString(PREFS_FILE_NAME, "")); + mFileTypeView.setText(preferences.getString(PREFS_FILE_TYPE, "")); + mFileSizeView.setText(preferences.getString(PREFS_FILE_SIZE, "")); + mFileStatusView.setText(R.string.dfu_file_status_ok); + mStatusOk = true; + showProgressBar(); + } + } + + @Override + protected void onResume() { + super.onResume(); + + // We are using LocalBroadcastReceiver instead of normal BroadcastReceiver for optimization purposes + final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this); + broadcastManager.registerReceiver(mDfuUpdateReceiver, makeDfuUpdateIntentFilter()); + } + + @Override + protected void onPause() { + super.onPause(); + + final LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this); + broadcastManager.unregisterReceiver(mDfuUpdateReceiver); + } + + private static IntentFilter makeDfuUpdateIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(DfuService.BROADCAST_PROGRESS); + intentFilter.addAction(DfuService.BROADCAST_ERROR); + intentFilter.addAction(DfuService.BROADCAST_LOG); + return intentFilter; + } + + private void isBLESupported() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + showToast(R.string.no_ble); + finish(); + } + } + + private boolean isBLEEnabled() { + final BluetoothManager manager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + final BluetoothAdapter adapter = manager.getAdapter(); + return adapter != null && adapter.isEnabled(); + } + + private void showBLEDialog() { + final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableIntent, ENABLE_BT_REQ); + } + + private void showDeviceScanningDialog() { + final FragmentManager fm = getFragmentManager(); + final ScannerFragment dialog = ScannerFragment.getInstance(DfuActivity.this, null, false); // Device that is advertising directly does not have the GENERAL_DISCOVERABLE nor LIMITED_DISCOVERABLE flag set. + dialog.show(fm, "scan_fragment"); + } + + private void ensureSamplesExist() { + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + final int version = preferences.getInt(PREFS_SAMPLES_VERSION, 0); + if (version == CURRENT_SAMPLES_VERSION) + return; + + /* + * Copy example HEX files to the external storage. Files will be copied if the DFU Applications folder is missing + */ + final File root = new File(Environment.getExternalStorageDirectory(), "Nordic Semiconductor"); + if (!root.exists()) { + root.mkdir(); + } + final File board = new File(root, "Board"); + if (!board.exists()) { + board.mkdir(); + } + final File nrf6310 = new File(board, "nrf6310"); + if (!nrf6310.exists()) { + nrf6310.mkdir(); + } + final File pca10028 = new File(board, "pca10028"); + if (!pca10028.exists()) { + pca10028.mkdir(); + } + + // Remove old files. Those will be moved to a new folder structure + new File(root, "ble_app_hrs_s110_v6_0_0.hex").delete(); + new File(root, "ble_app_rscs_s110_v6_0_0.hex").delete(); + new File(root, "ble_app_hrs_s110_v7_0_0.hex").delete(); + new File(root, "ble_app_rscs_s110_v7_0_0.hex").delete(); + new File(root, "blinky_arm_s110_v7_0_0.hex").delete(); + new File(root, "dfu_2_0.bat").delete(); // This file has been migrated to 3.0 + new File(root, "dfu_3_0.bat").delete(); // This file has been modified - bug fixed + new File(root, "dfu_2_0.sh").delete(); // This file has been migrated to 3.0 + new File(root, "README.txt").delete(); // This file has been modified to match v.3.0 + + boolean oldCopied = false; + boolean newCopied = false; + + // nrf6310 files + File f = new File(nrf6310, "ble_app_hrs_s110_v6_0_0.hex"); + if (!f.exists()) { + copyRawResource(R.raw.ble_app_hrs_s110_v6_0_0, f); + oldCopied = true; + } + f = new File(nrf6310, "ble_app_rscs_s110_v6_0_0.hex"); + if (!f.exists()) { + copyRawResource(R.raw.ble_app_rscs_s110_v6_0_0, f); + oldCopied = true; + } + f = new File(nrf6310, "ble_app_hrs_s110_v7_0_0.hex"); + if (!f.exists()) { + copyRawResource(R.raw.ble_app_hrs_s110_v7_0_0, f); + oldCopied = true; + } + f = new File(nrf6310, "ble_app_rscs_s110_v7_0_0.hex"); + if (!f.exists()) { + copyRawResource(R.raw.ble_app_rscs_s110_v7_0_0, f); + oldCopied = true; + } + f = new File(nrf6310, "blinky_arm_s110_v7_0_0.hex"); + if (!f.exists()) { + copyRawResource(R.raw.blinky_arm_s110_v7_0_0, f); + oldCopied = true; + } + // PCA10028 files + f = new File(pca10028, "blinky_s110_v7_1_0.hex"); + if (!f.exists()) { + copyRawResource(R.raw.blinky_s110_v7_1_0, f); + oldCopied = true; + } + f = new File(pca10028, "blinky_s110_v7_1_0_ext_init.dat"); + if (!f.exists()) { + copyRawResource(R.raw.blinky_s110_v7_1_0_ext_init, f); + oldCopied = true; + } + f = new File(pca10028, "ble_app_hrs_dfu_s110_v7_1_0.hex"); + if (!f.exists()) { + copyRawResource(R.raw.ble_app_hrs_dfu_s110_v7_1_0, f); + oldCopied = true; + } + f = new File(pca10028, "ble_app_hrs_dfu_s110_v7_1_0_ext_init.dat"); + if (!f.exists()) { + copyRawResource(R.raw.ble_app_hrs_dfu_s110_v7_1_0_ext_init, f); + oldCopied = true; + } + + if (oldCopied) + Toast.makeText(this, R.string.dfu_example_files_created, Toast.LENGTH_SHORT).show(); + else if (newCopied) + Toast.makeText(this, R.string.dfu_example_new_files_created, Toast.LENGTH_SHORT).show(); + + // Scripts + newCopied = false; + f = new File(root, "dfu_3_0.bat"); + if (!f.exists()) { + copyRawResource(R.raw.dfu_win_3_0, f); + newCopied = true; + } + f = new File(root, "dfu_3_0.sh"); + if (!f.exists()) { + copyRawResource(R.raw.dfu_mac_3_0, f); + newCopied = true; + } + f = new File(root, "README.txt"); + if (!f.exists()) { + copyRawResource(R.raw.readme, f); + } + if (newCopied) + Toast.makeText(this, R.string.dfu_scripts_created, Toast.LENGTH_SHORT).show(); + + // Save the current version + preferences.edit().putInt(PREFS_SAMPLES_VERSION, CURRENT_SAMPLES_VERSION).apply(); + } + + /** + * Copies the file from res/raw with given id to given destination file. If dest does not exist it will be created. + * + * @param rawResId the resource id + * @param dest destination file + */ + private void copyRawResource(final int rawResId, final File dest) { + try { + final InputStream is = getResources().openRawResource(rawResId); + final FileOutputStream fos = new FileOutputStream(dest); + + final byte[] buf = new byte[1024]; + int read; + try { + while ((read = is.read(buf)) > 0) + fos.write(buf, 0, read); + } finally { + is.close(); + fos.close(); + } + } catch (final IOException e) { + DebugLogger.e(TAG, "Error while copying HEX file " + e.toString()); + } + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.dfu_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + break; + case R.id.action_about: + final AppHelpFragment fragment = AppHelpFragment.getInstance(R.string.dfu_about_text); + fragment.show(getFragmentManager(), "help_fragment"); + break; + case R.id.action_settings: + final Intent intent = new Intent(this, SettingsActivity.class); + startActivity(intent); + break; + } + return true; + } + + @Override + protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { + if (resultCode != RESULT_OK) + return; + + switch (requestCode) { + case SELECT_FILE_REQ: { + // clear previous data + mFileType = mFileTypeTmp; + mFilePath = null; + mFileStreamUri = null; + + // and read new one + final Uri uri = data.getData(); + /* + * The URI returned from application may be in 'file' or 'content' schema. 'File' schema allows us to create a File object and read details from if + * directly. Data from 'Content' schema must be read by Content Provider. To do that we are using a Loader. + */ + if (uri.getScheme().equals("file")) { + // the direct path to the file has been returned + final String path = uri.getPath(); + final File file = new File(path); + mFilePath = path; + + updateFileInfo(file.getName(), file.length(), mFileType); + } else if (uri.getScheme().equals("content")) { + // an Uri has been returned + mFileStreamUri = uri; + // if application returned Uri for streaming, let's us it. Does it works? + // FIXME both Uris works with Google Drive app. Why both? What's the difference? How about other apps like DropBox? + final Bundle extras = data.getExtras(); + if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)) + mFileStreamUri = extras.getParcelable(Intent.EXTRA_STREAM); + + // file name and size must be obtained from Content Provider + final Bundle bundle = new Bundle(); + bundle.putParcelable(EXTRA_URI, uri); + getLoaderManager().restartLoader(SELECT_FILE_REQ, bundle, this); + } + break; + } + case SELECT_INIT_FILE_REQ: { + mInitFilePath = null; + mInitFileStreamUri = null; + + // and read new one + final Uri uri = data.getData(); + /* + * The URI returned from application may be in 'file' or 'content' schema. 'File' schema allows us to create a File object and read details from if + * directly. Data from 'Content' schema must be read by Content Provider. To do that we are using a Loader. + */ + if (uri.getScheme().equals("file")) { + // the direct path to the file has been returned + mInitFilePath = uri.getPath(); + mFileStatusView.setText(R.string.dfu_file_status_ok_with_init); + } else if (uri.getScheme().equals("content")) { + // an Uri has been returned + mInitFileStreamUri = uri; + // if application returned Uri for streaming, let's us it. Does it works? + // FIXME both Uris works with Google Drive app. Why both? What's the difference? How about other apps like DropBox? + final Bundle extras = data.getExtras(); + if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)) + mInitFileStreamUri = extras.getParcelable(Intent.EXTRA_STREAM); + mFileStatusView.setText(R.string.dfu_file_status_ok_with_init); + } + break; + } + default: + break; + } + } + + @Override + public Loader onCreateLoader(final int id, final Bundle args) { + final Uri uri = args.getParcelable(EXTRA_URI); + /* + * Some apps, f.e. Google Drive allow to select file that is not on the device. There is no "_data" column handled by that provider. Let's try to obtain + * all columns and than check which columns are present. + */ + // final String[] projection = new String[] { MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.SIZE, MediaStore.MediaColumns.DATA }; + return new CursorLoader(this, uri, null /* all columns, instead of projection */, null, null, null); + } + + @Override + public void onLoaderReset(final Loader loader) { + mFileNameView.setText(null); + mFileTypeView.setText(null); + mFileSizeView.setText(null); + mFilePath = null; + mFileStreamUri = null; + mStatusOk = false; + } + + @Override + public void onLoadFinished(final Loader loader, final Cursor data) { + if (data != null && data.moveToNext()) { + /* + * Here we have to check the column indexes by name as we have requested for all. The order may be different. + */ + final String fileName = data.getString(data.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME)/* 0 DISPLAY_NAME */); + final int fileSize = data.getInt(data.getColumnIndex(MediaStore.MediaColumns.SIZE) /* 1 SIZE */); + String filePath = null; + final int dataIndex = data.getColumnIndex(MediaStore.MediaColumns.DATA); + if (dataIndex != -1) + filePath = data.getString(dataIndex /* 2 DATA */); + if (!TextUtils.isEmpty(filePath)) + mFilePath = filePath; + + updateFileInfo(fileName, fileSize, mFileType); + } else { + mFileNameView.setText(null); + mFileTypeView.setText(null); + mFileSizeView.setText(null); + mFilePath = null; + mFileStreamUri = null; + mFileStatusView.setText(R.string.dfu_file_status_error); + mStatusOk = false; + } + } + + /** + * Updates the file information on UI + * + * @param fileName file name + * @param fileSize file length + */ + private void updateFileInfo(final String fileName, final long fileSize, final int fileType) { + mFileNameView.setText(fileName); + switch (fileType) { + case DfuService.TYPE_SOFT_DEVICE: + mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[0]); + break; + case DfuService.TYPE_BOOTLOADER: + mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[1]); + break; + case DfuService.TYPE_APPLICATION: + mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[2]); + break; + case DfuService.TYPE_AUTO: + mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[3]); + break; + } + mFileSizeView.setText(getString(R.string.dfu_file_size_text, fileSize)); + final String extension = mFileType == DfuService.TYPE_AUTO ? "(?i)ZIP" : "(?i)HEX|BIN"; // (?i) = case insensitive + final boolean statusOk = mStatusOk = MimeTypeMap.getFileExtensionFromUrl(fileName).matches(extension); + mFileStatusView.setText(statusOk ? R.string.dfu_file_status_ok : R.string.dfu_file_status_invalid); + mUploadButton.setEnabled(mSelectedDevice != null && statusOk); + + // Ask the user for the Init packet file if HEX or BIN files are selected. In case of a ZIP file the Init packets should be included in the ZIP. + if (statusOk && fileType != DfuService.TYPE_AUTO) { + new AlertDialog.Builder(this).setTitle(R.string.dfu_file_init_title).setMessage(R.string.dfu_file_init_message) + .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + mInitFilePath = null; + mInitFileStreamUri = null; + } + }).setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType(DfuService.MIME_TYPE_OCTET_STREAM); + intent.addCategory(Intent.CATEGORY_OPENABLE); + startActivityForResult(intent, SELECT_INIT_FILE_REQ); + } + }).show(); + } + } + + /** + * Called when the question mark was pressed + * + * @param view a button that was pressed + */ + public void onSelectFileHelpClicked(final View view) { + new AlertDialog.Builder(this).setTitle(R.string.dfu_help_title).setMessage(R.string.dfu_help_message).setPositiveButton(R.string.ok, null) + .show(); + } + + /** + * Called when Select File was pressed + * + * @param view a button that was pressed + */ + public void onSelectFileClicked(final View view) { + mFileTypeTmp = mFileType; + int index = 2; + switch (mFileType) { + case DfuService.TYPE_SOFT_DEVICE: + index = 0; + break; + case DfuService.TYPE_BOOTLOADER: + index = 1; + break; + case DfuService.TYPE_APPLICATION: + index = 2; + break; + case DfuService.TYPE_AUTO: + index = 3; + break; + } + // Show a dialog with file types + new AlertDialog.Builder(this).setTitle(R.string.dfu_file_type_title) + .setSingleChoiceItems(R.array.dfu_file_type, index, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + switch (which) { + case 0: + mFileTypeTmp = DfuService.TYPE_SOFT_DEVICE; + break; + case 1: + mFileTypeTmp = DfuService.TYPE_BOOTLOADER; + break; + case 2: + mFileTypeTmp = DfuService.TYPE_APPLICATION; + break; + case 3: + mFileTypeTmp = DfuService.TYPE_AUTO; + break; + } + } + }).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + openFileChooser(); + } + }).setNeutralButton(R.string.dfu_file_info, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + final ZipInfoFragment fragment = new ZipInfoFragment(); + fragment.show(getFragmentManager(), "help_fragment"); + } + }).setNegativeButton(R.string.cancel, null).show(); + } + + private void openFileChooser() { + final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); + intent.setType(mFileTypeTmp == DfuService.TYPE_AUTO ? DfuService.MIME_TYPE_ZIP : DfuService.MIME_TYPE_OCTET_STREAM); + intent.addCategory(Intent.CATEGORY_OPENABLE); + if (intent.resolveActivity(getPackageManager()) != null) { + // file browser has been found on the device + startActivityForResult(intent, SELECT_FILE_REQ); + } else { + // there is no any file browser app, let's try to download one + final View customView = getLayoutInflater().inflate(R.layout.app_file_browser, null); + final ListView appsList = (ListView) customView.findViewById(android.R.id.list); + appsList.setAdapter(new FileBrowserAppsAdapter(this)); + appsList.setChoiceMode(ListView.CHOICE_MODE_SINGLE); + appsList.setItemChecked(0, true); + new AlertDialog.Builder(this).setTitle(R.string.dfu_alert_no_filebrowser_title).setView(customView) + .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + dialog.dismiss(); + } + }).setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + final int pos = appsList.getCheckedItemPosition(); + if (pos >= 0) { + final String query = getResources().getStringArray(R.array.dfu_app_file_browser_action)[pos]; + final Intent storeIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(query)); + startActivity(storeIntent); + } + } + }).show(); + } + } + + /** + * Callback of UPDATE/CANCEL button on DfuActivity + */ + public void onUploadClicked(final View view) { + if (isDfuServiceRunning()) { + showUploadCancelDialog(); + return; + } + + // Check whether the selected file is a HEX file (we are just checking the extension) + if (!mStatusOk) { + Toast.makeText(this, R.string.dfu_file_status_invalid_message, Toast.LENGTH_LONG).show(); + return; + } + + // Save current state in order to restore it if user quit the Activity + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + final SharedPreferences.Editor editor = preferences.edit(); + editor.putString(PREFS_DEVICE_NAME, mSelectedDevice.getName()); + editor.putString(PREFS_FILE_NAME, mFileNameView.getText().toString()); + editor.putString(PREFS_FILE_TYPE, mFileTypeView.getText().toString()); + editor.putString(PREFS_FILE_SIZE, mFileSizeView.getText().toString()); + editor.apply(); + + showProgressBar(); + + final Intent service = new Intent(this, DfuService.class); + service.putExtra(DfuService.EXTRA_DEVICE_ADDRESS, mSelectedDevice.getAddress()); + service.putExtra(DfuService.EXTRA_DEVICE_NAME, mSelectedDevice.getName()); + service.putExtra(DfuService.EXTRA_FILE_MIME_TYPE, mFileType == DfuService.TYPE_AUTO ? DfuService.MIME_TYPE_ZIP : DfuService.MIME_TYPE_OCTET_STREAM); + service.putExtra(DfuService.EXTRA_FILE_TYPE, mFileType); + service.putExtra(DfuService.EXTRA_FILE_PATH, mFilePath); + service.putExtra(DfuService.EXTRA_FILE_URI, mFileStreamUri); + service.putExtra(DfuService.EXTRA_INIT_FILE_PATH, mInitFilePath); + service.putExtra(DfuService.EXTRA_INIT_FILE_URI, mInitFileStreamUri); + startService(service); + } + + private void showUploadCancelDialog() { + final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this); + final Intent pauseAction = new Intent(DfuService.BROADCAST_ACTION); + pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_PAUSE); + manager.sendBroadcast(pauseAction); + + final UploadCancelFragment fragment = UploadCancelFragment.getInstance(); + fragment.show(getFragmentManager(), TAG); + } + + /** + * Callback of CONNECT/DISCONNECT button on DfuActivity + */ + public void onConnectClicked(final View view) { + if (isBLEEnabled()) { + showDeviceScanningDialog(); + } else { + showBLEDialog(); + } + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + mSelectedDevice = device; + mUploadButton.setEnabled(mStatusOk); + mDeviceNameView.setText(name); + } + + @Override + public void onDialogCanceled() { + // do nothing + } + + private void updateProgressBar(final int progress, final int part, final int total, final boolean error) { + switch (progress) { + case DfuService.PROGRESS_CONNECTING: + mProgressBar.setIndeterminate(true); + mTextPercentage.setText(R.string.dfu_status_connecting); + break; + case DfuService.PROGRESS_STARTING: + mProgressBar.setIndeterminate(true); + mTextPercentage.setText(R.string.dfu_status_starting); + break; + case DfuService.PROGRESS_ENABLING_DFU_MODE: + mProgressBar.setIndeterminate(true); + mTextPercentage.setText(R.string.dfu_status_switching_to_dfu); + break; + case DfuService.PROGRESS_VALIDATING: + mProgressBar.setIndeterminate(true); + mTextPercentage.setText(R.string.dfu_status_validating); + break; + case DfuService.PROGRESS_DISCONNECTING: + mProgressBar.setIndeterminate(true); + mTextPercentage.setText(R.string.dfu_status_disconnecting); + break; + case DfuService.PROGRESS_COMPLETED: + mTextPercentage.setText(R.string.dfu_status_completed); + // let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again. + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + onTransferCompleted(); + + // if this activity is still open and upload process was completed, cancel the notification + final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + manager.cancel(DfuService.NOTIFICATION_ID); + } + }, 200); + break; + case DfuService.PROGRESS_ABORTED: + mTextPercentage.setText(R.string.dfu_status_aborted); + // let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again. + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + onUploadCanceled(); + + // if this activity is still open and upload process was completed, cancel the notification + final NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + manager.cancel(DfuService.NOTIFICATION_ID); + } + }, 200); + break; + default: + mProgressBar.setIndeterminate(false); + if (error) { + showErrorMessage(progress); + } else { + mProgressBar.setProgress(progress); + mTextPercentage.setText(getString(R.string.progress, progress)); + if (total > 1) + mTextUploading.setText(getString(R.string.dfu_status_uploading_part, part, total)); + else + mTextUploading.setText(R.string.dfu_status_uploading); + } + break; + } + } + + private void showProgressBar() { + mProgressBar.setVisibility(View.VISIBLE); + mTextPercentage.setVisibility(View.VISIBLE); + mTextPercentage.setText(null); + mTextUploading.setText(R.string.dfu_status_uploading); + mTextUploading.setVisibility(View.VISIBLE); + mConnectButton.setEnabled(false); + mSelectFileButton.setEnabled(false); + mUploadButton.setEnabled(true); + mUploadButton.setText(R.string.dfu_action_upload_cancel); + } + + private void onTransferCompleted() { + clearUI(true); + showToast(R.string.dfu_success); + } + + public void onUploadCanceled() { + clearUI(false); + showToast(R.string.dfu_aborted); + } + + @Override + public void onCancelUpload() { + mProgressBar.setIndeterminate(true); + mTextUploading.setText(R.string.dfu_status_aborting); + mTextPercentage.setText(null); + } + + private void showErrorMessage(final int code) { + clearUI(false); + showToast("Upload failed: " + GattError.parse(code) + " (" + (code & ~(DfuService.ERROR_MASK | DfuService.ERROR_REMOTE_MASK)) + ")"); + } + + private void clearUI(final boolean clearDevice) { + mProgressBar.setVisibility(View.INVISIBLE); + mTextPercentage.setVisibility(View.INVISIBLE); + mTextUploading.setVisibility(View.INVISIBLE); + mConnectButton.setEnabled(true); + mSelectFileButton.setEnabled(true); + mUploadButton.setEnabled(false); + mUploadButton.setText(R.string.dfu_action_upload); + if (clearDevice) { + mSelectedDevice = null; + mDeviceNameView.setText(R.string.dfu_default_name); + } + // Application may have lost the right to these files if Activity was closed during upload (grant uri permission). Clear file related values. + mFileNameView.setText(null); + mFileTypeView.setText(null); + mFileSizeView.setText(null); + mFileStatusView.setText(R.string.dfu_file_status_no_file); + mFilePath = null; + mFileStreamUri = null; + mInitFilePath = null; + mInitFileStreamUri = null; + mStatusOk = false; + } + + private void showToast(final int messageResId) { + Toast.makeText(this, messageResId, Toast.LENGTH_SHORT).show(); + } + + private void showToast(final String message) { + Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); + } + + private boolean isDfuServiceRunning() { + ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); + for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if (DfuService.class.getName().equals(service.service.getClassName())) { + return true; + } + } + return false; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuInitiatorActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuInitiatorActivity.java new file mode 100644 index 00000000..7f222b77 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuInitiatorActivity.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.dfu; + +import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; +import android.app.Activity; +import android.bluetooth.BluetoothDevice; +import android.content.Intent; +import android.os.Bundle; + +/** + * The activity is started only by a remote connected computer using ADB. It shows a list of DFU-supported devices in range and allows user to select target device. The HEX file will be uploaded to + * selected device using {@link DfuService}. + */ +public class DfuInitiatorActivity extends Activity implements ScannerFragment.OnDeviceSelectedListener { + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // The activity must be started with a path to the HEX file + final Intent intent = getIntent(); + if (!intent.hasExtra(DfuService.EXTRA_FILE_PATH)) + finish(); + + if (savedInstanceState == null) { + final ScannerFragment fragment = ScannerFragment.getInstance(this, null, false); // Device that is advertising directly does not have the GENERAL_DISCOVERABLE nor LIMITED_DISCOVERABLE flag set. + fragment.show(getFragmentManager(), null); + } + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + final Intent intent = getIntent(); + final String overwrittenName = intent.getStringExtra(DfuService.EXTRA_DEVICE_NAME); + final String path = intent.getStringExtra(DfuService.EXTRA_FILE_PATH); + final String initPath = intent.getStringExtra(DfuService.EXTRA_INIT_FILE_PATH); + final String address = device.getAddress(); + final String finalName = overwrittenName == null ? name : overwrittenName; + final int type = intent.getIntExtra(DfuService.EXTRA_FILE_TYPE, DfuService.TYPE_AUTO); + + // Start DFU service with data provided in the intent + final Intent service = new Intent(this, DfuService.class); + service.putExtra(DfuService.EXTRA_DEVICE_ADDRESS, address); + service.putExtra(DfuService.EXTRA_DEVICE_NAME, finalName); + service.putExtra(DfuService.EXTRA_FILE_TYPE, type); + service.putExtra(DfuService.EXTRA_FILE_PATH, path); + if (intent.hasExtra(DfuService.EXTRA_INIT_FILE_PATH)) + service.putExtra(DfuService.EXTRA_INIT_FILE_PATH, initPath); + startService(service); + finish(); + } + + @Override + public void onDialogCanceled() { + finish(); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuService.java new file mode 100644 index 00000000..b569a967 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuService.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.dfu; + +import no.nordicsemi.android.dfu.DfuBaseService; +import android.app.Activity; + +public class DfuService extends DfuBaseService { + + @Override + protected Class getNotificationTarget() { + /* + * As a target activity the NotificationActivity is returned, not the MainActivity. This is because the notification must create a new task: + * + * intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + * + * when user press it. Using NotificationActivity we can check whether the new activity is a root activity (that means no other activity was open before) + * or that there is other activity already open. In the later case the notificationActivity will just be closed. System will restore the previous activity. + * However if the application has been closed during upload and user click the notification a NotificationActivity will be launched as a root activity. + * It will create and start the main activity and terminate itself. + * + * This method may be used to restore the target activity in case the application was closed or is open. It may also be used to recreate an activity + * history (see NotificationActivity). + */ + return NotificationActivity.class; + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/NotificationActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/NotificationActivity.java new file mode 100644 index 00000000..c6034710 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/NotificationActivity.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.dfu; + +import no.nordicsemi.android.nrftoolbox.FeaturesActivity; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +public class NotificationActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // If this activity is the root activity of the task, the app is not running + if (isTaskRoot()) { + // Start the app before finishing + final Intent parentIntent = new Intent(this, FeaturesActivity.class); + parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final Intent startAppIntent = new Intent(this, DfuActivity.class); + startAppIntent.putExtras(getIntent().getExtras()); + startActivities(new Intent[] { parentIntent, startAppIntent }); + } + + // Now finish, which will drop the user in to the activity that was at the top + // of the task stack + finish(); + } +} \ No newline at end of file diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/adapter/FileBrowserAppsAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/adapter/FileBrowserAppsAdapter.java new file mode 100644 index 00000000..cfe2fba3 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/adapter/FileBrowserAppsAdapter.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.dfu.adapter; + +import no.nordicsemi.android.nrftoolbox.R; +import android.content.Context; +import android.content.res.Resources; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.TextView; + +/** + * This adapter displays some file browser applications that can be used to select HEX file. It is used when there is no such app already installed on the device. The hardcoded apps and Google Play + * URLs are specified in res/values/strings_dfu.xml. + */ +public class FileBrowserAppsAdapter extends BaseAdapter { + private final LayoutInflater mInflater; + private final Resources mResources; + + public FileBrowserAppsAdapter(final Context context) { + mInflater = LayoutInflater.from(context); + mResources = context.getResources(); + } + + @Override + public int getCount() { + return mResources.getStringArray(R.array.dfu_app_file_browser).length; + } + + @Override + public Object getItem(int position) { + return mResources.getStringArray(R.array.dfu_app_file_browser_action)[position]; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = convertView; + if (view == null) { + view = mInflater.inflate(R.layout.app_file_browser_item, parent, false); + } + + final TextView item = (TextView) view; + item.setText(mResources.getStringArray(R.array.dfu_app_file_browser)[position]); + item.getCompoundDrawablesRelative()[0].setLevel(position); + return view; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/UploadCancelFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/UploadCancelFragment.java new file mode 100644 index 00000000..3f653189 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/UploadCancelFragment.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.dfu.fragment; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.dfu.DfuService; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + +/** + * When cancel button is pressed during uploading this fragment shows uploading cancel dialog + */ +public class UploadCancelFragment extends DialogFragment { + private static final String TAG = "UploadCancelFragment"; + + private CancelFragmentListener mListener; + + public interface CancelFragmentListener { + public void onCancelUpload(); + } + + public static UploadCancelFragment getInstance() { + return new UploadCancelFragment(); + } + + @Override + public void onAttach(final Activity activity) { + super.onAttach(activity); + + try { + mListener = (CancelFragmentListener) activity; + } catch (final ClassCastException e) { + Log.d(TAG, "The parent Activity must implement CancelFragmentListener interface"); + } + } + + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()).setTitle(R.string.dfu_confirmation_dialog_title).setMessage(R.string.dfu_upload_dialog_cancel_message).setCancelable(false) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int whichButton) { + final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity()); + final Intent pauseAction = new Intent(DfuService.BROADCAST_ACTION); + pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_ABORT); + manager.sendBroadcast(pauseAction); + + mListener.onCancelUpload(); + } + }).setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(final DialogInterface dialog, final int which) { + dialog.cancel(); + } + }).create(); + } + + @Override + public void onCancel(final DialogInterface dialog) { + final LocalBroadcastManager manager = LocalBroadcastManager.getInstance(getActivity()); + final Intent pauseAction = new Intent(DfuService.BROADCAST_ACTION); + pauseAction.putExtra(DfuService.EXTRA_ACTION, DfuService.ACTION_RESUME); + manager.sendBroadcast(pauseAction); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/ZipInfoFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/ZipInfoFragment.java new file mode 100644 index 00000000..e3b6a3ec --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/ZipInfoFragment.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.dfu.fragment; + +import no.nordicsemi.android.nrftoolbox.R; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +public class ZipInfoFragment extends DialogFragment { + + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + final View view = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_zip_info, null); + return new AlertDialog.Builder(getActivity()).setView(view).setTitle(R.string.dfu_file_info).setPositiveButton(R.string.ok, null).create(); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/AboutDfuPreference.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/AboutDfuPreference.java new file mode 100644 index 00000000..6c818965 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/AboutDfuPreference.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.dfu.settings; + +import no.nordicsemi.android.nrftoolbox.R; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.preference.Preference; +import android.util.AttributeSet; +import android.widget.Toast; + +public class AboutDfuPreference extends Preference { + + public AboutDfuPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public AboutDfuPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onClick() { + final Context context = getContext(); + final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://developer.nordicsemi.com/nRF51_SDK/doc/7.1.0/s110/html/a00062.html")); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + // is browser installed? + if (intent.resolveActivity(context.getPackageManager()) != null) + context.startActivity(intent); + else { + Toast.makeText(getContext(), R.string.no_application, Toast.LENGTH_LONG).show(); + } + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsActivity.java new file mode 100644 index 00000000..e9614fc7 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsActivity.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.dfu.settings; + +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.view.MenuItem; + +public class SettingsActivity extends ActionBarActivity { + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + // Display the fragment as the main content. + getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit(); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsFragment.java new file mode 100644 index 00000000..c98d191c --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsFragment.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.dfu.settings; + +import no.nordicsemi.android.dfu.DfuSettingsConstants; +import no.nordicsemi.android.nrftoolbox.R; +import android.app.AlertDialog; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceFragment; +import android.preference.PreferenceScreen; + +public class SettingsFragment extends PreferenceFragment implements DfuSettingsConstants, SharedPreferences.OnSharedPreferenceChangeListener { + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.settings_dfu); + + // set initial values + updateNumberOfPacketsSummary(); + updateMBRSize(); + } + + @Override + public void onResume() { + super.onResume(); + + // attach the preference change listener. It will update the summary below interval preference + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); + } + + @Override + public void onPause() { + super.onPause(); + + // unregister listener + getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); + } + + @Override + public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { + final SharedPreferences preferences = getPreferenceManager().getSharedPreferences(); + + if (SETTINGS_PACKET_RECEIPT_NOTIFICATION_ENABLED.equals(key)) { + final boolean disabled = !preferences.getBoolean(SETTINGS_PACKET_RECEIPT_NOTIFICATION_ENABLED, true); + if (disabled) { + new AlertDialog.Builder(getActivity()).setMessage(R.string.dfu_settings_dfu_number_of_packets_info).setTitle(R.string.dfu_settings_dfu_information) + .setNeutralButton(R.string.ok, null).show(); + } + } else if (SETTINGS_NUMBER_OF_PACKETS.equals(key)) { + updateNumberOfPacketsSummary(); + } else if (SETTINGS_MBR_SIZE.equals(key)) { + updateMBRSize(); + } + } + + private void updateNumberOfPacketsSummary() { + final PreferenceScreen screen = getPreferenceScreen(); + final SharedPreferences preferences = getPreferenceManager().getSharedPreferences(); + + final String value = preferences.getString(SETTINGS_NUMBER_OF_PACKETS, String.valueOf(SETTINGS_NUMBER_OF_PACKETS_DEFAULT)); + screen.findPreference(SETTINGS_NUMBER_OF_PACKETS).setSummary(value); + + final int valueInt = Integer.parseInt(value); + if (valueInt > 200) { + new AlertDialog.Builder(getActivity()).setMessage(R.string.dfu_settings_dfu_number_of_packets_info).setTitle(R.string.dfu_settings_dfu_information) + .setNeutralButton(R.string.ok, null) + .show(); + } + } + + private void updateMBRSize() { + final PreferenceScreen screen = getPreferenceScreen(); + final SharedPreferences preferences = getPreferenceManager().getSharedPreferences(); + + final String value = preferences.getString(SETTINGS_MBR_SIZE, String.valueOf(SETTINGS_DEFAULT_MBR_SIZE)); + screen.findPreference(SETTINGS_MBR_SIZE).setSummary(value); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/ExpandableRecordAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/ExpandableRecordAdapter.java new file mode 100644 index 00000000..a4bc807d --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/ExpandableRecordAdapter.java @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.gls; + +import no.nordicsemi.android.nrftoolbox.R; +import android.content.Context; +import android.content.res.Resources; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseExpandableListAdapter; +import android.widget.TextView; + +public class ExpandableRecordAdapter extends BaseExpandableListAdapter { + private final GlucoseManager mGlucoseManager; + private final LayoutInflater mInflater; + private final Context mContext; + + public ExpandableRecordAdapter(final Context context, final GlucoseManager manager) { + mGlucoseManager = manager; + mContext = context; + mInflater = LayoutInflater.from(context); + } + + @Override + public int getGroupCount() { + return mGlucoseManager.getRecords().size(); + } + + @Override + public Object getGroup(int groupPosition) { + return mGlucoseManager.getRecords().valueAt(groupPosition); + } + + @Override + public long getGroupId(final int groupPosition) { + return mGlucoseManager.getRecords().keyAt(groupPosition); + } + + @Override + public View getGroupView(final int position, boolean isExpanded, final View convertView, final ViewGroup parent) { + View view = convertView; + if (view == null) { + view = mInflater.inflate(R.layout.activity_feature_gls_item, parent, false); + + final GroupViewHolder holder = new GroupViewHolder(); + holder.time = (TextView) view.findViewById(R.id.time); + holder.details = (TextView) view.findViewById(R.id.details); + holder.concentration = (TextView) view.findViewById(R.id.gls_concentration); + view.setTag(holder); + } + final GlucoseRecord record = (GlucoseRecord) getGroup(position); + if (record == null) + return view; // this may happen during closing the activity + final GroupViewHolder holder = (GroupViewHolder) view.getTag(); + holder.time.setText(mContext.getString(R.string.gls_timestamp, record.time)); + try { + holder.details.setText(mContext.getResources().getStringArray(R.array.gls_type)[record.type]); + } catch (final ArrayIndexOutOfBoundsException e) { + holder.details.setText(mContext.getResources().getStringArray(R.array.gls_type)[0]); + } + if (record.unit == GlucoseRecord.UNIT_kgpl) { + holder.concentration.setText(mContext.getString(R.string.gls_value, record.glucoseConcentration * 100000.0f)); + } else { + holder.concentration.setText(mContext.getString(R.string.gls_value, record.glucoseConcentration * 1000.0f)); + } + return view; + } + + @Override + public int getChildrenCount(final int groupPosition) { + final GlucoseRecord record = (GlucoseRecord) getGroup(groupPosition); + int count = 1 + (record.status != 0 ? 1 : 0); // Sample Location and Sensor Status Annunciation + if (record.context != null) { + final GlucoseRecord.MeasurementContext context = record.context; + if (context.carbohydrateId != 0) + count += 1; // Carbohydrate ID and units + if (context.meal != 0) + count += 1; // Meal + if (context.tester != 0) + count += 1; // Tester + if (context.health != 0) + count += 1; // Health + if (context.exerciseDuration != 0) + count += 1; // Duration and intensity + if (context.medicationId != 0) + count += 1; // Medication ID and quantity (with unit) + if (context.HbA1c != 0) + count += 1; // HbA1c + } + return count; + } + + @Override + public Object getChild(final int groupPosition, final int childPosition) { + final Resources resources = mContext.getResources(); + final GlucoseRecord record = (GlucoseRecord) getGroup(groupPosition); + switch (childPosition) { + case 0: + String location = null; + try { + location = resources.getStringArray(R.array.gls_location)[record.sampleLocation]; + } catch (final ArrayIndexOutOfBoundsException e) { + location = resources.getStringArray(R.array.gls_location)[0]; + } + return new Pair<>(resources.getString(R.string.gls_location_title), location); + case 1: { // sensor status annunciation + final StringBuilder builder = new StringBuilder(); + final int status = record.status; + for (int i = 0; i < 12; ++i) + if ((status & (1 << i)) > 0) + builder.append(resources.getStringArray(R.array.gls_status_annunciatioin)[i]).append("\n"); + builder.setLength(builder.length() - 1); + return new Pair<>(resources.getString(R.string.gls_status_annunciatioin_title), builder.toString()); + } + case 2: { // carbohydrate id and unit + final StringBuilder builder = new StringBuilder(); + builder.append(resources.getStringArray(R.array.gls_context_carbohydrare)[record.context.carbohydrateId]).append(" (" + record.context.carbohydrateUnits + " kg)"); + return new Pair<>(resources.getString(R.string.gls_context_carbohydrare_title), builder.toString()); + } + case 3: { // meal + final StringBuilder builder = new StringBuilder(); + builder.append(resources.getStringArray(R.array.gls_context_meal)[record.context.meal]); + return new Pair<>(resources.getString(R.string.gls_context_meal_title), builder.toString()); + } + case 4: { // tester + final StringBuilder builder = new StringBuilder(); + builder.append(resources.getStringArray(R.array.gls_context_tester)[record.context.tester]); + return new Pair<>(resources.getString(R.string.gls_context_tester_title), builder.toString()); + } + case 5: { // health + final StringBuilder builder = new StringBuilder(); + builder.append(resources.getStringArray(R.array.gls_context_health)[record.context.health]); + return new Pair<>(resources.getString(R.string.gls_context_health_title), builder.toString()); + } + default: + // TODO write parsers for other properties + return new Pair<>("Not implemented", "The value exists but is not shown"); + } + } + + @Override + public long getChildId(final int groupPosition, final int childPosition) { + return groupPosition + childPosition; + } + + @SuppressWarnings("unchecked") + @Override + public View getChildView(final int groupPosition, final int childPosition, final boolean isLastChild, final View convertView, final ViewGroup parent) { + View view = convertView; + if (view == null) { + view = mInflater.inflate(R.layout.activity_feature_gls_subitem, parent, false); + final ChildViewHolder holder = new ChildViewHolder(); + holder.title = (TextView) view.findViewById(android.R.id.text1); + holder.details = (TextView) view.findViewById(android.R.id.text2); + view.setTag(holder); + } + final Pair value = (Pair) getChild(groupPosition, childPosition); + final ChildViewHolder holder = (ChildViewHolder) view.getTag(); + holder.title.setText(value.first); + holder.details.setText(value.second); + return view; + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public boolean isChildSelectable(final int groupPosition, final int childPosition) { + return false; + } + + private class GroupViewHolder { + private TextView time; + private TextView details; + private TextView concentration; + } + + private class ChildViewHolder { + private TextView title; + private TextView details; + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java new file mode 100644 index 00000000..0021b194 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.gls; + +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileExpandableListActivity; +import android.os.Bundle; +import android.util.SparseArray; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.BaseExpandableListAdapter; +import android.widget.PopupMenu; +import android.widget.TextView; + +public class GlucoseActivity extends BleProfileExpandableListActivity implements PopupMenu.OnMenuItemClickListener, GlucoseManagerCallbacks { + @SuppressWarnings("unused") + private static final String TAG = "GlucoseActivity"; + + private BaseExpandableListAdapter mAdapter; + private GlucoseManager mGlucoseManager; + + private View mControlPanelStd; + private View mControlPanelAbort; + private TextView mUnitView; + + @Override + protected void onCreateView(final Bundle savedInstanceState) { + // FEATURE_INDETERMINATE_PROGRESS notifies the system, that we are going to show indeterminate progress bar in the ActionBar (during device scan) + // requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); // <- Deprecated + setContentView(R.layout.activity_feature_gls); + setGUI(); + } + + private void setGUI() { + mUnitView = (TextView) findViewById(R.id.unit); + mControlPanelStd = findViewById(R.id.gls_control_std); + mControlPanelAbort = findViewById(R.id.gls_control_abort); + + findViewById(R.id.action_last).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mGlucoseManager.getLastRecord(); + } + }); + findViewById(R.id.action_all).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mGlucoseManager.getAllRecords(); + } + }); + findViewById(R.id.action_abort).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mGlucoseManager.abort(); + } + }); + + // create popup menu attached to the button More + findViewById(R.id.action_more).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + PopupMenu menu = new PopupMenu(GlucoseActivity.this, v); + menu.setOnMenuItemClickListener(GlucoseActivity.this); + MenuInflater inflater = menu.getMenuInflater(); + inflater.inflate(R.menu.gls_more, menu.getMenu()); + menu.show(); + } + }); + + setListAdapter(mAdapter = new ExpandableRecordAdapter(this, mGlucoseManager)); + } + + @Override + protected BleManager initializeManager() { + GlucoseManager manager = mGlucoseManager = GlucoseManager.getGlucoseManager(); + manager.setGattCallbacks(this); + return manager; + } + + @Override + public boolean onMenuItemClick(final MenuItem item) { + switch (item.getItemId()) { + case R.id.action_refresh: + mGlucoseManager.refreshRecords(); + break; + case R.id.action_first: + mGlucoseManager.getFirstRecord(); + break; + case R.id.action_clear: + mGlucoseManager.clear(); + break; + case R.id.action_delete_all: + mGlucoseManager.deleteAllRecords(); + break; + } + return true; + } + + @Override + protected int getAboutTextId() { + return R.string.gls_about_text; + } + + @Override + protected int getDefaultDeviceName() { + return R.string.gls_default_name; + } + + @Override + protected UUID getFilterUUID() { + return GlucoseManager.GLS_SERVICE_UUID; + } + + @Override + protected void setDefaultUI() { + mGlucoseManager.clear(); + } + + private void setOperationInProgress(final boolean progress) { + runOnUiThread(new Runnable() { + @Override + public void run() { + // setSupportProgressBarIndeterminateVisibility(progress); + mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE); + mControlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE); + } + }); + } + + @Override + public void onServicesDiscovered(boolean optionalServicesFound) { + // this may notify user or show some views + } + + @Override + public void onGlucoseMeasurementNotificationEnabled() { + // this may notify user or show some views + } + + @Override + public void onGlucoseMeasurementContextNotificationEnabled() { + // this may notify user or show some views + } + + @Override + public void onRecordAccessControlPointIndicationsEnabled() { + // this may notify user or show some views + } + + @Override + public void onOperationStarted() { + setOperationInProgress(true); + } + + @Override + public void onOperationCompleted() { + setOperationInProgress(false); + } + + @Override + public void onOperationAborted() { + setOperationInProgress(false); + } + + @Override + public void onOperationNotSupported() { + setOperationInProgress(false); + showToast(R.string.gls_operation_not_supported); + } + + @Override + public void onOperationFailed() { + setOperationInProgress(false); + showToast(R.string.gls_operation_failed); + } + + @Override + public void onDatasetChanged() { + runOnUiThread(new Runnable() { + @Override + public void run() { + final SparseArray records = mGlucoseManager.getRecords(); + if (records.size() > 0) { + final int unit = records.valueAt(0).unit; + mUnitView.setVisibility(View.VISIBLE); + mUnitView.setText(unit == GlucoseRecord.UNIT_kgpl ? R.string.gls_unit_mgpdl : R.string.gls_unit_mmolpl); + } else + mUnitView.setVisibility(View.GONE); + + mAdapter.notifyDataSetChanged(); + } + }); + } + + @Override + public void onNumberOfRecordsRequested(final int value) { + showToast(getString(R.string.gls_progress, value)); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java new file mode 100644 index 00000000..a734e845 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java @@ -0,0 +1,698 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.gls; + +import java.util.Calendar; +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothProfile; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.util.SparseArray; + +@SuppressWarnings("unused") +public class GlucoseManager implements BleManager { + private static final String TAG = "GlucoseManager"; + + private GlucoseManagerCallbacks mCallbacks; + private BluetoothGatt mBluetoothGatt; + private Context mContext; + private Handler mHandler; + private boolean mAbort; + + private final SparseArray mRecords = new SparseArray<>(); + + public final static UUID GLS_SERVICE_UUID = UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"); + public final static UUID BATTERY_SERVICE = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); + /** Glucose Measurement characteristic */ + private final static UUID GM_CHARACTERISTIC = UUID.fromString("00002A18-0000-1000-8000-00805f9b34fb"); + /** Glucose Measurement Context characteristic */ + private final static UUID GM_CONTEXT_CHARACTERISTIC = UUID.fromString("00002A34-0000-1000-8000-00805f9b34fb"); + /** Glucose Feature characteristic */ + private final static UUID GF_CHARACTERISTIC = UUID.fromString("00002A51-0000-1000-8000-00805f9b34fb"); + /** Record Access Control Point characteristic */ + private final static UUID RACP_CHARACTERISTIC = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb"); + /** Battery Level characteristic */ + private final static UUID BATTERY_LEVEL_CHARACTERISTIC = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); + /** Client configuration descriptor that will allow us to enable notifications and indications */ + private static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + + private final static int OP_CODE_REPORT_STORED_RECORDS = 1; + private final static int OP_CODE_DELETE_STORED_RECORDS = 2; + private final static int OP_CODE_ABORT_OPERATION = 3; + private final static int OP_CODE_REPORT_NUMBER_OF_RECORDS = 4; + private final static int OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE = 5; + private final static int OP_CODE_RESPONSE_CODE = 6; + + private final static int OPERATOR_NULL = 0; + private final static int OPERATOR_ALL_RECORDS = 1; + private final static int OPERATOR_LESS_THEN_OR_EQUAL = 2; + private final static int OPERATOR_GREATER_THEN_OR_EQUAL = 3; + private final static int OPERATOR_WITHING_RANGE = 4; + private final static int OPERATOR_FIRST_RECORD = 5; + private final static int OPERATOR_LAST_RECORD = 6; + + /** + * The filter type is used for range operators ({@link #OPERATOR_LESS_THEN_OR_EQUAL}, {@link #OPERATOR_GREATER_THEN_OR_EQUAL}, {@link #OPERATOR_WITHING_RANGE}.
+ * The syntax of the operand is: [Filter Type][Minimum][Maximum].
+ * This filter selects the records by the sequence number. + */ + private final static int FILTER_TYPE_SEQUENCE_NUMBER = 1; + /** + * The filter type is used for range operators ({@link #OPERATOR_LESS_THEN_OR_EQUAL}, {@link #OPERATOR_GREATER_THEN_OR_EQUAL}, {@link #OPERATOR_WITHING_RANGE}.
+ * The syntax of the operand is: [Filter Type][Minimum][Maximum].
+ * This filter selects the records by the user facing time (base time + offset time). + */ + private final static int FILTER_TYPE_USER_FACING_TIME = 2; + + private final static int RESPONSE_SUCCESS = 1; + private final static int RESPONSE_OP_CODE_NOT_SUPPORTED = 2; + private final static int RESPONSE_INVALID_OPERATOR = 3; + private final static int RESPONSE_OPERATOR_NOT_SUPPORTED = 4; + private final static int RESPONSE_INVALID_OPERAND = 5; + private final static int RESPONSE_NO_RECORDS_FOUND = 6; + private final static int RESPONSE_ABORT_UNSUCCESSFUL = 7; + private final static int RESPONSE_PROCEDURE_NOT_COMPLETED = 8; + private final static int RESPONSE_OPERAND_NOT_SUPPORTED = 9; + + private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change"; + private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services"; + private final static String ERROR_WRITE_DESCRIPTOR = "Error on writing descriptor"; + private final static String ERROR_WRITE_CHARACTERISTIC = "Error on writing characteristic"; + private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information"; + + private BluetoothGattCharacteristic mGlucoseMeasurementCharacteristic; + private BluetoothGattCharacteristic mGlucoseFeatureCharacteristic; + private BluetoothGattCharacteristic mGlucoseMeasurementContextCharacteristic; + private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic; + private BluetoothGattCharacteristic mBatteryLevelCharacteristic; + + private static GlucoseManager mInstance; + + /** + * Returns the singleton implementation of GlucoseManager + */ + public static GlucoseManager getGlucoseManager() { + if (mInstance == null) + mInstance = new GlucoseManager(); + return mInstance; + } + + /** + * Callbacks for activity {@link GlucoseActivity} that implements {@link GlucoseManagerCallbacks} interface activity use this method to register itself for receiving callbacks + */ + @Override + public void setGattCallbacks(final GlucoseManagerCallbacks callbacks) { + mCallbacks = callbacks; + } + + /** + * Returns all records as a sparse array where sequence number is the key. + * + * @return the records list + */ + public SparseArray getRecords() { + return mRecords; + } + + @Override + public void connect(final Context context, final BluetoothDevice device) { + if (mHandler == null) + mHandler = new Handler(); + mContext = context; + + // Register bonding broadcast receiver + final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + context.registerReceiver(mBondingBroadcastReceiver, filter); + + mBluetoothGatt = device.connectGatt(context, false, mGattCallback); + } + + /** + * Disable HR notification first and then disconnect to HR device + */ + @Override + public void disconnect() { + if (mBluetoothGatt != null) { + mBluetoothGatt.disconnect(); + } + } + + /** + * Clears the records list locally + */ + public void clear() { + mRecords.clear(); + mCallbacks.onDatasetChanged(); + } + + /** + * Sends the request to obtain the last (most recent) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access + * Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of error. + */ + public void getLastRecord() { + if (mBluetoothGatt == null || mRecordAccessControlPointCharacteristic == null) + return; + + clear(); + mCallbacks.onOperationStarted(); + + final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic; + setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_LAST_RECORD); + mBluetoothGatt.writeCharacteristic(characteristic); + } + + /** + * Sends the request to obtain the first (oldest) record from glucose device. The data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control + * Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of error. + */ + public void getFirstRecord() { + if (mBluetoothGatt == null || mRecordAccessControlPointCharacteristic == null) + return; + + clear(); + mCallbacks.onOperationStarted(); + + final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic; + setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_FIRST_RECORD); + mBluetoothGatt.writeCharacteristic(characteristic); + } + + /** + * Sends the request to obtain all records from glucose device. Initially we want to notify him/her about the number of the records so the {@link #OP_CODE_REPORT_NUMBER_OF_RECORDS} is send. The + * data will be returned to Glucose Measurement characteristic as a notification followed by Record Access Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of + * error. + */ + public void getAllRecords() { + if (mBluetoothGatt == null || mRecordAccessControlPointCharacteristic == null) + return; + + clear(); + mCallbacks.onOperationStarted(); + + final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic; + setOpCode(characteristic, OP_CODE_REPORT_NUMBER_OF_RECORDS, OPERATOR_ALL_RECORDS); + mBluetoothGatt.writeCharacteristic(characteristic); + } + + /** + * Sends the request to obtain from the glucose device all records newer than the newest one from local storage. The data will be returned to Glucose Measurement characteristic as a notification + * followed by Record Access Control Point indication with status code ({@link #RESPONSE_SUCCESS} or other in case of error. + *

+ * Refresh button will not download records older than the oldest in the local memory. F.e. if you have pressed Last and then Refresh, than it will try to get only newer records. However if there + * are no records, it will download all existing (using {@link #getAllRecords()}). + *

+ */ + public void refreshRecords() { + if (mBluetoothGatt == null || mRecordAccessControlPointCharacteristic == null) + return; + + if (mRecords.size() == 0) { + getAllRecords(); + } else { + mCallbacks.onOperationStarted(); + + // obtain the last sequence number + final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1; + + final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic; + setOpCode(characteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_GREATER_THEN_OR_EQUAL, sequenceNumber); + mBluetoothGatt.writeCharacteristic(characteristic); + // Info: + // Operators OPERATOR_LESS_THEN_OR_EQUAL and OPERATOR_RANGE are not supported by Nordic Semiconductor Glucose Service in SDK 4.4.2. + } + } + + /** + * Sends abort operation signal to the device + */ + public void abort() { + if (mBluetoothGatt == null || mRecordAccessControlPointCharacteristic == null) + return; + + mAbort = true; + final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic; + setOpCode(characteristic, OP_CODE_ABORT_OPERATION, OPERATOR_NULL); + mBluetoothGatt.writeCharacteristic(characteristic); + } + + /** + * Sends the request to delete all data from the device. A Record Access Control Point indication with status code ({@link #RESPONSE_SUCCESS} (or other in case of error) will be send. + * + * @FIXME This method is not supported by Nordic Semiconductor Glucose Service in SDK 4.4.2. + */ + public void deleteAllRecords() { + if (mBluetoothGatt == null || mRecordAccessControlPointCharacteristic == null) + return; + + clear(); + mCallbacks.onOperationStarted(); + + final BluetoothGattCharacteristic characteristic = mRecordAccessControlPointCharacteristic; + setOpCode(characteristic, OP_CODE_DELETE_STORED_RECORDS, OPERATOR_ALL_RECORDS); + mBluetoothGatt.writeCharacteristic(characteristic); + } + + private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); + final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1); + + DebugLogger.d(TAG, "Bond state changed for: " + device.getAddress() + " new state: " + bondState + " previous: " + previousBondState); + + // skip other devices + if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) + return; + + if (bondState == BluetoothDevice.BOND_BONDING) { + mCallbacks.onBondingRequired(); + } else if (bondState == BluetoothDevice.BOND_BONDED) { + // We've read Battery Level, now let'so enable notifications and indication + enableGlucoseMeasurementNotification(mBluetoothGatt); + mCallbacks.onBonded(); + } + } + }; + + /** + * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving notification, etc + */ + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + mCallbacks.onDeviceConnected(); + // start discovering services + gatt.discoverServices(); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + mCallbacks.onDeviceDisconnected(); + gatt.close(); + } + } else { + DebugLogger.e(TAG, "onConnectionStateChange error " + status); + mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status); + } + } + + @Override + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + for (BluetoothGattService service : gatt.getServices()) { + if (GLS_SERVICE_UUID.equals(service.getUuid())) { + mGlucoseMeasurementCharacteristic = service.getCharacteristic(GM_CHARACTERISTIC); + mGlucoseMeasurementContextCharacteristic = service.getCharacteristic(GM_CONTEXT_CHARACTERISTIC); + mGlucoseFeatureCharacteristic = service.getCharacteristic(GF_CHARACTERISTIC); + mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_CHARACTERISTIC); + } else if (BATTERY_SERVICE.equals(service.getUuid())) { + mBatteryLevelCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC); + } + } + // Validate the device for required characteristics + if (mGlucoseMeasurementCharacteristic == null || mRecordAccessControlPointCharacteristic == null) { + mCallbacks.onDeviceNotSupported(); + gatt.disconnect(); + return; + } + mCallbacks.onServicesDiscovered(mGlucoseMeasurementContextCharacteristic != null); + + // We have discovered services, let's start notifications and indications, one by one: read battery, enable GM, GMP (if exists) and RACP + if (mBatteryLevelCharacteristic != null) { + readBatteryLevel(gatt); + } else { + // this characteristic is mandatory + enableGlucoseMeasurementNotification(gatt); + } + } else { + DebugLogger.e(TAG, "onServicesDiscovered error " + status); + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (BATTERY_LEVEL_CHARACTERISTIC.equals(characteristic.getUuid())) { + final int batteryValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0); + mCallbacks.onBatteryValueReceived(batteryValue); + + // We've read Battery Level, now let'so enable ICP notifications or BPM indications + enableGlucoseMeasurementNotification(gatt); + } + } else { + DebugLogger.e(TAG, "onCharacteristicRead error " + status); + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (GM_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) { + mCallbacks.onGlucoseMeasurementNotificationEnabled(); + + if (mGlucoseMeasurementContextCharacteristic != null) { + enableGlucoseMeasurementContextNotification(gatt); + } else { + enableRecordAccessControlPointIndication(gatt); + } + } + + if (GM_CONTEXT_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) { + mCallbacks.onGlucoseMeasurementContextNotificationEnabled(); + enableRecordAccessControlPointIndication(gatt); + } + + if (RACP_CHARACTERISTIC.equals(descriptor.getCharacteristic().getUuid())) { + mCallbacks.onRecordAccessControlPointIndicationsEnabled(); + } + } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { + if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { + DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); + mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status); + } + } else { + DebugLogger.e(TAG, "onDescriptorWrite error " + status); + mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status); + } + } + + @Override + public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { + final UUID uuid = characteristic.getUuid(); + if (GM_CHARACTERISTIC.equals(uuid)) { + int offset = 0; + final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + offset += 1; + + final boolean timeOffsetPresent = (flags & 0x01) > 0; + final boolean typeAndLocationPresent = (flags & 0x02) > 0; + final int concentrationUnit = (flags & 0x04) > 0 ? GlucoseRecord.UNIT_molpl : GlucoseRecord.UNIT_kgpl; + final boolean sensorStatusAnnunciationPresent = (flags & 0x08) > 0; + final boolean contextInfoFollows = (flags & 0x10) > 0; + + // create and fill the new record + final GlucoseRecord record = new GlucoseRecord(); + record.sequenceNumber = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); + offset += 2; + + final int year = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); + final int month = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 2) + 1; // months are 1-based + final int day = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 3); + final int hours = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 4); + final int minutes = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 5); + final int seconds = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 6); + offset += 7; + + final Calendar calendar = Calendar.getInstance(); + calendar.set(year, month, day, hours, minutes, seconds); + record.time = calendar; + + if (timeOffsetPresent) { + // time offset is ignored in the current release + record.timeOffset = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16, offset); + offset += 2; + } + + if (typeAndLocationPresent) { + record.glucoseConcentration = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset); + record.unit = concentrationUnit; + final int typeAndLocation = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 2); + record.type = (typeAndLocation & 0xF0) >> 4; // TODO this way or around? + record.sampleLocation = (typeAndLocation & 0x0F); + offset += 3; + } + + if (sensorStatusAnnunciationPresent) { + record.status = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); + } + // This allows you to check other values that are not provided by the Nordic Semiconductor's Glucose Service in SDK 4.4.2. + // record.status = 0x1A; + // record.context = new GlucoseRecord.MeasurementContext(); + // record.context.carbohydrateId = 1; + // record.context.carbohydrateUnits = 0.23f; + // record.context.meal = 2; + // record.context.tester = 2; + // record.context.health = 4; + // the following values are not implemented yet (see ExpandableRecordAdapter#getChildrenCount() and #getChild(...) + // record.context.exerciseDuration = 3600; + // record.context.exerciseIntensity = 45; + // record.context.medicationId = 3; + // record.context.medicationQuantity = 0.03f; + // record.context.medicationUnit = GlucoseRecord.MeasurementContext.UNIT_kg; + // record.context.HbA1c = 213.3f; + + // data set modifications must be done in UI thread + mHandler.post(new Runnable() { + @Override + public void run() { + // insert the new record to storage + mRecords.put(record.sequenceNumber, record); + + // if there is no context information following the measurement data, notify callback about the new record + if (!contextInfoFollows) + mCallbacks.onDatasetChanged(); + } + }); + } else if (GM_CONTEXT_CHARACTERISTIC.equals(uuid)) { + int offset = 0; + final int flags = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + offset += 1; + + final boolean carbohydratePresent = (flags & 0x01) > 0; + final boolean mealPresent = (flags & 0x02) > 0; + final boolean testerHealthPresent = (flags & 0x04) > 0; + final boolean exercisePresent = (flags & 0x08) > 0; + final boolean medicationPresent = (flags & 0x10) > 0; + final int medicationUnit = (flags & 0x20) > 0 ? GlucoseRecord.MeasurementContext.UNIT_l : GlucoseRecord.MeasurementContext.UNIT_kg; + final boolean hbA1cPresent = (flags & 0x40) > 0; + final boolean moreFlagsPresent = (flags & 0x80) > 0; + + final int sequenceNumber = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); + offset += 2; + + final GlucoseRecord record = mRecords.get(sequenceNumber); + if (record == null) { + DebugLogger.w(TAG, "Context information with unknown sequence number: " + sequenceNumber); + return; + } + + final GlucoseRecord.MeasurementContext context = new GlucoseRecord.MeasurementContext(); + record.context = context; + + if (moreFlagsPresent) + offset += 1; + + if (carbohydratePresent) { + context.carbohydrateId = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + context.carbohydrateUnits = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset + 1); + offset += 3; + } + + if (mealPresent) { + context.meal = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + offset += 1; + } + + if (testerHealthPresent) { + final int testerHealth = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + context.tester = (testerHealth & 0xF0) >> 4; + context.health = (testerHealth & 0x0F); + offset += 1; + } + + if (exercisePresent) { + context.exerciseDuration = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); + context.exerciseIntensity = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 2); + offset += 3; + } + + if (medicationPresent) { + context.medicationId = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + context.medicationQuantity = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset + 1); + context.medicationUnit = medicationUnit; + offset += 3; + } + + if (hbA1cPresent) { + context.HbA1c = characteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, offset); + } + + // notify callback about the new record + mCallbacks.onDatasetChanged(); + } else { // Record Access Control Point characteristic + int offset = 0; + final int opCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + offset += 2; // skip the operator + + if (opCode == OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE) { + // We've obtained the number of all records + final int number = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); + + mCallbacks.onNumberOfRecordsRequested(number); + + // Request the records + final BluetoothGattCharacteristic racpCharacteristic = mRecordAccessControlPointCharacteristic; + setOpCode(racpCharacteristic, OP_CODE_REPORT_STORED_RECORDS, OPERATOR_ALL_RECORDS); + mBluetoothGatt.writeCharacteristic(racpCharacteristic); + } else if (opCode == OP_CODE_RESPONSE_CODE) { + final int requestedOpCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + final int responseCode = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset + 1); + DebugLogger.d(TAG, "Response result for: " + requestedOpCode + " is: " + responseCode); + + switch (responseCode) { + case RESPONSE_SUCCESS: + if (!mAbort) + mCallbacks.onOperationCompleted(); + else + mCallbacks.onOperationAborted(); + break; + case RESPONSE_NO_RECORDS_FOUND: + mCallbacks.onOperationCompleted(); + break; + case RESPONSE_OP_CODE_NOT_SUPPORTED: + mCallbacks.onOperationNotSupported(); + break; + case RESPONSE_PROCEDURE_NOT_COMPLETED: + case RESPONSE_ABORT_UNSUCCESSFUL: + default: + mCallbacks.onOperationFailed(); + break; + } + mAbort = false; + } + } + } + + /** + * Reads battery level on the device + */ + private void readBatteryLevel(final BluetoothGatt gatt) { + DebugLogger.d(TAG, "readBatteryLevel()"); + gatt.readCharacteristic(mBatteryLevelCharacteristic); + } + }; + + /** + * Enabling notification on Glucose Measurement Characteristic + */ + private void enableGlucoseMeasurementNotification(final BluetoothGatt gatt) { + DebugLogger.d(TAG, "enableGlucoseMeasurementNotification()"); + gatt.setCharacteristicNotification(mGlucoseMeasurementCharacteristic, true); + final BluetoothGattDescriptor descriptor = mGlucoseMeasurementCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + gatt.writeDescriptor(descriptor); + } + + /** + * Enabling notification on Glucose Measurement Context Characteristic. This characteristic is optional + */ + private void enableGlucoseMeasurementContextNotification(final BluetoothGatt gatt) { + DebugLogger.d(TAG, "enableGlucoseMeasurementContextNotification()"); + gatt.setCharacteristicNotification(mGlucoseMeasurementContextCharacteristic, true); + final BluetoothGattDescriptor descriptor = mGlucoseMeasurementContextCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + gatt.writeDescriptor(descriptor); + } + + /** + * Enabling indications on Record Access Control Point Characteristic + */ + private void enableRecordAccessControlPointIndication(final BluetoothGatt gatt) { + DebugLogger.d(TAG, "enableGlucoseMeasurementContextNotification()"); + gatt.setCharacteristicNotification(mRecordAccessControlPointCharacteristic, true); + final BluetoothGattDescriptor descriptor = mRecordAccessControlPointCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); + gatt.writeDescriptor(descriptor); + } + + /** + * Writes given operation parameters to the characteristic + * + * @param characteristic + * the characteristic to write. This must be the Record Access Control Point characteristic + * @param opCode + * the operation code + * @param operator + * the operator (see {@link #OPERATOR_NULL} and others + * @param params + * optional parameters (one for >=, <=, two for the range, none for other operators) + */ + private void setOpCode(final BluetoothGattCharacteristic characteristic, final int opCode, final int operator, final Integer... params) { + final int size = 2 + ((params.length > 0) ? 1 : 0) + params.length * 2; // 1 byte for opCode, 1 for operator, 1 for filter type (if parameters exists) and 2 for each parameter + characteristic.setValue(new byte[size]); + + // write the operation code + int offset = 0; + characteristic.setValue(opCode, BluetoothGattCharacteristic.FORMAT_UINT8, offset); + offset += 1; + + // write the operator. This is always present but may be equal to OPERATOR_NULL + characteristic.setValue(operator, BluetoothGattCharacteristic.FORMAT_UINT8, offset); + offset += 1; + + // if parameters exists, append them. Parameters should be sorted from minimum to maximum. Currently only one or two params are allowed + if (params.length > 0) { + // our implementation use only sequence number as a filer type + characteristic.setValue(FILTER_TYPE_SEQUENCE_NUMBER, BluetoothGattCharacteristic.FORMAT_UINT8, offset); + offset += 1; + + for (final Integer i : params) { + characteristic.setValue(i, BluetoothGattCharacteristic.FORMAT_UINT16, offset); + offset += 2; + } + } + } + + @Override + public void closeBluetoothGatt() { + try { + mContext.unregisterReceiver(mBondingBroadcastReceiver); + } catch (Exception e) { + // the receiver must have been not registered or unregistered before + } + + if (mBluetoothGatt != null) { + mBluetoothGatt.close(); + mRecords.clear(); + mGlucoseMeasurementCharacteristic = null; + mGlucoseMeasurementContextCharacteristic = null; + mGlucoseFeatureCharacteristic = null; + mRecordAccessControlPointCharacteristic = null; + mBatteryLevelCharacteristic = null; + mBluetoothGatt = null; + } + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java new file mode 100644 index 00000000..83a2a3d6 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.gls; + +import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; + +public interface GlucoseManagerCallbacks extends BleManagerCallbacks { + public static final int UNIT_mmHG = 0; + public static final int UNIT_kPa = 1; + + public void onGlucoseMeasurementNotificationEnabled(); + + public void onGlucoseMeasurementContextNotificationEnabled(); + + public void onRecordAccessControlPointIndicationsEnabled(); + + public void onOperationStarted(); + + public void onOperationCompleted(); + + public void onOperationFailed(); + + public void onOperationAborted(); + + public void onOperationNotSupported(); + + public void onDatasetChanged(); + + public void onNumberOfRecordsRequested(final int value); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseRecord.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseRecord.java new file mode 100644 index 00000000..f83c1731 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseRecord.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.gls; + +import java.util.Calendar; + +public class GlucoseRecord { + public static final int UNIT_kgpl = 0; + public static final int UNIT_molpl = 1; + + /** Record sequence number */ + protected int sequenceNumber; + /** The base time of the measurement */ + protected Calendar time; + /** Time offset of the record */ + protected int timeOffset; + /** The glucose concentration. 0 if not present */ + protected float glucoseConcentration; + /** Concentration unit. One of the following: {@link GlucoseRecord#UNIT_kgpl}, {@link GlucoseRecord#UNIT_molpl} */ + protected int unit; + /** The type of the record. 0 if not present */ + protected int type; + /** The sample location. 0 if unknown */ + protected int sampleLocation; + /** Sensor status annunciation flags. 0 if not present */ + protected int status; + + protected MeasurementContext context; + + public static class MeasurementContext { + public static final int UNIT_kg = 0; + public static final int UNIT_l = 1; + + /** + * One of the following:
+ * 0 Not present
+ * 1 Breakfast
+ * 2 Lunch
+ * 3 Dinner
+ * 4 Snack
+ * 5 Drink
+ * 6 Supper
+ * 7 Brunch + */ + protected int carbohydrateId; + /** Number of kilograms of carbohydrate */ + protected float carbohydrateUnits; + /** + * One of the following:
+ * 0 Not present
+ * 1 Preprandial (before meal)
+ * 2 Postprandial (after meal)
+ * 3 Fasting
+ * 4 Casual (snacks, drinks, etc.)
+ * 5 Bedtime + */ + protected int meal; + /** + * One of the following:
+ * 0 Not present
+ * 1 Self
+ * 2 Health Care Professional
+ * 3 Lab test
+ * 15 Tester value not available + */ + protected int tester; + /** + * One of the following:
+ * 0 Not present
+ * 1 Minor health issues
+ * 2 Major health issues
+ * 3 During menses
+ * 4 Under stress
+ * 5 No health issues
+ * 15 Tester value not available + */ + protected int health; + /** Exercise duration in seconds. 0 if not present */ + protected int exerciseDuration; + /** Exercise intensity in percent. 0 if not present */ + protected int exerciseIntensity; + /** + * One of the following:
+ * 0 Not present
+ * 1 Rapid acting insulin
+ * 2 Short acting insulin
+ * 3 Intermediate acting insulin
+ * 4 Long acting insulin
+ * 5 Pre-mixed insulin + */ + protected int medicationId; + /** Quantity of medication. See {@link #medicationUnit} for the unit. */ + protected float medicationQuantity; + /** One of the following: {@link GlucoseRecord.MeasurementContext#UNIT_kg}, {@link GlucoseRecord.MeasurementContext#UNIT_l}. */ + protected int medicationUnit; + /** HbA1c value. 0 if not present */ + protected float HbA1c; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java new file mode 100644 index 00000000..7e987e29 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.hrs; + +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileActivity; + +import org.achartengine.GraphicalView; + +import android.graphics.Point; +import android.os.Bundle; +import android.os.Handler; +import android.view.ViewGroup; +import android.widget.TextView; + +/** + * HRSActivity is the main Heart rate activity. It implements HRSManagerCallbacks to receive callbacks from HRSManager class. The activity supports portrait and landscape orientations. The activity + * uses external library AChartEngine to show real time graph of HR values. + */ +public class HRSActivity extends BleProfileActivity implements HRSManagerCallbacks { + @SuppressWarnings("unused") + private final String TAG = "HRSActivity"; + + private static final String GRAPH_STATUS = "graph_status"; + private static final String GRAPH_COUNTER = "graph_counter"; + private static final String HR_VALUE = "hr_value"; + + private final int MAX_HR_VALUE = 65535; + private final int MIN_POSITIVE_VALUE = 0; + private final int REFRESH_INTERVAL = 1000; // 1 second interval + + private Handler mHandler = new Handler(); + + private boolean isGraphInProgress = false; + + private GraphicalView mGraphView; + private LineGraphView mLineGraph; + private TextView mHRSValue, mHRSPosition; + + private int mHrmValue = 0; + private int mCounter = 0; + + @Override + protected void onCreateView(Bundle savedInstanceState) { + setContentView(R.layout.activity_feature_hrs); + setGUI(); + } + + private void setGUI() { + mLineGraph = LineGraphView.getLineGraphView(); + mHRSValue = (TextView) findViewById(R.id.text_hrs_value); + mHRSPosition = (TextView) findViewById(R.id.text_hrs_position); + showGraph(); + } + + private void showGraph() { + mGraphView = mLineGraph.getView(this); + ViewGroup layout = (ViewGroup) findViewById(R.id.graph_hrs); + layout.addView(mGraphView); + } + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + if (savedInstanceState != null) { + isGraphInProgress = savedInstanceState.getBoolean(GRAPH_STATUS); + mCounter = savedInstanceState.getInt(GRAPH_COUNTER); + mHrmValue = savedInstanceState.getInt(HR_VALUE); + + if (isGraphInProgress) + startShowGraph(); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putBoolean(GRAPH_STATUS, isGraphInProgress); + outState.putInt(GRAPH_COUNTER, mCounter); + outState.putInt(HR_VALUE, mHrmValue); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + stopShowGraph(); + } + + @Override + protected int getAboutTextId() { + return R.string.hrs_about_text; + } + + @Override + protected int getDefaultDeviceName() { + return R.string.hrs_default_name; + } + + @Override + protected UUID getFilterUUID() { + return HRSManager.HR_SERVICE_UUID; + } + + private void updateGraph(final int hrmValue) { + mCounter++; + mLineGraph.addValue(new Point(mCounter, hrmValue)); + mGraphView.repaint(); + } + + private Runnable mRepeatTask = new Runnable() { + @Override + public void run() { + if (mHrmValue > 0) + updateGraph(mHrmValue); + if (isGraphInProgress) + mHandler.postDelayed(mRepeatTask, REFRESH_INTERVAL); + } + }; + + void startShowGraph() { + isGraphInProgress = true; + mRepeatTask.run(); + } + + void stopShowGraph() { + isGraphInProgress = false; + mHandler.removeCallbacks(mRepeatTask); + } + + @Override + protected BleManager initializeManager() { + HRSManager manager = HRSManager.getInstance(this); + manager.setGattCallbacks(this); + return manager; + } + + private void setHRSValueOnView(final int value) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (value >= MIN_POSITIVE_VALUE && value <= MAX_HR_VALUE) { + mHRSValue.setText(Integer.toString(value)); + } else { + mHRSValue.setText(R.string.not_available_value); + } + } + }); + } + + private void setHRSPositionOnView(final String position) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (position != null) { + mHRSPosition.setText(position); + } else { + mHRSPosition.setText(R.string.not_available); + } + } + }); + } + + @Override + public void onServicesDiscovered(boolean optionalServicesFound) { + // this may notify user or show some views + } + + @Override + public void onHRSensorPositionFound(String position) { + setHRSPositionOnView(position); + } + + @Override + public void onHRNotificationEnabled() { + startShowGraph(); + } + + @Override + public void onHRValueReceived(int value) { + mHrmValue = value; + setHRSValueOnView(mHrmValue); + } + + @Override + public void onDeviceDisconnected() { + super.onDeviceDisconnected(); + runOnUiThread(new Runnable() { + @Override + public void run() { + mHRSValue.setText(R.string.not_available_value); + mHRSPosition.setText(R.string.not_available); + stopShowGraph(); + } + }); + } + + @Override + protected void setDefaultUI() { + mHRSValue.setText(R.string.not_available_value); + mHRSPosition.setText(R.string.not_available); + clearGraph(); + } + + private void clearGraph() { + mLineGraph.clearGraph(); + mGraphView.repaint(); + mCounter = 0; + mHrmValue = 0; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java new file mode 100644 index 00000000..4cf393e5 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.hrs; + +import java.util.List; +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +/** + * HRSManager class performs BluetoothGatt operations for connection, service discovery, enabling notification and reading characteristics. All operations required to connect to device with BLE HR + * Service and reading heart rate values are performed here. HRSActivity implements HRSManagerCallbacks in order to receive callbacks of BluetoothGatt operations + */ +public class HRSManager implements BleManager { + private final String TAG = "HRSManager"; + private HRSManagerCallbacks mCallbacks; + private BluetoothGatt mBluetoothGatt; + private Context mContext; + + public final static UUID HR_SERVICE_UUID = UUID.fromString("0000180D-0000-1000-8000-00805f9b34fb"); + private static final UUID HR_SENSOR_LOCATION_CHARACTERISTIC_UUID = UUID.fromString("00002A38-0000-1000-8000-00805f9b34fb"); + + private static final UUID HR_CHARACTERISTIC_UUID = UUID.fromString("00002A37-0000-1000-8000-00805f9b34fb"); + private static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + + private final static UUID BATTERY_SERVICE = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); + private final static UUID BATTERY_LEVEL_CHARACTERISTIC = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); + + private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change"; + private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services"; + private final static String ERROR_WRITE_DESCRIPTOR = "Error on writing descriptor"; + private final static String ERROR_READ_CHARACTERISTIC = "Error on reading characteristic"; + + private BluetoothGattCharacteristic mHRCharacteristic, mHRLocationCharacteristic, mBatteryCharacteristic; + private static final int FIRST_BITMASK = 0x01; + + private static HRSManager managerInstance = null; + + /** + * singleton implementation of HRSManager class + */ + public static synchronized HRSManager getInstance(Context context) { + if (managerInstance == null) { + managerInstance = new HRSManager(); + } + managerInstance.mContext = context; + return managerInstance; + } + + /** + * callbacks for activity {HRSActivity} that implements HRSManagerCallbacks interface activity use this method to register itself for receiving callbacks + */ + @Override + public void setGattCallbacks(HRSManagerCallbacks callbacks) { + mCallbacks = callbacks; + } + + @Override + public void connect(Context context, BluetoothDevice device) { + DebugLogger.d(TAG, "Connecting to device..."); + mBluetoothGatt = device.connectGatt(context, false, mGattCallback); + } + + /** + * Disable HR notification first and then disconnect to HR device + */ + @Override + public void disconnect() { + DebugLogger.d(TAG, "Disconnecting device..."); + if (mBluetoothGatt != null) { + mBluetoothGatt.disconnect(); + } + } + + /** + * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving notification, etc + */ + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + DebugLogger.d(TAG, "Device connected"); + mBluetoothGatt.discoverServices(); + //This will send callback to HRSActivity when device get connected + mCallbacks.onDeviceConnected(); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + DebugLogger.d(TAG, "Device disconnected"); + //This will send callback to HRSActivity when device get disconnected + mCallbacks.onDeviceDisconnected(); + } + } else { + mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status); + } + } + + @Override + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + List services = gatt.getServices(); + for (BluetoothGattService service : services) { + if (service.getUuid().equals(HR_SERVICE_UUID)) { + mHRCharacteristic = service.getCharacteristic(HR_CHARACTERISTIC_UUID); + mHRLocationCharacteristic = service.getCharacteristic(HR_SENSOR_LOCATION_CHARACTERISTIC_UUID); + } else if (service.getUuid().equals(BATTERY_SERVICE)) { + mBatteryCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC); + } + } + if (mHRCharacteristic != null) { + //This will send callback to HRSActivity when HR Service is found in device + mCallbacks.onServicesDiscovered(false); + readHRSensorLocation(); + } else { + mCallbacks.onDeviceNotSupported(); + gatt.disconnect(); + } + } else { + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (characteristic.getUuid().equals(HR_SENSOR_LOCATION_CHARACTERISTIC_UUID)) { + final String sensorPosition = getBodySensorPosition(characteristic.getValue()[0]); + //This will send callback to HRSActivity when HR sensor position on body is found in HR device + mCallbacks.onHRSensorPositionFound(sensorPosition); + + if (mBatteryCharacteristic != null) { + readBatteryLevel(); + } else { + enableHRNotification(); + } + } + if (characteristic.getUuid().equals(BATTERY_LEVEL_CHARACTERISTIC)) { + int batteryValue = characteristic.getValue()[0]; + //This will send callback to HRSActivity when Battery value is received from HR device + mCallbacks.onBatteryValueReceived(batteryValue); + + enableHRNotification(); + } + } else { + mCallbacks.onError(ERROR_READ_CHARACTERISTIC, status); + } + } + + @Override + public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { + int hrValue; + //This will check if HR value is in 8 bits or 16 bits. + if (characteristic.getUuid().equals(HR_CHARACTERISTIC_UUID)) { + if (isHeartRateInUINT16(characteristic.getValue()[0])) { + hrValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, 1); + } else { + hrValue = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 1); + } + //This will send callback to HRSActivity when new HR value is received from HR device + mCallbacks.onHRValueReceived(hrValue); + } + } + + @Override + public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + //This will send callback to HRSActivity when HR notification is enabled + mCallbacks.onHRNotificationEnabled(); + } else { + mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status); + } + } + }; + + private void readBatteryLevel() { + if (mBatteryCharacteristic != null) { + mBluetoothGatt.readCharacteristic(mBatteryCharacteristic); + } + } + + private void readHRSensorLocation() { + if (mHRLocationCharacteristic != null) { + mBluetoothGatt.readCharacteristic(mHRLocationCharacteristic); + } + } + + /** + * This method will decode and return Heart rate sensor position on body + */ + private String getBodySensorPosition(byte bodySensorPositionValue) { + String[] locations = mContext.getResources().getStringArray(R.array.hrs_locations); + if (bodySensorPositionValue > locations.length) + return mContext.getString(R.string.hrs_location_other); + return locations[bodySensorPositionValue]; + } + + /** + * This method will check if Heart rate value is in 8 bits or 16 bits + */ + private boolean isHeartRateInUINT16(byte value) { + return ((value & FIRST_BITMASK) != 0); + } + + /** + * Enabling notification on Heart Rate Characteristic + */ + private void enableHRNotification() { + DebugLogger.d(TAG, "Enabling heart rate notifications"); + mBluetoothGatt.setCharacteristicNotification(mHRCharacteristic, true); + BluetoothGattDescriptor descriptor = mHRCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + mBluetoothGatt.writeDescriptor(descriptor); + } + + @Override + public void closeBluetoothGatt() { + if (mBluetoothGatt != null) { + mBluetoothGatt.close(); + mBluetoothGatt = null; + } + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java new file mode 100644 index 00000000..ab083e6e --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.hrs; + +import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; + +public interface HRSManagerCallbacks extends BleManagerCallbacks { + + /** + * Called when Heart Rate notifications has been enabled + */ + public void onHRNotificationEnabled(); + + /** + * Called when the sensor position information has been obtained from the sensor + * + * @param position + * the sensor position + */ + public void onHRSensorPositionFound(String position); + + /** + * Called when new Heart Rate value has been obtained from the sensor + * + * @param value + * the new value + */ + public void onHRValueReceived(int value); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/LineGraphView.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/LineGraphView.java new file mode 100644 index 00000000..c2208234 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/LineGraphView.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.hrs; + +import org.achartengine.ChartFactory; +import org.achartengine.GraphicalView; +import org.achartengine.chart.PointStyle; +import org.achartengine.model.TimeSeries; +import org.achartengine.model.XYMultipleSeriesDataset; +import org.achartengine.renderer.XYMultipleSeriesRenderer; +import org.achartengine.renderer.XYSeriesRenderer; + +import android.content.Context; +import android.graphics.Color; +import android.graphics.Paint.Align; +import android.graphics.Point; + +/** + * This class uses external library AChartEngine to show dynamic real time line graph for HR values + */ +public class LineGraphView { + //TimeSeries will hold the data in x,y format for single chart + private TimeSeries mSeries = new TimeSeries("Heart Rate"); + //XYMultipleSeriesDataset will contain all the TimeSeries + private XYMultipleSeriesDataset mDataset = new XYMultipleSeriesDataset(); + //XYMultipleSeriesRenderer will contain all XYSeriesRenderer and it can be used to set the properties of whole Graph + private XYMultipleSeriesRenderer mMultiRenderer = new XYMultipleSeriesRenderer(); + private static LineGraphView mInstance = null; + + /** + * singleton implementation of LineGraphView class + */ + public static synchronized LineGraphView getLineGraphView() { + if (mInstance == null) { + mInstance = new LineGraphView(); + } + return mInstance; + } + + /** + * This constructor will set some properties of single chart and some properties of whole graph + */ + public LineGraphView() { + //add single line chart mSeries + mDataset.addSeries(mSeries); + + //XYSeriesRenderer is used to set the properties like chart color, style of each point, etc. of single chart + final XYSeriesRenderer seriesRenderer = new XYSeriesRenderer(); + //set line chart color to Black + seriesRenderer.setColor(Color.BLACK); + //set line chart style to square points + seriesRenderer.setPointStyle(PointStyle.SQUARE); + seriesRenderer.setFillPoints(true); + + final XYMultipleSeriesRenderer renderer = mMultiRenderer; + //set whole graph background color to transparent color + renderer.setBackgroundColor(Color.TRANSPARENT); + renderer.setMargins(new int[] { 50, 65, 40, 5 }); // top, left, bottom, right + renderer.setMarginsColor(Color.argb(0x00, 0x01, 0x01, 0x01)); + renderer.setAxesColor(Color.BLACK); + renderer.setAxisTitleTextSize(24); + renderer.setShowGrid(true); + renderer.setGridColor(Color.LTGRAY); + renderer.setLabelsColor(Color.BLACK); + renderer.setYLabelsColor(0, Color.DKGRAY); + renderer.setYLabelsAlign(Align.RIGHT); + renderer.setYLabelsPadding(4.0f); + renderer.setXLabelsColor(Color.DKGRAY); + renderer.setLabelsTextSize(20); + renderer.setLegendTextSize(20); + //Disable zoom + renderer.setPanEnabled(false, false); + renderer.setZoomEnabled(false, false); + //set title to x-axis and y-axis + renderer.setXTitle(" Time (seconds)"); + renderer.setYTitle(" BPM"); + renderer.addSeriesRenderer(seriesRenderer); + } + + /** + * return graph view to activity + */ + public GraphicalView getView(Context context) { + final GraphicalView graphView = ChartFactory.getLineChartView(context, mDataset, mMultiRenderer); + return graphView; + } + + /** + * add new x,y value to chart + */ + public void addValue(Point p) { + mSeries.add(p.x, p.y); + } + + /** + * clear all previous values of chart + */ + public void clearGraph() { + mSeries.clear(); + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java new file mode 100644 index 00000000..3a9c0dd9 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.hts; + +import java.text.DecimalFormat; +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; +import android.widget.TextView; + +/** + * HTSActivity is the main Health Thermometer activity. It implements {@link HTSManagerCallbacks} to receive callbacks from {@link HTSManager} class. The activity supports portrait and landscape + * orientations. + */ +public class HTSActivity extends BleProfileServiceReadyActivity { + @SuppressWarnings("unused") + private final String TAG = "HTSActivity"; + + private TextView mHTSValue; + + @Override + protected void onCreateView(Bundle savedInstanceState) { + setContentView(R.layout.activity_feature_hts); + setGUI(); + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + private void setGUI() { + mHTSValue = (TextView) findViewById(R.id.text_hts_value); + } + + @Override + protected void onServiceBinded(final HTSService.RSCBinder binder) { + // not used + } + + @Override + protected void onServiceUnbinded() { + // not used + } + + @Override + protected int getAboutTextId() { + return R.string.hts_about_text; + } + + @Override + protected int getDefaultDeviceName() { + return R.string.hts_default_name; + } + + @Override + protected UUID getFilterUUID() { + return HTSManager.HT_SERVICE_UUID; + } + + @Override + protected Class getServiceClass() { + return HTSService.class; + } + + @Override + public void onServicesDiscovered(boolean optionalServicesFound) { + // this may notify user or show some views + } + + private void setHTSValueOnView(final double value) { + DecimalFormat formattedTemp = new DecimalFormat("#0.00"); + mHTSValue.setText(formattedTemp.format(value)); + } + + @Override + protected void setDefaultUI() { + mHTSValue.setText(R.string.not_available_value); + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + + if (HTSService.BROADCAST_HTS_MEASUREMENT.equals(action)) { + final double value = intent.getDoubleExtra(HTSService.EXTRA_TEMPERATURE, 0.0f); + // Update GUI + setHTSValueOnView(value); + } + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(HTSService.BROADCAST_HTS_MEASUREMENT); + return intentFilter; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java new file mode 100644 index 00000000..5f7ef22a --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.hts; + +import java.util.List; +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothProfile; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +/** + * HTSManager class performs BluetoothGatt operations for connection, service discovery, enabling indication and reading characteristics. All operations required to connect to device with BLE HT + * Service and reading health thermometer values are performed here. HTSActivity implements HTSManagerCallbacks in order to receive callbacks of BluetoothGatt operations + */ +public class HTSManager implements BleManager { + private final String TAG = "HTSManager"; + private HTSManagerCallbacks mCallbacks; + private BluetoothGatt mBluetoothGatt; + private Context mContext; + + public final static UUID HT_SERVICE_UUID = UUID.fromString("00001809-0000-1000-8000-00805f9b34fb"); + + private static final UUID HT_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A1C-0000-1000-8000-00805f9b34fb"); + private static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + + private final static UUID BATTERY_SERVICE = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); + private final static UUID BATTERY_LEVEL_CHARACTERISTIC = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); + + private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change"; + private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services"; + private final static String ERROR_READ_CHARACTERISTIC = "Error on reading characteristic"; + private final static String ERROR_WRITE_DESCRIPTOR = "Error on writing descriptor"; + private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information"; + + private BluetoothGattCharacteristic mHTCharacteristic, mBatteryCharacteristic; + + private final static int HIDE_MSB_8BITS_OUT_OF_32BITS = 0x00FFFFFF; + private final static int HIDE_MSB_8BITS_OUT_OF_16BITS = 0x00FF; + private final static int SHIFT_LEFT_8BITS = 8; + private final static int SHIFT_LEFT_16BITS = 16; + private final static int GET_BIT24 = 0x00400000; + private final static int FIRST_BIT_MASK = 0x01; + + private static HTSManager managerInstance = null; + + /** + * singleton implementation of HTSManager class + */ + public static synchronized HTSManager getHTSManager() { + if (managerInstance == null) { + managerInstance = new HTSManager(); + } + return managerInstance; + } + + /** + * callbacks for activity {HTSActivity} that implements HTSManagerCallbacks interface activity use this method to register itself for receiving callbacks + */ + @Override + public void setGattCallbacks(HTSManagerCallbacks callbacks) { + mCallbacks = callbacks; + } + + @Override + public void connect(Context context, BluetoothDevice device) { + mBluetoothGatt = device.connectGatt(context, false, mGattCallback); + mContext = context; + } + + @Override + public void disconnect() { + DebugLogger.d(TAG, "Disconnecting device"); + if (mBluetoothGatt != null) { + mBluetoothGatt.disconnect(); + } + } + + private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); + final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1); + + DebugLogger.d(TAG, "Bond state changed for: " + device.getAddress() + " new state: " + bondState + " previous: " + previousBondState); + + // skip other devices + if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) + return; + + if (bondState == BluetoothDevice.BOND_BONDED) { + // We've read Battery Level, now enabling HT indications + if (mHTCharacteristic != null) { + enableHTIndication(); + } + mContext.unregisterReceiver(this); + mCallbacks.onBonded(); + } + } + }; + + /** + * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc + */ + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + DebugLogger.d(TAG, "Device connected"); + mBluetoothGatt.discoverServices(); + //This will send callback to HTSActivity when device get connected + mCallbacks.onDeviceConnected(); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + DebugLogger.d(TAG, "Device disconnected"); + //This will send callback to HTSActivity when device get disconnected + mCallbacks.onDeviceDisconnected(); + } + } else { + mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status); + } + } + + @Override + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + List services = gatt.getServices(); + for (BluetoothGattService service : services) { + if (service.getUuid().equals(HT_SERVICE_UUID)) { + mHTCharacteristic = service.getCharacteristic(HT_MEASUREMENT_CHARACTERISTIC_UUID); + } else if (service.getUuid().equals(BATTERY_SERVICE)) { + mBatteryCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC); + } + } + if (mHTCharacteristic != null) { + mCallbacks.onServicesDiscovered(false); + } else { + mCallbacks.onDeviceNotSupported(); + gatt.disconnect(); + return; + } + if (mBatteryCharacteristic != null) { + readBatteryLevel(); + } else { + enableHTIndication(); + } + } else { + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (characteristic.getUuid().equals(BATTERY_LEVEL_CHARACTERISTIC)) { + int batteryValue = characteristic.getValue()[0]; + mCallbacks.onBatteryValueReceived(batteryValue); + + enableHTIndication(); + } + } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { + if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { + DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); + mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status); + } + } else { + mCallbacks.onError(ERROR_READ_CHARACTERISTIC, status); + } + } + + @Override + public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { + if (characteristic.getUuid().equals(HT_MEASUREMENT_CHARACTERISTIC_UUID)) { + try { + double tempValue = decodeTemperature(characteristic.getValue()); + mCallbacks.onHTValueReceived(tempValue); + } catch (Exception e) { + DebugLogger.e(TAG, "invalid temperature value"); + } + } + } + + @Override + public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + // HT indications has been enabled + } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { + if (gatt.getDevice().getBondState() == BluetoothDevice.BOND_NONE) { + mCallbacks.onBondingRequired(); + + final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + mContext.registerReceiver(mBondingBroadcastReceiver, filter); + } else { + DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); + mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status); + } + } else { + DebugLogger.e(TAG, ERROR_WRITE_DESCRIPTOR + " (" + status + ")"); + mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status); + } + } + }; + + public void readBatteryLevel() { + if (mBatteryCharacteristic != null) { + mBluetoothGatt.readCharacteristic(mBatteryCharacteristic); + } else { + DebugLogger.e(TAG, "Battery Level Characteristic is null"); + } + } + + /** + * enable Health Thermometer indication on Health Thermometer Measurement characteristic + */ + private void enableHTIndication() { + mBluetoothGatt.setCharacteristicNotification(mHTCharacteristic, true); + BluetoothGattDescriptor descriptor = mHTCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); + mBluetoothGatt.writeDescriptor(descriptor); + } + + /** + * This method decode temperature value received from Health Thermometer device First byte {0} of data is flag and first bit of flag shows unit information of temperature. if bit 0 has value 1 + * then unit is Fahrenheit and Celsius otherwise Four bytes {1 to 4} after Flag bytes represent the temperature value in IEEE-11073 32-bit Float format + */ + private double decodeTemperature(byte[] data) throws Exception { + double temperatureValue; + byte flag = data[0]; + byte exponential = data[4]; + short firstOctet = convertNegativeByteToPositiveShort(data[1]); + short secondOctet = convertNegativeByteToPositiveShort(data[2]); + short thirdOctet = convertNegativeByteToPositiveShort(data[3]); + int mantissa = ((thirdOctet << SHIFT_LEFT_16BITS) | (secondOctet << SHIFT_LEFT_8BITS) | (firstOctet)) & HIDE_MSB_8BITS_OUT_OF_32BITS; + mantissa = getTwosComplimentOfNegativeMantissa(mantissa); + temperatureValue = (mantissa * Math.pow(10, exponential)); + /* + * Conversion of temperature unit from Fahrenheit to Celsius if unit is in Fahrenheit + * Celsius = (98.6*Fahrenheit -32) 5/9 + */ + if ((flag & FIRST_BIT_MASK) != 0) { + temperatureValue = (float) ((98.6 * temperatureValue - 32) * (5 / 9.0)); + } + return temperatureValue; + } + + private short convertNegativeByteToPositiveShort(byte octet) { + if (octet < 0) { + return (short) (octet & HIDE_MSB_8BITS_OUT_OF_16BITS); + } else { + return octet; + } + } + + private int getTwosComplimentOfNegativeMantissa(int mantissa) { + if ((mantissa & GET_BIT24) != 0) { + return ((((~mantissa) & HIDE_MSB_8BITS_OUT_OF_32BITS) + 1) * (-1)); + } else { + return mantissa; + } + } + + @Override + public void closeBluetoothGatt() { + try { + mContext.unregisterReceiver(mBondingBroadcastReceiver); + } catch (Exception e) { + // the receiver must have been not registered or unregistered before + } + if (mBluetoothGatt != null) { + mBluetoothGatt.close(); + mBluetoothGatt = null; + mBatteryCharacteristic = null; + mHTCharacteristic = null; + } + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java new file mode 100644 index 00000000..9063c9df --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.hts; + +import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; + +/** + * Interface {@link HTSManagerCallbacks} must be implemented by {@link HTSActivity} in order to receive callbacks from {@link HTSManager} + */ +public interface HTSManagerCallbacks extends BleManagerCallbacks { + + /** + * Called when Health Thermometer value has been received + * + * @param value + * the new value + */ + public void onHTValueReceived(double value); + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java new file mode 100644 index 00000000..d40a0dd8 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.hts; + +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.FeaturesActivity; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.IBinder; +import android.support.v4.content.LocalBroadcastManager; + +public class HTSService extends BleProfileService implements HTSManagerCallbacks { + public static final String BROADCAST_HTS_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.hts.BROADCAST_HTS_MEASUREMENT"; + public static final String EXTRA_TEMPERATURE = "no.nordicsemi.android.nrftoolbox.hts.EXTRA_TEMPERATURE"; + + private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.hts.ACTION_DISCONNECT"; + + private final static int NOTIFICATION_ID = 267; + private final static int OPEN_ACTIVITY_REQ = 0; + private final static int DISCONNECT_REQ = 1; + + private HTSManager mManager; + private boolean mBinded; + + private final LocalBinder mBinder = new RSCBinder(); + + /** + * This local binder is an interface for the binded activity to operate with the HTS sensor + */ + public class RSCBinder extends LocalBinder { + // empty + } + + @Override + protected LocalBinder getBinder() { + return mBinder; + } + + @Override + protected BleManager initializeManager() { + return mManager = new HTSManager(); + } + + @Override + public void onCreate() { + super.onCreate(); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DISCONNECT); + registerReceiver(mDisconnectActionBroadcastReceiver, filter); + } + + @Override + public void onDestroy() { + // when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService + cancelNotification(); + unregisterReceiver(mDisconnectActionBroadcastReceiver); + + super.onDestroy(); + } + + @Override + public IBinder onBind(final Intent intent) { + mBinded = true; + return super.onBind(intent); + } + + @Override + public void onRebind(final Intent intent) { + mBinded = true; + // when the activity rebinds to the service, remove the notification + cancelNotification(); + + // read the battery level when back in the Activity + if (isConnected()) + mManager.readBatteryLevel(); + } + + @Override + public boolean onUnbind(final Intent intent) { + mBinded = false; + // when the activity closes we need to show the notification that user is connected to the sensor + createNotifcation(R.string.hts_notification_connected_message, 0); + return super.onUnbind(intent); + } + + @Override + public void onHTValueReceived(final double value) { + final Intent broadcast = new Intent(BROADCAST_HTS_MEASUREMENT); + broadcast.putExtra(EXTRA_TEMPERATURE, value); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + /** + * Creates the notification + * + * @param messageResId + * message resource id. The message must have one String parameter,
+ * f.e. <string name="name">%s is connected</string> + * @param defaults + * signals that will be used to notify the user + */ + private void createNotifcation(final int messageResId, final int defaults) { + final Intent parentIntent = new Intent(this, FeaturesActivity.class); + parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final Intent targetIntent = new Intent(this, HTSActivity.class); + + final Intent disconnect = new Intent(ACTION_DISCONNECT); + final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT); + + // both activities above have launchMode="singleTask" in the AndoridManifest.xml file, so if the task is already running, it will be resumed + final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT); + final Notification.Builder builder = new Notification.Builder(this).setContentIntent(pendingIntent); + builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); + builder.setSmallIcon(R.drawable.ic_stat_notify_hts); + builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); + builder.addAction(R.drawable.ic_action_bluetooth, getString(R.string.hts_notification_action_disconnect), disconnectAction); + + final Notification notification = builder.build(); + final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID, notification); + } + + /** + * Cancels the existing notification. If there is no active notification this method does nothing + */ + private void cancelNotification() { + final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + nm.cancel(NOTIFICATION_ID); + } + + /** + * This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification. + */ + private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + Logger.i(getLogSession(), "[HTS] Disconnect action pressed"); + if (isConnected()) + getBinder().disconnect(); + else + stopSelf(); + } + }; + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java new file mode 100644 index 00000000..f2810fd9 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManager.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.profile; + +import android.app.Activity; +import android.bluetooth.BluetoothDevice; +import android.content.Context; + +public interface BleManager { + + /** + * Connects to the Bluetooth Smart device + * + * @param context + * this must be an application context, not the Activity. Call {@link Activity#getApplicationContext()} to get one. + * @param device + * a device to connect to + */ + public void connect(final Context context, final BluetoothDevice device); + + /** + * Disconnects from the device. Does nothing if not connected. + */ + public void disconnect(); + + /** + * Sets the manager callback listener + * + * @param callbacks + * the callback listener + */ + public void setGattCallbacks(E callbacks); + + /** + * Closes and releases resources. May be also used to unregister broadcast listeners. + */ + public void closeBluetoothGatt(); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManagerCallbacks.java new file mode 100644 index 00000000..18082c66 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleManagerCallbacks.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.profile; + +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; + +public interface BleManagerCallbacks { + + /** + * Called when the device has been connected. This does not mean that the application may start communication. A service discovery will be handled automatically after this call. Service discovery + * may ends up with calling {@link #onServicesDiscovered(boolean)} or {@link #onDeviceNotSupported()} if required services have not been found. + */ + public void onDeviceConnected(); + + /** + * Called when the device has disconnected (when the callback returned {@link BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} with state DISCONNECTED. + */ + public void onDeviceDisconnected(); + + /** + * Some profiles may use this method to notify user that the link was lost. You must call this method in youe Ble Manager instead of {@link #onDeviceDisconnected()} while you discover + * disconnection not initiated by the user. + */ + public void onLinklossOccur(); + + /** + * Called when service discovery has finished and primary services has been found. The device is ready to operate. This method is not called if the primary, mandatory services were not found + * during service discovery. For example in the Blood Pressure Monitor, a Blood Pressure service is a primary service and Intermediate Cuff Pressure service is a optional secondary service. + * Existence of battery service is not notified by this call. + * + * @param optionalServicesFound + * if true the secondary services were also found on the device. + */ + public void onServicesDiscovered(final boolean optionalServicesFound); + + /** + * Called when battery value has been received from the device + * + * @param value + * the battery value in percent + */ + public void onBatteryValueReceived(final int value); + + /** + * Called when an {@link BluetoothGatt#GATT_INSUFFICIENT_AUTHENTICATION} error occurred and the device bond state is NOT_BONDED + */ + public void onBondingRequired(); + + /** + * Called when the device has been successfully bonded + */ + public void onBonded(); + + /** + * Called when a BLE error has occurred + * + * @param message + * the error message + * @param errorCode + * the error code + */ + public void onError(final String message, final int errorCode); + + /** + * Called when service discovery has finished but the main services were not found on the device. This may occur when connecting to bonded device that does not support required services. + */ + public void onDeviceNotSupported(); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java new file mode 100644 index 00000000..855944d0 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java @@ -0,0 +1,396 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.profile; + +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.AppHelpFragment; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +public abstract class BleProfileActivity extends ActionBarActivity implements BleManagerCallbacks, ScannerFragment.OnDeviceSelectedListener { + private static final String TAG = "BaseProfileActivity"; + + private static final String CONNECTION_STATUS = "connection_status"; + private static final String DEVICE_NAME = "device_name"; + private static final int REQUEST_ENABLE_BT = 2; + + private BleManager mBleManager; + + private TextView mDeviceNameView; + private TextView mBatteryLevelView; + private Button mConnectButton; + + private boolean mDeviceConnected = false; + private String mDeviceName; + + @Override + protected final void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ensureBLESupported(); + if (!isBLEEnabled()) { + showBLEDialog(); + } + + /* + * We use the managers using a singleton pattern. It's not recommended for the Android, because the singleton instance remains after Activity has been + * destroyed but it's simple and is used only for this demo purpose. In final application Managers should be created as a non-static objects in + * Services. The Service should implement ManagerCallbacks interface. The application Activity may communicate with such Service using binding, + * broadcast listeners, local broadcast listeners (see support.v4 library), or messages. See the Proximity profile for Service approach. + */ + mBleManager = initializeManager(); + onInitialize(savedInstanceState); + onCreateView(savedInstanceState); + onViewCreated(savedInstanceState); + } + + /** + * You may do some initialization here. This method is called from {@link #onCreate(Bundle)} before the view was created. + */ + protected void onInitialize(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called from {@link #onCreate(Bundle)}. This method should build the activity UI, f.e. using {@link #setContentView(int)}. Use to obtain references to + * views. Connect/Disconnect button, the device name view and battery level view are manager automatically. + * + * @param savedInstanceState + * contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. Note: Otherwise it is null. + */ + protected abstract void onCreateView(final Bundle savedInstanceState); + + /** + * Called after the view has been created. + * + * @param savedInstanceState + */ + protected final void onViewCreated(final Bundle savedInstanceState) { + // set GUI + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mConnectButton = (Button) findViewById(R.id.action_connect); + mDeviceNameView = (TextView) findViewById(R.id.device_name); + mBatteryLevelView = (TextView) findViewById(R.id.battery); + } + + @Override + public void onBackPressed() { + mBleManager.disconnect(); + super.onBackPressed(); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(CONNECTION_STATUS, mDeviceConnected); + outState.putString(DEVICE_NAME, mDeviceName); + } + + @Override + protected void onRestoreInstanceState(final Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mDeviceConnected = savedInstanceState.getBoolean(CONNECTION_STATUS); + mDeviceName = savedInstanceState.getString(DEVICE_NAME); + + if (mDeviceConnected) { + mConnectButton.setText(R.string.action_disconnect); + } else { + mConnectButton.setText(R.string.action_connect); + } + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.help, menu); + return true; + } + + /** + * Use this method to handle menu actions other than home and about. + * + * @param itemId + * the menu item id + * @return true if action has been handled + */ + protected boolean onOptionsItemSelected(final int itemId) { + // Overwrite when using menu other than R.menu.help + return false; + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + final int id = item.getItemId(); + switch (id) { + case android.R.id.home: + onBackPressed(); + break; + case R.id.action_about: + final AppHelpFragment fragment = AppHelpFragment.getInstance(getAboutTextId()); + fragment.show(getFragmentManager(), "help_fragment"); + break; + default: + return onOptionsItemSelected(id); + } + return true; + } + + /** + * Called when user press CONNECT or DISCONNECT button. See layout files -> onClick attribute. + */ + public void onConnectClicked(final View view) { + if (isBLEEnabled()) { + if (!mDeviceConnected) { + setDefaultUI(); + showDeviceScanningDialog(getFilterUUID(), isDiscoverableRequired()); + } else { + mBleManager.disconnect(); + } + } else { + showBLEDialog(); + } + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + mDeviceNameView.setText(mDeviceName = name); + mBleManager.connect(getApplicationContext(), device); + } + + @Override + public void onDialogCanceled() { + // do nothing + } + + @Override + public void onDeviceConnected() { + mDeviceConnected = true; + runOnUiThread(new Runnable() { + @Override + public void run() { + mConnectButton.setText(R.string.action_disconnect); + } + }); + } + + @Override + public void onDeviceDisconnected() { + mDeviceConnected = false; + mBleManager.closeBluetoothGatt(); + runOnUiThread(new Runnable() { + @Override + public void run() { + mConnectButton.setText(R.string.action_connect); + mDeviceNameView.setText(getDefaultDeviceName()); + mBatteryLevelView.setText(R.string.not_available); + } + }); + } + + @Override + public void onLinklossOccur() { + mDeviceConnected = false; + runOnUiThread(new Runnable() { + @Override + public void run() { + mConnectButton.setText(R.string.action_connect); + mDeviceNameView.setText(getDefaultDeviceName()); + mBatteryLevelView.setText(R.string.not_available); + } + }); + } + + @Override + public void onBatteryValueReceived(final int value) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mBatteryLevelView.setText(getString(R.string.battery, value)); + } + }); + } + + @Override + public void onBondingRequired() { + showToast(R.string.bonding); + } + + @Override + public void onBonded() { + showToast(R.string.bonded); + } + + @Override + public void onError(final String message, final int errorCode) { + DebugLogger.e(TAG, "Error occured: " + message + ", error code: " + errorCode); + showToast(message + " (" + errorCode + ")"); + + // refresh UI when connection failed + onDeviceDisconnected(); + } + + @Override + public void onDeviceNotSupported() { + showToast(R.string.not_supported); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message + * a message to be shown + */ + protected void showToast(final String message) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(BleProfileActivity.this, message, Toast.LENGTH_SHORT).show(); + } + }); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId + * an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(BleProfileActivity.this, messageResId, Toast.LENGTH_SHORT).show(); + } + }); + } + + /** + * Returns true if the device is connected. Services may not have been discovered yet. + */ + protected boolean isDeviceConnected() { + return mDeviceConnected; + } + + /** + * Returns the name of the device that the phone is currently connected to or was connected last time + */ + protected String getDeviceName() { + return mDeviceName; + } + + /** + * Initializes the Bluetooth Low Energy manager. A manager is used to communicate with profile's services. + * + * @return the manager that was created + */ + protected abstract BleManager initializeManager(); + + /** + * Restores the default UI before reconnecting + */ + protected abstract void setDefaultUI(); + + /** + * Returns the default device name resource id. The real device name is obtained when connecting to the device. This one is used when device has + * disconnected. + * + * @return the default device name resource id + */ + protected abstract int getDefaultDeviceName(); + + /** + * Returns the string resource id that will be shown in About box + * + * @return the about resource id + */ + protected abstract int getAboutTextId(); + + /** + * The UUID filter is used to filter out available devices that does not have such UUID in their advertisement packet. See also: + * {@link #isChangingConfigurations()}. + * + * @return the required UUID or null + */ + protected abstract UUID getFilterUUID(); + + /** + * Whether the scanner must search only for devices with GENERAL_DISCOVERABLE or LIMITER_DISCOVERABLE flag set. + * + * @return true if devices must have one of those flags set in their advertisement packets + */ + protected boolean isDiscoverableRequired() { + return true; + } + + /** + * Shows the scanner fragment. + * + * @param filter + * the UUID filter used to filter out available devices. The fragment will always show all bonded devices as there is no information about their + * services + * @param discoverableRequired + * true if devices must have GENERAL_DISCOVERABLE or LIMITED_DISCOVERABLE flags set in their advertisement packet + * @see #getFilterUUID() + */ + private void showDeviceScanningDialog(final UUID filter, final boolean discoverableRequired) { + runOnUiThread(new Runnable() { + @Override + public void run() { + final ScannerFragment dialog = ScannerFragment.getInstance(BleProfileActivity.this, filter, discoverableRequired); + dialog.show(getFragmentManager(), "scan_fragment"); + } + }); + } + + private void ensureBLESupported() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show(); + finish(); + } + } + + protected boolean isBLEEnabled() { + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + final BluetoothAdapter adapter = bluetoothManager.getAdapter(); + return adapter != null && adapter.isEnabled(); + } + + protected void showBLEDialog() { + final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableIntent, REQUEST_ENABLE_BT); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java new file mode 100644 index 00000000..8fe2a34b --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java @@ -0,0 +1,391 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.profile; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.AppHelpFragment; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.app.ExpandableListActivity; +import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; + +public abstract class BleProfileExpandableListActivity extends ExpandableListActivity implements BleManagerCallbacks, ScannerFragment.OnDeviceSelectedListener { + private static final String TAG = "BaseProfileActivity"; + + private static final String CONNECTION_STATUS = "connection_status"; + private static final String DEVICE_NAME = "device_name"; + protected static final int REQUEST_ENABLE_BT = 2; + + private BleManager mBleManager; + + private TextView mDeviceNameView; + private TextView mBatteryLevelView; + private Button mConnectButton; + + private boolean mDeviceConnected = false; + private String mDeviceName; + + @Override + protected final void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ensureBLESupported(); + if (!isBLEEnabled()) { + showBLEDialog(); + } + + /* + * We use the managers using a singleton pattern. It's not recommended for the Android, because the singleton instance remains after Activity has been + * destroyed but it's simple and is used only for this demo purpose. In final application Managers should be created as a non-static objects in + * Services. The Service should implement ManagerCallbacks interface. The application Activity may communicate with such Service using binding, + * broadcast listeners, local broadcast listeners (see support.v4 library), or messages. See the Proximity profile for Service approach. + */ + mBleManager = initializeManager(); + onInitialize(savedInstanceState); + onCreateView(savedInstanceState); + onViewCreated(savedInstanceState); + } + + /** + * You may do some initialization here. This method is called from {@link #onCreate(Bundle)} before the view was created. + */ + protected void onInitialize(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called from {@link #onCreate(Bundle)}. This method should build the activity UI, f.e. using {@link #setContentView(int)}. Use to obtain references to + * views. Connect/Disconnect button, the device name view and battery level view are manager automatically. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. Note: Otherwise it is null. + */ + protected abstract void onCreateView(final Bundle savedInstanceState); + + /** + * Called after the view has been created. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. Note: Otherwise it is null. + */ + protected final void onViewCreated(final Bundle savedInstanceState) { + // set GUI + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mConnectButton = (Button) findViewById(R.id.action_connect); + mDeviceNameView = (TextView) findViewById(R.id.device_name); + mBatteryLevelView = (TextView) findViewById(R.id.battery); + } + + @Override + public void onBackPressed() { + mBleManager.disconnect(); + super.onBackPressed(); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(CONNECTION_STATUS, mDeviceConnected); + outState.putString(DEVICE_NAME, mDeviceName); + } + + @Override + protected void onRestoreInstanceState(final Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mDeviceConnected = savedInstanceState.getBoolean(CONNECTION_STATUS); + mDeviceName = savedInstanceState.getString(DEVICE_NAME); + + if (mDeviceConnected) { + mConnectButton.setText(R.string.action_disconnect); + } else { + mConnectButton.setText(R.string.action_connect); + } + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.help, menu); + return true; + } + + /** + * Use this method to handle menu actions other than home and about. + * + * @param itemId the menu item id + * @return true if action has been handled + */ + protected boolean onOptionsItemSelected(final int itemId) { + // Overwrite when using menu other than R.menu.help + return false; + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + final int id = item.getItemId(); + switch (id) { + case android.R.id.home: + onBackPressed(); + break; + case R.id.action_about: + final AppHelpFragment fragment = AppHelpFragment.getInstance(getAboutTextId()); + fragment.show(getFragmentManager(), "help_fragment"); + break; + default: + return onOptionsItemSelected(id); + } + return true; + } + + /** + * Called when user press CONNECT or DISCONNECT button. See layout files -> onClick attribute. + */ + public void onConnectClicked(final View view) { + if (isBLEEnabled()) { + if (!mDeviceConnected) { + setDefaultUI(); + showDeviceScanningDialog(getFilterUUID(), isDiscoverableRequired()); + } else { + mBleManager.disconnect(); + } + } else { + showBLEDialog(); + } + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + mDeviceNameView.setText(mDeviceName = name); + mBleManager.connect(getApplicationContext(), device); + } + + @Override + public void onDialogCanceled() { + // do nothing + } + + @Override + public void onDeviceConnected() { + mDeviceConnected = true; + runOnUiThread(new Runnable() { + @Override + public void run() { + mConnectButton.setText(R.string.action_disconnect); + } + }); + } + + @Override + public void onDeviceDisconnected() { + mDeviceConnected = false; + mBleManager.closeBluetoothGatt(); + runOnUiThread(new Runnable() { + @Override + public void run() { + mConnectButton.setText(R.string.action_connect); + mDeviceNameView.setText(getDefaultDeviceName()); + mBatteryLevelView.setText(R.string.not_available); + } + }); + } + + @Override + public void onLinklossOccur() { + mDeviceConnected = false; + runOnUiThread(new Runnable() { + @Override + public void run() { + mConnectButton.setText(R.string.action_connect); + mDeviceNameView.setText(getDefaultDeviceName()); + mBatteryLevelView.setText(R.string.not_available); + } + }); + } + + @Override + public void onBatteryValueReceived(final int value) { + runOnUiThread(new Runnable() { + @Override + public void run() { + mBatteryLevelView.setText(getString(R.string.battery, value)); + } + }); + } + + @Override + public void onBondingRequired() { + showToast(R.string.bonding); + } + + @Override + public void onBonded() { + showToast(R.string.bonded); + } + + @Override + public void onError(final String message, final int errorCode) { + DebugLogger.e(TAG, "Error occured: " + message + ", error code: " + errorCode); + showToast(message + " (" + errorCode + ")"); + + // refresh UI when connection failed + onDeviceDisconnected(); + } + + @Override + public void onDeviceNotSupported() { + showToast(R.string.not_supported); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message a message to be shown + */ + protected void showToast(final String message) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(BleProfileExpandableListActivity.this, message, Toast.LENGTH_SHORT).show(); + } + }); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(BleProfileExpandableListActivity.this, messageResId, Toast.LENGTH_SHORT).show(); + } + }); + } + + /** + * Returns true if the device is connected. Services may not have been discovered yet. + */ + protected boolean isDeviceConnected() { + return mDeviceConnected; + } + + /** + * Returns the name of the device that the phone is currently connected to or was connected last time + */ + protected String getDeviceName() { + return mDeviceName; + } + + /** + * Initializes the Bluetooth Low Energy manager. A manager is used to communicate with profile's services. + * + * @return the manager that was created + */ + protected abstract BleManager initializeManager(); + + /** + * Restores the default UI before reconnecting + */ + protected abstract void setDefaultUI(); + + /** + * Returns the default device name resource id. The real device name is obtained when connecting to the device. This one is used when device has + * disconnected. + * + * @return the default device name resource id + */ + protected abstract int getDefaultDeviceName(); + + /** + * Returns the string resource id that will be shown in About box + * + * @return the about resource id + */ + protected abstract int getAboutTextId(); + + /** + * The UUID filter is used to filter out available devices that does not have such UUID in their advertisement packet. See also: + * {@link #isChangingConfigurations()}. + * + * @return the required UUID or null + */ + protected abstract UUID getFilterUUID(); + + /** + * Whether the scanner must search only for devices with GENERAL_DISCOVERABLE or LIMITER_DISCOVERABLE flag set. + * + * @return true if devices must have one of those flags set in their advertisement packets + */ + protected boolean isDiscoverableRequired() { + return true; + } + + /** + * Shows the scanner fragment. + * + * @param filter the UUID filter used to filter out available devices. The fragment will always show all bonded devices as there is no information about their + * services + * @param discoverableRequired true if devices must have GENERAL_DISCOVERABLE or LIMITED_DISCOVERABLE flags set in their advertisement packet + * @see #getFilterUUID() + */ + private void showDeviceScanningDialog(final UUID filter, final boolean discoverableRequired) { + runOnUiThread(new Runnable() { + @Override + public void run() { + final ScannerFragment dialog = ScannerFragment.getInstance(BleProfileExpandableListActivity.this, filter, discoverableRequired); + dialog.show(getFragmentManager(), "scan_fragment"); + } + }); + } + + private void ensureBLESupported() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show(); + finish(); + } + } + + protected boolean isBLEEnabled() { + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + final BluetoothAdapter adapter = bluetoothManager.getAdapter(); + return adapter != null && adapter.isEnabled(); + } + + protected void showBLEDialog() { + final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableIntent, REQUEST_ENABLE_BT); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java new file mode 100644 index 00000000..9cfc3bbc --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.profile; + +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.R; +import android.app.Service; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.Intent; +import android.net.Uri; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.support.v4.content.LocalBroadcastManager; +import android.widget.Toast; + +public abstract class BleProfileService extends Service implements BleManagerCallbacks { + @SuppressWarnings("unused") + private static final String TAG = "BleProfileService"; + + public static final String BROADCAST_CONNECTION_STATE = "no.nordicsemi.android.nrftoolbox.BROADCAST_CONNECTION_STATE"; + public static final String BROADCAST_SERVICES_DISCOVERED = "no.nordicsemi.android.nrftoolbox.BROADCAST_SERVICES_DISCOVERED"; + public static final String BROADCAST_BOND_STATE = "no.nordicsemi.android.nrftoolbox.BROADCAST_BOND_STATE"; + public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL"; + public static final String BROADCAST_ERROR = "no.nordicsemi.android.nrftoolbox.BROADCAST_ERROR"; + + /** The parameter passed when creating the service. Must contain the address of the sensor that we want to connect to */ + public static final String EXTRA_DEVICE_ADDRESS = "no.nordicsemi.android.nrftoolbox.EXTRA_DEVICE_ADDRESS"; + /** The key for the device name that is returned in {@link #BROADCAST_CONNECTION_STATE} with state {@link #STATE_CONNECTED}. */ + public static final String EXTRA_DEVICE_NAME = "no.nordicsemi.android.nrftoolbox.EXTRA_DEVICE_NAME"; + public static final String EXTRA_LOG_URI = "no.nordicsemi.android.nrftoolbox.EXTRA_LOG_URI"; + public static final String EXTRA_CONNECTION_STATE = "no.nordicsemi.android.nrftoolbox.EXTRA_CONNECTION_STATE"; + public static final String EXTRA_BOND_STATE = "no.nordicsemi.android.nrftoolbox.EXTRA_BOND_STATE"; + public static final String EXTRA_SERVICE_PRIMARY = "no.nordicsemi.android.nrftoolbox.EXTRA_SERVICE_PRIMARY"; + public static final String EXTRA_SERVICE_SECONDARY = "no.nordicsemi.android.nrftoolbox.EXTRA_SERVICE_SECONDARY"; + public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL"; + public static final String EXTRA_ERROR_MESSAGE = "no.nordicsemi.android.nrftoolbox.EXTRA_ERROR_MESSAGE"; + public static final String EXTRA_ERROR_CODE = "no.nordicsemi.android.nrftoolbox.EXTRA_ERROR_CODE"; + + public static final int STATE_LINK_LOSS = -1; + public static final int STATE_DISCONNECTED = 0; + public static final int STATE_CONNECTED = 1; + public static final int STATE_CONNECTING = 2; + public static final int STATE_DISCONNECTING = 3; + + private BleManager mBleManager; + private Handler mHandler; + + private boolean mConnected; + private String mDeviceAddress; + private String mDeviceName; + private ILogSession mLogSession; + + public class LocalBinder extends Binder { + /** + * Disconnects from the sensor. + */ + public final void disconnect() { + if (!mConnected) { + onDeviceDisconnected(); + return; + } + + // notify user about changing the state to DISCONNECTING + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING); + LocalBroadcastManager.getInstance(BleProfileService.this).sendBroadcast(broadcast); + + mBleManager.disconnect(); + } + + /** + * Returns the device address + * + * @return device address + */ + public String getDeviceAddress() { + return mDeviceAddress; + } + + /** + * Returns the device name + * + * @return the device name + */ + public String getDeviceName() { + return mDeviceName; + } + + /** + * Returns true if the device is connected to the sensor. + * + * @return true if device is connected to the sensor, false otherwise + */ + public boolean isConnected() { + return mConnected; + } + + /** + * Returns the log session that can be used to append log entries. The log session is created when the service is being created. The method returns null if the nRF Logger app was + * not installed. + * + * @return the log session + */ + protected ILogSession getLogSession() { + return mLogSession; + } + } + + @Override + public IBinder onBind(final Intent intent) { + return getBinder(); + } + + /** + * Returns the binder implementation. This must return class implementing the additional manager interface that may be used in the binded activity. + * + * @return the service binder + */ + protected LocalBinder getBinder() { + // default implementation returns the basic binder. You can overwrite the LocalBinder with your own, wider implementation + return new LocalBinder(); + } + + @Override + public boolean onUnbind(Intent intent) { + // we must allow to rebind to the same service + return true; + } + + @SuppressWarnings("unchecked") + @Override + public void onCreate() { + super.onCreate(); + + mHandler = new Handler(); + + // initialize the manager + mBleManager = initializeManager(); + mBleManager.setGattCallbacks(this); + } + + @SuppressWarnings("rawtypes") + protected abstract BleManager initializeManager(); + + @Override + public int onStartCommand(final Intent intent, final int flags, final int startId) { + if (intent == null || !intent.hasExtra(EXTRA_DEVICE_ADDRESS)) + throw new UnsupportedOperationException("No device address at EXTRA_DEVICE_ADDRESS key"); + + final Uri logUri = intent.getParcelableExtra(EXTRA_LOG_URI); + mLogSession = Logger.openSession(getApplicationContext(), logUri); + mDeviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS); + + Logger.i(mLogSession, "Service started"); + + // notify user about changing the state to CONNECTING + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING); + LocalBroadcastManager.getInstance(BleProfileService.this).sendBroadcast(broadcast); + + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); + final BluetoothAdapter adapter = bluetoothManager.getAdapter(); + final BluetoothDevice device = adapter.getRemoteDevice(mDeviceAddress); + mDeviceName = device.getName(); + onServiceStarted(); + + Logger.v(mLogSession, "Connecting..."); + mBleManager.connect(BleProfileService.this, device); + return START_REDELIVER_INTENT; + } + + /** + * Called when the service has been started. The device name and address are set. It nRF Logger is installed than logger was also initialized. + */ + protected void onServiceStarted() { + // empty default implementation + } + + @Override + public void onDestroy() { + super.onDestroy(); + + // shutdown the manager + mBleManager.closeBluetoothGatt(); + Logger.i(mLogSession, "Service destroyed"); + mBleManager = null; + mDeviceAddress = null; + mDeviceName = null; + mConnected = false; + mLogSession = null; + } + + @Override + public void onDeviceConnected() { + Logger.i(mLogSession, "Connected to " + mDeviceAddress); + mConnected = true; + + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED); + broadcast.putExtra(EXTRA_DEVICE_ADDRESS, mDeviceAddress); + broadcast.putExtra(EXTRA_DEVICE_NAME, mDeviceName); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceDisconnected() { + Logger.i(mLogSession, "Disconnected"); + mConnected = false; + mDeviceAddress = null; + mDeviceName = null; + + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + // user requested disconnection. We must stop the service + Logger.v(mLogSession, "Stopping service..."); + stopSelf(); + } + + @Override + public void onLinklossOccur() { + Logger.w(mLogSession, "Connection lost"); + mConnected = false; + + final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); + broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onServicesDiscovered(final boolean optionalServicesFound) { + Logger.i(mLogSession, "Services Discovered"); + Logger.v(mLogSession, "Primary service found"); + if (optionalServicesFound) + Logger.v(mLogSession, "Secondary service found"); + + final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED); + broadcast.putExtra(EXTRA_SERVICE_PRIMARY, true); + broadcast.putExtra(EXTRA_SERVICE_SECONDARY, optionalServicesFound); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDeviceNotSupported() { + Logger.i(mLogSession, "Services Discovered"); + Logger.w(mLogSession, "Device is not supported"); + + final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED); + broadcast.putExtra(EXTRA_SERVICE_PRIMARY, false); + broadcast.putExtra(EXTRA_SERVICE_SECONDARY, false); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + // no need for disconnecting, it will be disconnected by the manager automatically + } + + @Override + public void onBatteryValueReceived(final int value) { + Logger.i(mLogSession, "Battery level received: " + value + "%"); + + final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); + broadcast.putExtra(EXTRA_BATTERY_LEVEL, value); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onBondingRequired() { + Logger.v(mLogSession, "Bond state: Bonding..."); + showToast(R.string.bonding); + + final Intent broadcast = new Intent(BROADCAST_BOND_STATE); + broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onBonded() { + Logger.i(mLogSession, "Bond state: Bonded"); + showToast(R.string.bonded); + + final Intent broadcast = new Intent(BROADCAST_BOND_STATE); + broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onError(final String message, final int errorCode) { + Logger.e(mLogSession, message + " (" + errorCode + ")"); + + final Intent broadcast = new Intent(BROADCAST_ERROR); + broadcast.putExtra(EXTRA_ERROR_MESSAGE, message); + broadcast.putExtra(EXTRA_ERROR_CODE, errorCode); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + mBleManager.disconnect(); + stopSelf(); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId + * an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + mHandler.post(new Runnable() { + @Override + public void run() { + Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show(); + } + }); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message + * a message to be shown + */ + protected void showToast(final String message) { + mHandler.post(new Runnable() { + @Override + public void run() { + Toast.makeText(BleProfileService.this, message, Toast.LENGTH_SHORT).show(); + } + }); + } + + /** + * Returns the log session that can be used to append log entries. The method returns null if the nRF Logger app was not installed. It is safe to use logger when + * {@link #onServiceStarted()} has been called. + * + * @return the log session + */ + protected ILogSession getLogSession() { + return mLogSession; + } + + /** + * Returns the device address + * + * @return device address + */ + protected String getDeviceAddress() { + return mDeviceAddress; + } + + /** + * Returns the device name + * + * @return the device name + */ + protected String getDeviceName() { + return mDeviceName; + } + + /** + * Returns true if the device is connected to the sensor. + * + * @return true if device is connected to the sensor, false otherwise + */ + protected boolean isConnected() { + return mConnected; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java new file mode 100644 index 00000000..6000a21e --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java @@ -0,0 +1,645 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.profile; + +import android.app.Service; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothManager; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.net.Uri; +import android.os.Bundle; +import android.os.IBinder; +import android.support.v4.content.LocalBroadcastManager; +import android.support.v7.app.ActionBarActivity; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.util.UUID; + +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.LocalLogSession; +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.AppHelpFragment; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; + +/** + *

+ * The {@link BleProfileServiceReadyActivity} activity is designed to be the base class for profile activities that uses services in order to connect to the + * device. When user press CONNECT button a service is created and the activity binds to it. The service tries to connect to the service and notifies the + * activity using Local Broadcasts ({@link LocalBroadcastManager}). See {@link BleProfileService} for messages. If the device is not in range it will listen for + * it and connect when it become visible. The service exists until user will press DISCONNECT button. + *

+ *

+ * When user closes the activity (f.e. by pressing Back button) while being connected, the Service remains working. It's still connected to the device or still + * listens for it. When entering back to the activity, activity will to bind to the service and refresh UI. + *

+ */ +public abstract class BleProfileServiceReadyActivity extends ActionBarActivity implements + ScannerFragment.OnDeviceSelectedListener { + private static final String TAG = "BleProfileServiceReadyActivity"; + + private static final String DEVICE_NAME = "device_name"; + private static final String LOG_URI = "log_uri"; + protected static final int REQUEST_ENABLE_BT = 2; + + private E mService; + + private TextView mDeviceNameView; + private TextView mBatteryLevelView; + private Button mConnectButton; + + private ILogSession mLogSession; + private String mDeviceName; + + private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + + if (BleProfileService.BROADCAST_CONNECTION_STATE.equals(action)) { + final int state = intent.getIntExtra(BleProfileService.EXTRA_CONNECTION_STATE, BleProfileService.STATE_DISCONNECTED); + + switch (state) { + case BleProfileService.STATE_CONNECTED: { + mDeviceName = intent.getStringExtra(BleProfileService.EXTRA_DEVICE_NAME); + onDeviceConnected(); + break; + } + case BleProfileService.STATE_DISCONNECTED: { + onDeviceDisconnected(); + mDeviceName = null; + break; + } + case BleProfileService.STATE_LINK_LOSS: { + onLinklossOccur(); + break; + } + case BleProfileService.STATE_CONNECTING: + case BleProfileService.STATE_DISCONNECTING: + // current implementation does nothing in this states + default: + // there should be no other actions + break; + + } + } else if (BleProfileService.BROADCAST_SERVICES_DISCOVERED.equals(action)) { + final boolean primaryService = intent.getBooleanExtra(BleProfileService.EXTRA_SERVICE_PRIMARY, false); + final boolean secondaryService = intent.getBooleanExtra(BleProfileService.EXTRA_SERVICE_SECONDARY, false); + + if (primaryService) { + onServicesDiscovered(secondaryService); + } else { + onDeviceNotSupported(); + } + } else if (BleProfileService.BROADCAST_BOND_STATE.equals(action)) { + final int state = intent.getIntExtra(BleProfileService.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE); + switch (state) { + case BluetoothDevice.BOND_BONDING: + onBondingRequired(); + break; + case BluetoothDevice.BOND_BONDED: + onBonded(); + break; + } + } else if (BleProfileService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int value = intent.getIntExtra(BleProfileService.EXTRA_BATTERY_LEVEL, -1); + if (value > 0) + onBatteryValueReceived(value); + } else if (BleProfileService.BROADCAST_ERROR.equals(action)) { + final String message = intent.getStringExtra(BleProfileService.EXTRA_ERROR_MESSAGE); + final int errorCode = intent.getIntExtra(BleProfileService.EXTRA_ERROR_CODE, 0); + onError(message, errorCode); + } + } + }; + + private ServiceConnection mServiceConnection = new ServiceConnection() { + @SuppressWarnings("unchecked") + @Override + public void onServiceConnected(final ComponentName name, final IBinder service) { + final E bleService = mService = (E) service; + mLogSession = mService.getLogSession(); + Logger.d(mLogSession, "Activity binded to the service"); + onServiceBinded(bleService); + + // update UI + mDeviceName = bleService.getDeviceName(); + mDeviceNameView.setText(mDeviceName); + mConnectButton.setText(R.string.action_disconnect); + + // and notify user if device is connected + if (bleService.isConnected()) + onDeviceConnected(); + } + + @Override + public void onServiceDisconnected(final ComponentName name) { + Logger.d(mLogSession, "Activity disconnected from the service"); + mDeviceNameView.setText(getDefaultDeviceName()); + mConnectButton.setText(R.string.action_connect); + + mService = null; + mDeviceName = null; + mLogSession = null; + onServiceUnbinded(); + } + }; + + @Override + protected final void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ensureBLESupported(); + if (!isBLEEnabled()) { + showBLEDialog(); + } + + // Restore the old log session + if (savedInstanceState != null) { + final Uri logUri = savedInstanceState.getParcelable(LOG_URI); + mLogSession = Logger.openSession(getApplicationContext(), logUri); + } + + /* + * In this example we use the ProximityManager in the service. This class communicates with the service using local broadcasts. Final activity may bind + * to the Server to use its interface. + */ + onInitialize(savedInstanceState); + onCreateView(savedInstanceState); + onViewCreated(savedInstanceState); + + LocalBroadcastManager.getInstance(this).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onStart() { + super.onStart(); + + /* + * If the service has not been started before the following lines will not start it. However, if it's running, the Activity will be binded to it and + * notified via mServiceConnection. + */ + final Intent service = new Intent(this, getServiceClass()); + if (bindService(service, mServiceConnection, 0)) // we pass 0 as a flag so the service will not be created if not exists + Logger.d(mLogSession, "Binding to the service..."); // (* - see the comment below) + + /* + * * - When user exited the UARTActivity while being connected the log session is kept in the service. We may not get it before binding to it so in this + * case this event will not be logged. It will, however, be logged after the orientation changes. + */ + } + + @Override + protected void onStop() { + super.onStop(); + + try { + Logger.d(mLogSession, "Unbinding from the service..."); + unbindService(mServiceConnection); + mService = null; + + Logger.d(mLogSession, "Activity unbinded from the service"); + onServiceUnbinded(); + mDeviceName = null; + mLogSession = null; + } catch (final IllegalArgumentException e) { + // do nothing, we were not connected to the sensor + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + + LocalBroadcastManager.getInstance(this).unregisterReceiver(mCommonBroadcastReceiver); + } + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE); + intentFilter.addAction(BleProfileService.BROADCAST_SERVICES_DISCOVERED); + intentFilter.addAction(BleProfileService.BROADCAST_BOND_STATE); + intentFilter.addAction(BleProfileService.BROADCAST_BATTERY_LEVEL); + intentFilter.addAction(BleProfileService.BROADCAST_ERROR); + return intentFilter; + } + + /** + * Called when activity binds to the service. The parameter is the object returned in {@link Service#onBind(Intent)} method in your service. The method is + * called when device gets connected or is created while sensor was connected before. You may use the binder as a sensor interface. + */ + protected abstract void onServiceBinded(E binder); + + /** + * Called when activity unbinds from the service. You may no longer use this binder because the sensor was disconnected. This method is also called when you + * leave the activity being connected to the sensor in the background. + */ + protected abstract void onServiceUnbinded(); + + /** + * Returns the service class for sensor communication. The service class must derive from {@link BleProfileService} in order to operate with this class. + * + * @return the service class + */ + protected abstract Class getServiceClass(); + + /** + * Returns the service interface that may be used to communicate with the sensor. This will return null if the device is disconnected from the + * sensor. + * + * @return the service binder or null + */ + protected BleProfileService.LocalBinder getService() { + return mService; + } + + /** + * You may do some initialization here. This method is called from {@link #onCreate(Bundle)} before the view was created. + */ + protected void onInitialize(final Bundle savedInstanceState) { + // empty default implementation + } + + /** + * Called from {@link #onCreate(Bundle)}. This method should build the activity UI, f.e. using {@link #setContentView(int)}. Use to obtain references to + * views. Connect/Disconnect button, the device name view and battery level view are manager automatically. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. Note: Otherwise it is null. + */ + protected abstract void onCreateView(final Bundle savedInstanceState); + + /** + * Called after the view has been created. + * + * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. Note: Otherwise it is null. + */ + protected final void onViewCreated(final Bundle savedInstanceState) { + // set GUI + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + mConnectButton = (Button) findViewById(R.id.action_connect); + mDeviceNameView = (TextView) findViewById(R.id.device_name); + mBatteryLevelView = (TextView) findViewById(R.id.battery); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString(DEVICE_NAME, mDeviceName); + if (mLogSession != null) + outState.putParcelable(LOG_URI, mLogSession.getSessionUri()); + } + + @Override + protected void onRestoreInstanceState(final Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + mDeviceName = savedInstanceState.getString(DEVICE_NAME); + } + + @Override + public boolean onCreateOptionsMenu(final Menu menu) { + getMenuInflater().inflate(R.menu.help, menu); + return true; + } + + /** + * Use this method to handle menu actions other than home and about. + * + * @param itemId the menu item id + * @return true if action has been handled + */ + protected boolean onOptionsItemSelected(final int itemId) { + // Overwrite when using menu other than R.menu.help + return false; + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + final int id = item.getItemId(); + switch (id) { + case android.R.id.home: + onBackPressed(); + break; + case R.id.action_about: + final AppHelpFragment fragment = AppHelpFragment.getInstance(getAboutTextId()); + fragment.show(getFragmentManager(), "help_fragment"); + break; + default: + return onOptionsItemSelected(id); + } + return true; + } + + /** + * Called when user press CONNECT or DISCONNECT button. See layout files -> onClick attribute. + */ + public void onConnectClicked(final View view) { + if (isBLEEnabled()) { + if (mService == null) { + setDefaultUI(); + showDeviceScanningDialog(getFilterUUID(), isDiscoverableRequired()); + } else { + Logger.v(mLogSession, "Disconnecting..."); + mService.disconnect(); + } + } else { + showBLEDialog(); + } + } + + /** + * Returns the title resource id that will be used to create logger session. If 0 is returned (default) logger will not be used. + * + * @return the title resource id + */ + protected int getLoggerProfileTitle() { + return 0; + } + + /** + * This method may return the local log content provider authority if local log sessions are supported. + * + * @return local log session content provider URI + */ + protected Uri getLocalAuthorityLogger() { + return null; + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + final int titleId = getLoggerProfileTitle(); + if (titleId > 0) { + mLogSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name); + // If nRF Logger is not installed we may want to use local logger + if (mLogSession == null && getLocalAuthorityLogger() != null) { + mLogSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name); + } + } + mDeviceNameView.setText(mDeviceName = name); + mConnectButton.setText(R.string.action_disconnect); + + // The device may not be in the range but the service will try to connect to it if it reach it + Logger.d(mLogSession, "Creating service..."); + final Intent service = new Intent(this, getServiceClass()); + service.putExtra(BleProfileService.EXTRA_DEVICE_ADDRESS, device.getAddress()); + if (mLogSession != null) + service.putExtra(BleProfileService.EXTRA_LOG_URI, mLogSession.getSessionUri()); + startService(service); + Logger.d(mLogSession, "Binding to the service..."); + bindService(service, mServiceConnection, 0); + } + + @Override + public void onDialogCanceled() { + // do nothing + } + + /** + * Called when the device has been connected. This does not mean that the application may start communication. A service discovery will be handled + * automatically after this call. Service discovery may ends up with calling {@link #onServicesDiscovered(boolean)} or {@link #onDeviceNotSupported()} if required + * services have not been found. + */ + public void onDeviceConnected() { + mDeviceNameView.setText(mDeviceName); + mConnectButton.setText(R.string.action_disconnect); + } + + /** + * Called when the device has disconnected (when the callback returned + * {@link BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} with state DISCONNECTED. + */ + public void onDeviceDisconnected() { + mConnectButton.setText(R.string.action_connect); + mDeviceNameView.setText(getDefaultDeviceName()); + if (mBatteryLevelView != null) + mBatteryLevelView.setText(R.string.not_available); + + try { + Logger.d(mLogSession, "Unbinding from the service..."); + unbindService(mServiceConnection); + mService = null; + + Logger.d(mLogSession, "Activity unbinded from the service"); + onServiceUnbinded(); + mDeviceName = null; + mLogSession = null; + } catch (final IllegalArgumentException e) { + // do nothing. This should never happen but does... + } + } + + /** + * Some profiles may use this method to notify user that the link was lost. You must call this method in youe Ble Manager instead of + * {@link #onDeviceDisconnected()} while you discover disconnection not initiated by the user. + */ + public void onLinklossOccur() { + if (mBatteryLevelView != null) + mBatteryLevelView.setText(R.string.not_available); + } + + /** + * Called when service discovery has finished and primary services has been found. The device is ready to operate. This method is not called if the primary, + * mandatory services were not found during service discovery. For example in the Blood Pressure Monitor, a Blood Pressure service is a primary service and + * Intermediate Cuff Pressure service is a optional secondary service. Existence of battery service is not notified by this call. + * + * @param optionalServicesFound if true the secondary services were also found on the device. + */ + public abstract void onServicesDiscovered(final boolean optionalServicesFound); + + /** + * Called when the device has started bonding process + */ + public void onBondingRequired() { + // empty default implementation + } + + /** + * Called when the device has finished bonding process successfully + */ + public void onBonded() { + // empty default implementation + } + + /** + * Called when service discovery has finished but the main services were not found on the device. This may occur when connecting to bonded device that does + * not support required services. + */ + public void onDeviceNotSupported() { + showToast(R.string.not_supported); + } + + /** + * Called when battery value has been received from the device + * + * @param value the battery value in percent + */ + public void onBatteryValueReceived(final int value) { + if (mBatteryLevelView != null) + mBatteryLevelView.setText(getString(R.string.battery, value)); + } + + /** + * Called when a BLE error has occurred + * + * @param message the error message + * @param errorCode the error code + */ + public void onError(final String message, final int errorCode) { + DebugLogger.e(TAG, "Error occured: " + message + ", error code: " + errorCode); + showToast(message + " (" + errorCode + ")"); + + // refresh UI when connection failed + onDeviceDisconnected(); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param message a message to be shown + */ + protected void showToast(final String message) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(BleProfileServiceReadyActivity.this, message, Toast.LENGTH_LONG).show(); + } + }); + } + + /** + * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread + * + * @param messageResId an resource id of the message to be shown + */ + protected void showToast(final int messageResId) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(BleProfileServiceReadyActivity.this, messageResId, Toast.LENGTH_SHORT).show(); + } + }); + } + + /** + * Returns true if the device is connected. Services may not have been discovered yet. + */ + protected boolean isDeviceConnected() { + return mService != null; + } + + /** + * Returns the name of the device that the phone is currently connected to or was connected last time + */ + protected String getDeviceName() { + return mDeviceName; + } + + /** + * Restores the default UI before reconnecting + */ + protected abstract void setDefaultUI(); + + /** + * Returns the default device name resource id. The real device name is obtained when connecting to the device. This one is used when device has + * disconnected. + * + * @return the default device name resource id + */ + protected abstract int getDefaultDeviceName(); + + /** + * Returns the string resource id that will be shown in About box + * + * @return the about resource id + */ + protected abstract int getAboutTextId(); + + /** + * The UUID filter is used to filter out available devices that does not have such UUID in their advertisement packet. See also: + * {@link #isChangingConfigurations()}. + * + * @return the required UUID or null + */ + protected abstract UUID getFilterUUID(); + + /** + * Whether the scanner must search only for devices with GENERAL_DISCOVERABLE or LIMITER_DISCOVERABLE flag set. + * + * @return true if devices must have one of those flags set in their advertisement packets + */ + protected boolean isDiscoverableRequired() { + return true; + } + + /** + * Shows the scanner fragment. + * + * @param filter the UUID filter used to filter out available devices. The fragment will always show all bonded devices as there is no information about their + * services + * @param discoverableRequired true if devices must have GENERAL_DISCOVERABLE or LIMITED_DISCOVERABLE flags set in their advertisement packet + * @see #getFilterUUID() + */ + private void showDeviceScanningDialog(final UUID filter, final boolean discoverableRequired) { + final ScannerFragment dialog = ScannerFragment.getInstance(BleProfileServiceReadyActivity.this, filter, discoverableRequired); + dialog.show(getFragmentManager(), "scan_fragment"); + } + + /** + * Returns the log session. Log session is created when the device was selected using the {@link ScannerFragment} and released when user press DISCONNECT. + * + * @return the logger session or null + */ + public ILogSession getLogSession() { + return mLogSession; + } + + private void ensureBLESupported() { + if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) { + Toast.makeText(this, R.string.no_ble, Toast.LENGTH_LONG).show(); + finish(); + } + } + + protected boolean isBLEEnabled() { + final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); + final BluetoothAdapter adapter = bluetoothManager.getAdapter(); + return adapter != null && adapter.isEnabled(); + } + + protected void showBLEDialog() { + final Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); + startActivityForResult(enableIntent, REQUEST_ENABLE_BT); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/LinklossFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/LinklossFragment.java new file mode 100644 index 00000000..a374595d --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/LinklossFragment.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.proximity; + +import no.nordicsemi.android.nrftoolbox.R; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.os.Bundle; + +public class LinklossFragment extends DialogFragment { + private static final String ARG_NAME = "name"; + + private String mName; + + public static LinklossFragment getInstance(String name) { + final LinklossFragment fragment = new LinklossFragment(); + + final Bundle args = new Bundle(); + args.putString(ARG_NAME, name); + fragment.setArguments(args); + + return fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mName = getArguments().getString(ARG_NAME); + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()).setTitle(getString(R.string.app_name)).setMessage(getString(R.string.proximity_notification_linkloss_alert, mName)) + .setPositiveButton(R.string.ok, null).create(); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java new file mode 100644 index 00000000..7bb09ceb --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.proximity; + +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.app.FragmentManager; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.view.View; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.ImageView; + +public class ProximityActivity extends BleProfileServiceReadyActivity { + private static final String TAG = "ProximityActivity"; + + public static final String PREFS_GATT_SERVER_ENABLED = "prefs_gatt_server_enabled"; + private static final String IMMEDIATE_ALERT_STATUS = "immediate_alert_status"; + private boolean isImmediateAlertOn = false; + + private Button mFindMeButton; + private ImageView mLockImage; + private CheckBox mGattServerSwitch; + + @Override + protected void onCreateView(final Bundle savedInstanceState) { + setContentView(R.layout.activity_feature_proximity); + setGUI(); + } + + private void setGUI() { + mFindMeButton = (Button) findViewById(R.id.action_findme); + mLockImage = (ImageView) findViewById(R.id.imageLock); + mGattServerSwitch = (CheckBox) findViewById(R.id.option); + + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ProximityActivity.this); + mGattServerSwitch.setChecked(preferences.getBoolean(PREFS_GATT_SERVER_ENABLED, true)); + mGattServerSwitch.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { + preferences.edit().putBoolean(PREFS_GATT_SERVER_ENABLED, isChecked).commit(); + } + }); + } + + @Override + protected void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(IMMEDIATE_ALERT_STATUS, isImmediateAlertOn); + } + + @Override + protected void onRestoreInstanceState(final Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + isImmediateAlertOn = savedInstanceState.getBoolean(IMMEDIATE_ALERT_STATUS); + if (isDeviceConnected()) { + showOpenLock(); + + if (isImmediateAlertOn) { + showSilentMeOnButton(); + } + } + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.proximity_feature_title; + } + + @Override + protected void onServiceBinded(final ProximityService.ProximityBinder binder) { + // you may get the binder instance here + } + + @Override + protected void onServiceUnbinded() { + // you may release the binder instance here + } + + @Override + protected Class getServiceClass() { + return ProximityService.class; + } + + @Override + protected int getAboutTextId() { + return R.string.proximity_about_text; + } + + @Override + protected int getDefaultDeviceName() { + return R.string.proximity_default_name; + } + + @Override + protected UUID getFilterUUID() { + return ProximityManager.LINKLOSS_SERVICE_UUID; + } + + /** + * Callback of FindMe button on ProximityActivity + */ + public void onFindMeClicked(final View view) { + if (isBLEEnabled()) { + if (!isDeviceConnected()) { + // do nothing + } else if (!isImmediateAlertOn) { + showSilentMeOnButton(); + ((ProximityService.ProximityBinder) getService()).startImmediateAlert(); + isImmediateAlertOn = true; + } else { + showFindMeOnButton(); + ((ProximityService.ProximityBinder) getService()).stopImmediateAlert(); + isImmediateAlertOn = false; + } + } else { + showBLEDialog(); + } + } + + @Override + protected void setDefaultUI() { + runOnUiThread(new Runnable() { + @Override + public void run() { + mFindMeButton.setText(R.string.proximity_action_findme); + mLockImage.setImageResource(R.drawable.proximity_lock_closed); + } + }); + } + + @Override + public void onServicesDiscovered(boolean optionalServicesFound) { + // this may notify user or update views + } + + @Override + public void onDeviceConnected() { + super.onDeviceConnected(); + showOpenLock(); + mGattServerSwitch.setEnabled(false); + } + + @Override + public void onDeviceDisconnected() { + super.onDeviceDisconnected(); + showClosedLock(); + mGattServerSwitch.setEnabled(true); + } + + @Override + public void onBondingRequired() { + showClosedLock(); + } + + @Override + public void onBonded() { + showOpenLock(); + } + + @Override + public void onLinklossOccur() { + super.onLinklossOccur(); + showClosedLock(); + resetForLinkloss(); + + DebugLogger.w(TAG, "Linkloss occur"); + + String deviceName = getDeviceName(); + if (deviceName == null) { + deviceName = getString(R.string.proximity_default_name); + } + + showLinklossDialog(deviceName); + } + + private void resetForLinkloss() { + isImmediateAlertOn = false; + setDefaultUI(); + } + + private void showFindMeOnButton() { + mFindMeButton.setText(R.string.proximity_action_findme); + } + + private void showSilentMeOnButton() { + mFindMeButton.setText(R.string.proximity_action_silentme); + } + + private void showOpenLock() { + mFindMeButton.setEnabled(true); + mLockImage.setImageResource(R.drawable.proximity_lock_open); + } + + private void showClosedLock() { + mFindMeButton.setEnabled(false); + mLockImage.setImageResource(R.drawable.proximity_lock_closed); + } + + private void showLinklossDialog(final String name) { + try { + FragmentManager fm = getFragmentManager(); + LinklossFragment dialog = LinklossFragment.getInstance(name); + dialog.show(fm, "scan_fragment"); + } catch (final Exception e) { + // the activity must have been destroyed + } + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java new file mode 100644 index 00000000..381bc1b3 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.proximity; + +import java.util.List; +import java.util.UUID; + +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattServer; +import android.bluetooth.BluetoothGattServerCallback; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothManager; +import android.bluetooth.BluetoothProfile; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.media.AudioManager; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.util.Log; + +public class ProximityManager implements BleManager { + private final String TAG = "ProximityManager"; + + private ProximityManagerCallbacks mCallbacks; + private BluetoothGattServer mBluetoothGattServer; + private BluetoothGatt mBluetoothGatt; + private BluetoothDevice mDeviceToConnect; + private Context mContext; + private final Handler mHandler; + private ILogSession mLogSession; + private Ringtone mRingtoneNotification; + private Ringtone mRingtoneAlarm; + + public final static UUID IMMEIDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb"); + public final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb"); + + private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb"); + + private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); + private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); + + private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change"; + private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services"; + private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information"; + private final static String ERROR_WRITE_CHARACTERISTIC = "Error on writing characteristic"; + private final static String ERROR_READ_CHARACTERISTIC = "Error on reading characteristic"; + + private final static int HIGH_ALERT = 2; + private final static int NO_ALERT = 0; + + private BluetoothGattCharacteristic mAlertLevelCharacteristic, mLinklossCharacteristic, mBatteryCharacteristic; + + private boolean userDisconnectedFlag = false; + + public ProximityManager(Context context) { + initializeAlarm(context); + + mHandler = new Handler(); + + // Register bonding broadcast receiver + final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + context.registerReceiver(mBondingBroadcastReceiver, filter); + } + + private void openGattServer(Context context, BluetoothManager manager) { + mBluetoothGattServer = manager.openGattServer(context, mGattServerCallbacks); + } + + private void closeGattServer() { + if (mBluetoothGattServer != null) { + // mBluetoothGattServer.cancelConnection(mBluetoothGatt.getDevice()); // FIXME this method does not cancel the connection + mBluetoothGattServer.close(); // FIXME This method does not cause BluetoothGattServerCallback#onConnectionStateChange(newState=DISCONNECTED) to be called on Nexus phones. + mBluetoothGattServer = null; + } + } + + private void addImmediateAlertService() { + /* + * This method must be called in UI thread. It works fine on Nexus devices but if called from other thread (f.e. from onServiceAdded in gatt server callback) it hangs the app. + */ + BluetoothGattCharacteristic alertLevel = new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, + BluetoothGattCharacteristic.PERMISSION_WRITE); + alertLevel.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0); + BluetoothGattService immediateAlertService = new BluetoothGattService(IMMEIDIATE_ALERT_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY); + immediateAlertService.addCharacteristic(alertLevel); + mBluetoothGattServer.addService(immediateAlertService); + } + + private void addLinklossService() { + /* + * This method must be called in UI thread. It works fine on Nexus devices but if called from other thread (f.e. from onServiceAdded in gatt server callback) it hangs the app. + */ + BluetoothGattCharacteristic linklossAlertLevel = new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_WRITE + | BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_WRITE); + linklossAlertLevel.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0); + BluetoothGattService linklossService = new BluetoothGattService(LINKLOSS_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY); + linklossService.addCharacteristic(linklossAlertLevel); + mBluetoothGattServer.addService(linklossService); + } + + private final BluetoothGattServerCallback mGattServerCallbacks = new BluetoothGattServerCallback() { + @Override + public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { + DebugLogger.d(TAG, "[Proximity Server] onCharacteristicReadRequest " + device.getName()); + } + + @Override + public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, + byte[] value) { + DebugLogger.d(TAG, "[Proximity Server] onCharacteristicWriteRequest " + device.getName()); + final int receivedValue = value[0]; + if (receivedValue != NO_ALERT) { + Logger.i(mLogSession, "[Proximity Server] Immediate alarm request received: ON"); + playAlarm(); + } else { + Logger.i(mLogSession, "[Proximity Server] Immediate alarm request received: OFF"); + stopAlarm(); + } + } + + @Override + public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { + DebugLogger.d(TAG, "[Proximity Server] onConnectionStateChange " + device.getName() + " status: " + status + " new state: " + newState); + } + + @Override + public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) { + DebugLogger.d(TAG, "[Proximity Server] onDescriptorReadRequest " + device.getName()); + } + + @Override + public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { + DebugLogger.d(TAG, "[Proximity Server] onDescriptorWriteRequest " + device.getName()); + } + + @Override + public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) { + DebugLogger.d(TAG, "[Proximity Server] onExecuteWrite " + device.getName()); + } + + @Override + public void onServiceAdded(final int status, final BluetoothGattService service) { + DebugLogger.d(TAG, "[Proximity Server] onServiceAdded " + service.getUuid()); + + mHandler.post(new Runnable() { + @Override + public void run() { + // adding another service from callback thread fails on Samsung S4 with Android 4.3 + if (IMMEIDIATE_ALERT_SERVICE_UUID.equals(service.getUuid())) + addLinklossService(); + else { + DebugLogger.d(TAG, "[Proximity Server] Gatt server started"); + Logger.i(mLogSession, "[Proximity Server] Gatt server started"); + if (mBluetoothGatt == null) { + mBluetoothGatt = mDeviceToConnect.connectGatt(mContext, false, mGattCallback); + mDeviceToConnect = null; + } else { + mBluetoothGatt.connect(); + } + } + } + }); + } + }; + + /** + * Callbacks for activity {HTSActivity} that implements HTSManagerCallbacks interface activity use this method to register itself for receiving callbacks + */ + @Override + public void setGattCallbacks(ProximityManagerCallbacks callbacks) { + mCallbacks = callbacks; + } + + /** + * Sets the log session that can be used to log events + * + * @param logSession + */ + public void setLogger(ILogSession logSession) { + mLogSession = logSession; + } + + @Override + public void connect(Context context, BluetoothDevice device) { + mContext = context; + // save the device that we want to connect to + mDeviceToConnect = device; + + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); + if (preferences.getBoolean(ProximityActivity.PREFS_GATT_SERVER_ENABLED, true)) { + final BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); + try { + DebugLogger.d(TAG, "[Proximity Server] Starting Gatt server..."); + Logger.v(mLogSession, "[Proximity Server] Starting Gatt server..."); + openGattServer(context, bluetoothManager); + addImmediateAlertService(); + // the BluetoothGattServerCallback#onServiceAdded callback will proceed further operations + } catch (final Exception e) { + // On Nexus 4&7 with Android 4.4 (build KRT16S) sometimes creating Gatt Server fails. There is a Null Pointer Exception thrown from addCharacteristic method. + Logger.e(mLogSession, "[Proximity Server] Gatt server failed to start"); + Log.e(TAG, "Creating Gatt Server failed", e); + } + } else { + if (mBluetoothGatt == null) { + mBluetoothGatt = mDeviceToConnect.connectGatt(context, false, mGattCallback); + mDeviceToConnect = null; + } else { + mBluetoothGatt.connect(); + } + } + } + + @Override + public void disconnect() { + if (mBluetoothGatt != null) { + userDisconnectedFlag = true; + mBluetoothGatt.disconnect(); + stopAlarm(); + closeGattServer(); + } + } + + private void initializeAlarm(Context context) { + final Uri alarmUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); + mRingtoneAlarm = RingtoneManager.getRingtone(context, alarmUri); + mRingtoneAlarm.setStreamType(AudioManager.STREAM_ALARM); + + final Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + mRingtoneNotification = RingtoneManager.getRingtone(context, notification); + } + + private void playNotification() { + DebugLogger.d(TAG, "playNotification"); + mRingtoneNotification.play(); + } + + private void playAlarm() { + DebugLogger.d(TAG, "playAlarm"); + final AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + am.setStreamVolume(AudioManager.STREAM_ALARM, am.getStreamMaxVolume(AudioManager.STREAM_ALARM), AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); + mRingtoneAlarm.play(); + } + + private void stopAlarm() { + DebugLogger.d(TAG, "stopAlarm"); + mRingtoneAlarm.stop(); + } + + /** + * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc + */ + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + DebugLogger.d(TAG, "Device connected"); + mBluetoothGatt.discoverServices(); + //This will send callback to ProximityActivity when device get connected + mCallbacks.onDeviceConnected(); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + DebugLogger.d(TAG, "Device disconnected"); + if (userDisconnectedFlag) { + mCallbacks.onDeviceDisconnected(); + userDisconnectedFlag = false; + } else { + playNotification(); + mCallbacks.onLinklossOccur(); + } + } + } else { + mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status); + } + } + + @Override + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + final List services = gatt.getServices(); + for (BluetoothGattService service : services) { + if (service.getUuid().equals(IMMEIDIATE_ALERT_SERVICE_UUID)) { + DebugLogger.d(TAG, "Immediate Alert service is found"); + mAlertLevelCharacteristic = service.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID); + } else if (service.getUuid().equals(LINKLOSS_SERVICE_UUID)) { + DebugLogger.d(TAG, "Linkloss service is found"); + mLinklossCharacteristic = service.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID); + } else if (service.getUuid().equals(BATTERY_SERVICE_UUID)) { + DebugLogger.d(TAG, "Battery service is found"); + mBatteryCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID); + } + } + if (mLinklossCharacteristic == null) { + mCallbacks.onDeviceNotSupported(); + gatt.disconnect(); + } else { + mCallbacks.onServicesDiscovered(mAlertLevelCharacteristic != null); + writeLinklossAlertLevel(HIGH_ALERT); + } + } else { + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (characteristic.getUuid().equals(BATTERY_LEVEL_CHARACTERISTIC_UUID)) { + int batteryValue = characteristic.getValue()[0]; + mCallbacks.onBatteryValueReceived(batteryValue); + } + } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { + if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { + DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); + mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status); + } + } else { + mCallbacks.onError(ERROR_READ_CHARACTERISTIC, status); + } + } + + @Override + public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (characteristic.getUuid().equals(ALERT_LEVEL_CHARACTERISTIC_UUID)) { + if (mBatteryCharacteristic != null) { + readBatteryLevel(); + } + } + } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { + if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { + DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); + mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status); + } + } else { + mCallbacks.onError(ERROR_WRITE_CHARACTERISTIC, status); + } + } + }; + + private final BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); + final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1); + + // skip other devices + if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) + return; + + DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState); + + if (bondState == BluetoothDevice.BOND_BONDING) { + mCallbacks.onBondingRequired(); + return; + } + if (bondState == BluetoothDevice.BOND_BONDED) { + if (mLinklossCharacteristic != null) { + writeLinklossAlertLevel(HIGH_ALERT); + } + mCallbacks.onBonded(); + } + } + }; + + private void readBatteryLevel() { + if (mBatteryCharacteristic != null) { + DebugLogger.d(TAG, "reading battery characteristic"); + mBluetoothGatt.readCharacteristic(mBatteryCharacteristic); + } else { + DebugLogger.w(TAG, "Battery Level Characteristic is null"); + } + } + + @SuppressWarnings("unused") + private void readLinklossAlertLevel() { + if (mLinklossCharacteristic != null) { + DebugLogger.d(TAG, "reading linkloss alert level characteristic"); + mBluetoothGatt.readCharacteristic(mLinklossCharacteristic); + } else { + DebugLogger.w(TAG, "Linkloss Alert Level Characteristic is null"); + } + } + + private void writeLinklossAlertLevel(int alertLevel) { + if (mLinklossCharacteristic != null) { + DebugLogger.d(TAG, "writing linkloss alert level characteristic"); + mLinklossCharacteristic.setValue(alertLevel, BluetoothGattCharacteristic.FORMAT_UINT8, 0); + mBluetoothGatt.writeCharacteristic(mLinklossCharacteristic); + } else { + DebugLogger.w(TAG, "Linkloss Alert Level Characteristic is not found"); + } + } + + public void writeImmediateAlertOn() { + if (mAlertLevelCharacteristic != null) { + DebugLogger.d(TAG, "writing Immediate alert characteristic On"); + mAlertLevelCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); + mAlertLevelCharacteristic.setValue(HIGH_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0); + mBluetoothGatt.writeCharacteristic(mAlertLevelCharacteristic); + } else { + DebugLogger.w(TAG, "Immediate Alert Level Characteristic is not found"); + } + } + + public void writeImmediateAlertOff() { + if (mAlertLevelCharacteristic != null) { + DebugLogger.d(TAG, "writing Immediate alert characteristic Off"); + mAlertLevelCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); + mAlertLevelCharacteristic.setValue(NO_ALERT, BluetoothGattCharacteristic.FORMAT_UINT8, 0); + mBluetoothGatt.writeCharacteristic(mAlertLevelCharacteristic); + } else { + DebugLogger.w(TAG, "Immediate Alert Level Characteristic is not found"); + } + } + + @Override + public void closeBluetoothGatt() { + try { + mContext.unregisterReceiver(mBondingBroadcastReceiver); + } catch (Exception e) { + // the receiver must have been not registered or unregistered before + } + if (mBluetoothGatt != null) { + mBluetoothGatt.close(); + mBluetoothGatt = null; + } + if (mBluetoothGattServer != null) { + mBluetoothGattServer.close(); + mBluetoothGattServer = null; + } + mCallbacks = null; + mLogSession = null; + mRingtoneAlarm = mRingtoneNotification = null; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java new file mode 100644 index 00000000..1e0e84e5 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.proximity; + +import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; + +public interface ProximityManagerCallbacks extends BleManagerCallbacks { + // no additional methods +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java new file mode 100644 index 00000000..b7eec6b7 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.proximity; + +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.FeaturesActivity; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.IBinder; + +public class ProximityService extends BleProfileService implements ProximityManagerCallbacks { + @SuppressWarnings("unused") + private static final String TAG = "ProximityService"; + + private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.proximity.ACTION_DISCONNECT"; + + private ProximityManager mProximityManager; + private boolean mBinded; + + private final static int NOTIFICATION_ID = 100; + private final static int OPEN_ACTIVITY_REQ = 0; + private final static int DISCONNECT_REQ = 1; + + private final LocalBinder mBinder = new ProximityBinder(); + + /** + * This local binder is an interface for the binded activity to operate with the proximity sensor + */ + public class ProximityBinder extends LocalBinder { + public void startImmediateAlert() { + Logger.i(getLogSession(), "[Proximity] Immediate alarm request: ON"); + mProximityManager.writeImmediateAlertOn(); + } + + public void stopImmediateAlert() { + Logger.i(getLogSession(), "[Proximity] Immediate alarm request: OFF"); + mProximityManager.writeImmediateAlertOff(); + } + } + + @Override + protected LocalBinder getBinder() { + return mBinder; + } + + @Override + protected BleManager initializeManager() { + return mProximityManager = new ProximityManager(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DISCONNECT); + registerReceiver(mDisconnectActionBroadcastReceiver, filter); + } + + @Override + public void onDestroy() { + // when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService + cancelNotification(); + unregisterReceiver(mDisconnectActionBroadcastReceiver); + + super.onDestroy(); + } + + @Override + public IBinder onBind(final Intent intent) { + mBinded = true; + return super.onBind(intent); + } + + @Override + public void onRebind(final Intent intent) { + mBinded = true; + // when the activity rebinds to the service, remove the notification + cancelNotification(); + } + + @Override + public boolean onUnbind(final Intent intent) { + mBinded = false; + // when the activity closes we need to show the notification that user is connected to the sensor + createNotifcation(R.string.proximity_notification_connected_message, 0); + return super.onUnbind(intent); + } + + @Override + protected void onServiceStarted() { + // logger is now available. Assign it to the manager + mProximityManager.setLogger(getLogSession()); + } + + @Override + public void onLinklossOccur() { + super.onLinklossOccur(); + + if (!mBinded) { + // when the activity closes we need to show the notification that user is connected to the sensor + createNotifcation(R.string.proximity_notification_linkloss_alert, Notification.DEFAULT_ALL); + } + } + + /** + * Creates the notification + * + * @param messageResId + * message resource id. The message must have one String parameter,
+ * f.e. <string name="name">%s is connected</string> + * @param defaults + * signals that will be used to notify the user + */ + private void createNotifcation(final int messageResId, final int defaults) { + final Intent parentIntent = new Intent(this, FeaturesActivity.class); + parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final Intent targetIntent = new Intent(this, ProximityActivity.class); + + final Intent disconnect = new Intent(ACTION_DISCONNECT); + final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT); + + // both activities above have launchMode="singleTask" in the AndoridManifest.xml file, so if the task is already running, it will be resumed + final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT); + final Notification.Builder builder = new Notification.Builder(this).setContentIntent(pendingIntent); + builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); + builder.setSmallIcon(R.drawable.ic_stat_notify_proximity); + builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); + builder.addAction(R.drawable.ic_action_bluetooth, getString(R.string.proximity_notification_action_disconnect), disconnectAction); + + final Notification notification = builder.build(); + final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID, notification); + } + + /** + * Cancels the existing notification. If there is no active notification this method does nothing + */ + private void cancelNotification() { + final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + nm.cancel(NOTIFICATION_ID); + } + + /** + * This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification. + */ + private BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + Logger.i(getLogSession(), "[Proximity] Disconnect action pressed"); + if (isConnected()) + getBinder().disconnect(); + else + stopSelf(); + } + }; +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCActivity.java new file mode 100644 index 00000000..6d52aab5 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCActivity.java @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.rsc; + +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; +import android.widget.TextView; + +public class RSCActivity extends BleProfileServiceReadyActivity { + private TextView mSpeedView; + private TextView mCadenceView; + private TextView mDistanceView; + private TextView mDistanceUnitView; + private TextView mTotalDistanceView; + private TextView mStridesCountView; + private TextView mActivityView; + + @Override + protected void onCreateView(final Bundle savedInstanceState) { + setContentView(R.layout.activity_feature_rsc); + setGui(); + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + private void setGui() { + mSpeedView = (TextView) findViewById(R.id.speed); + mCadenceView = (TextView) findViewById(R.id.cadence); + mDistanceView = (TextView) findViewById(R.id.distance); + mDistanceUnitView = (TextView) findViewById(R.id.distance_unit); + mTotalDistanceView = (TextView) findViewById(R.id.total_distance); + mStridesCountView = (TextView) findViewById(R.id.strides); + mActivityView = (TextView) findViewById(R.id.activity); + } + + @Override + protected void setDefaultUI() { + mSpeedView.setText(R.string.not_available_value); + mCadenceView.setText(R.string.not_available_value); + mDistanceView.setText(R.string.not_available_value); + mDistanceUnitView.setText(R.string.rsc_distance_unit_m); + mTotalDistanceView.setText(R.string.not_available_value); + mStridesCountView.setText(R.string.not_available_value); + mActivityView.setText(R.string.not_available); + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.rsc_feature_title; + } + + @Override + protected int getDefaultDeviceName() { + return R.string.rsc_default_name; + } + + @Override + protected int getAboutTextId() { + return R.string.rsc_about_text; + } + + @Override + protected Class getServiceClass() { + return RSCService.class; + } + + @Override + protected UUID getFilterUUID() { + return RSCManager.RUNNING_SPEED_AND_CADENCE_SERVICE_UUID; + } + + @Override + protected void onServiceBinded(final RSCService.RSCBinder binder) { + // not used + } + + @Override + protected void onServiceUnbinded() { + // not used + } + + @Override + public void onServicesDiscovered(final boolean optionalServicesFound) { + // not used + } + + private void onMeasurementReceived(final float speed, final int cadence, final float totalDistance, final int activity) { + mSpeedView.setText(String.format("%.1f", speed)); + mCadenceView.setText(String.format("%d", cadence)); + if (totalDistance == RSCManagerCallbacks.NOT_AVAILABLE) { + mTotalDistanceView.setText(R.string.not_available); + } else { + mTotalDistanceView.setText(String.format("%.2f", totalDistance / 10000.0f)); // 1km in dm + } + + mActivityView.setText(activity == RSCManagerCallbacks.ACTIVITY_RUNNING ? R.string.rsc_running : R.string.rsc_walking); + } + + private void onStripsesUpdate(final float distance, final int strides) { + if (distance == RSCManagerCallbacks.NOT_AVAILABLE) { + mDistanceView.setText(R.string.not_available); + mDistanceUnitView.setText(R.string.rsc_distance_unit_m); + } else if (distance < 100000) { // 1 km in cm + mDistanceView.setText(String.format("%.0f", distance / 100.0f)); + mDistanceUnitView.setText(R.string.rsc_distance_unit_m); + } else { + mDistanceView.setText(String.format("%.2f", distance / 100000.0f)); + mDistanceUnitView.setText(R.string.rsc_distance_unit_km); + } + + mStridesCountView.setText(String.valueOf(strides)); + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + + if (RSCService.BROADCAST_RSC_MEASUREMENT.equals(action)) { + final float speed = intent.getFloatExtra(RSCService.EXTRA_SPEED, 0.0f); + final int cadence = intent.getIntExtra(RSCService.EXTRA_CADENCE, 0); + final float totalDistance = intent.getFloatExtra(RSCService.EXTRA_TOTAL_DISTANCE, RSCManagerCallbacks.NOT_AVAILABLE); + final int activity = intent.getIntExtra(RSCService.EXTRA_ACTIVITY, RSCManagerCallbacks.ACTIVITY_WALKING); + // Update GUI + onMeasurementReceived(speed, cadence, totalDistance, activity); + } else if (RSCService.BROADCAST_STRIDES_UPDATE.equals(action)) { + final int strides = intent.getIntExtra(RSCService.EXTRA_STRIDES, 0); + final float distance = intent.getFloatExtra(RSCService.EXTRA_DISTANCE, 0); + // Update GUI + onStripsesUpdate(distance, strides); + } + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(RSCService.BROADCAST_RSC_MEASUREMENT); + intentFilter.addAction(RSCService.BROADCAST_STRIDES_UPDATE); + return intentFilter; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java new file mode 100644 index 00000000..9b27a330 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java @@ -0,0 +1,279 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.rsc; + +import java.util.List; +import java.util.UUID; + +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothProfile; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +public class RSCManager implements BleManager { + private static final String TAG = "RSCManager"; + + private RSCManagerCallbacks mCallbacks; + private BluetoothGatt mBluetoothGatt; + private Context mContext; + private ILogSession mLogSession; + + private static final byte INSTANTANEOUS_STRIDE_LENGTH_PRESENT = 0x01; // 1 bit + private static final byte TOTAL_DISTANCE_PRESENT = 0x02; // 1 bit + private static final byte WALKING_OR_RUNNING_STATUS_BITS = 0x04; // 1 bit + + public final static UUID RUNNING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001814-0000-1000-8000-00805f9b34fb"); + /** Running Speed and Cadence Measurement characteristic */ + private static final UUID RSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A53-0000-1000-8000-00805f9b34fb"); + + private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); + /** Battery Level characteristic */ + private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); + /** Client configuration descriptor that will allow us to enable notifications and indications */ + private static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + + private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change"; + private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services"; + private final static String ERROR_AUTH_ERROR_WHILE_BONDED = "Phone has lost bonding information"; + private final static String ERROR_WRITE_CHARACTERISTIC = "Error on writing characteristic"; + private final static String ERROR_READ_CHARACTERISTIC = "Error on reading characteristic"; + + private BluetoothGattCharacteristic mRSCMeasurementCharacteristic, mBatteryCharacteristic; + + public RSCManager(final Context context) { + // Register bonding broadcast receiver + final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED); + context.registerReceiver(mBondingBroadcastReceiver, filter); + } + + @Override + public void setGattCallbacks(final RSCManagerCallbacks callbacks) { + mCallbacks = callbacks; + } + + public void setLogger(final ILogSession session) { + mLogSession = session; + } + + @Override + public void connect(final Context context, final BluetoothDevice device) { + mContext = context; + + Logger.i(mLogSession, "[RSC] Gatt server started"); + if (mBluetoothGatt == null) { + mBluetoothGatt = device.connectGatt(mContext, true, mGattCallback); + } else { + mBluetoothGatt.connect(); + } + } + + @Override + public void disconnect() { + if (mBluetoothGatt != null) { + mBluetoothGatt.disconnect(); + } + } + + /** + * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc + */ + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + DebugLogger.d(TAG, "Device connected"); + mBluetoothGatt.discoverServices(); + //This will send callback to RSCActivity when device get connected + mCallbacks.onDeviceConnected(); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + DebugLogger.d(TAG, "Device disconnected"); + + // TODO It should check whether the user has requested disconnection or was it link loss. On Samsung S4 the DevKit reconnects itself just after linkloss but the Service is already dead. + mCallbacks.onDeviceDisconnected(); + closeBluetoothGatt(); + } + } else { + mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status); + } + } + + @Override + public void onServicesDiscovered(final BluetoothGatt gatt, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + final List services = gatt.getServices(); + for (BluetoothGattService service : services) { + if (service.getUuid().equals(RUNNING_SPEED_AND_CADENCE_SERVICE_UUID)) { + DebugLogger.d(TAG, "Running Speed and Cadence service is found"); + mRSCMeasurementCharacteristic = service.getCharacteristic(RSC_MEASUREMENT_CHARACTERISTIC_UUID); + } else if (service.getUuid().equals(BATTERY_SERVICE_UUID)) { + DebugLogger.d(TAG, "Battery service is found"); + mBatteryCharacteristic = service.getCharacteristic(BATTERY_LEVEL_CHARACTERISTIC_UUID); + } + } + if (mRSCMeasurementCharacteristic == null) { + mCallbacks.onDeviceNotSupported(); + gatt.disconnect(); + } else { + mCallbacks.onServicesDiscovered(false /* more characteristics not supported */); + + // We have discovered services, let's start notifications and indications, one by one: battery, icp (if exists), bpm + if (mBatteryCharacteristic != null) { + readBatteryLevel(gatt); + } else { + enableRSCMeasurementNotification(gatt); + } + } + } else { + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onCharacteristicRead(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (characteristic.getUuid().equals(BATTERY_LEVEL_CHARACTERISTIC_UUID)) { + int batteryValue = characteristic.getValue()[0]; + mCallbacks.onBatteryValueReceived(batteryValue); + + enableRSCMeasurementNotification(gatt); + } + } else if (status == BluetoothGatt.GATT_INSUFFICIENT_AUTHENTICATION) { + if (gatt.getDevice().getBondState() != BluetoothDevice.BOND_NONE) { + DebugLogger.w(TAG, ERROR_AUTH_ERROR_WHILE_BONDED); + mCallbacks.onError(ERROR_AUTH_ERROR_WHILE_BONDED, status); + } + } else { + mCallbacks.onError(ERROR_READ_CHARACTERISTIC, status); + } + } + + @Override + public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { + // Decode the new data + int offset = 0; + final int flags = characteristic.getValue()[offset]; // 1 byte + offset += 1; + + final boolean islmPresent = (flags & INSTANTANEOUS_STRIDE_LENGTH_PRESENT) > 0; + final boolean tdPreset = (flags & TOTAL_DISTANCE_PRESENT) > 0; + final boolean running = (flags & WALKING_OR_RUNNING_STATUS_BITS) > 0; + + final float instantaneousSpeed = (float) characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset) / 256.0f * 3.6f; // 1/256 m/s in km/h + offset += 2; + + final int instantaneousCadence = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + offset += 1; + + float instantaneousStrideLength = RSCManagerCallbacks.NOT_AVAILABLE; + if (islmPresent) { + instantaneousStrideLength = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, offset); + offset += 2; + } + + float totalDistance = RSCManagerCallbacks.NOT_AVAILABLE; + if (tdPreset) { + totalDistance = (float) characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, offset) / 10.0f; + offset += 4; + } + + // Notify listener about the new measurement + mCallbacks.onMeasurementReceived(instantaneousSpeed, instantaneousCadence, totalDistance, instantaneousStrideLength, running ? RSCManagerCallbacks.ACTIVITY_RUNNING + : RSCManagerCallbacks.ACTIVITY_WALKING); + } + }; + + private BroadcastReceiver mBondingBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + final BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); + final int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, -1); + final int previousBondState = intent.getIntExtra(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, -1); + + // skip other devices + if (!device.getAddress().equals(mBluetoothGatt.getDevice().getAddress())) + return; + + DebugLogger.i(TAG, "Bond state changed for: " + device.getName() + " new state: " + bondState + " previous: " + previousBondState); + + if (bondState == BluetoothDevice.BOND_BONDING) { + mCallbacks.onBondingRequired(); + return; + } + if (bondState == BluetoothDevice.BOND_BONDED) { + mCallbacks.onBonded(); + } + } + }; + + public void readBatteryLevel() { + readBatteryLevel(mBluetoothGatt); + } + + private void readBatteryLevel(final BluetoothGatt gatt) { + if (mBatteryCharacteristic != null) { + DebugLogger.d(TAG, "reading battery characteristic"); + gatt.readCharacteristic(mBatteryCharacteristic); + } else { + DebugLogger.w(TAG, "Battery Level Characteristic is null"); + } + } + + /** + * Enabling notification on RSC Measurement Characteristic + */ + private void enableRSCMeasurementNotification(final BluetoothGatt gatt) { + DebugLogger.d(TAG, "enableIntermediateCuffPressureNotification()"); + gatt.setCharacteristicNotification(mRSCMeasurementCharacteristic, true); + final BluetoothGattDescriptor descriptor = mRSCMeasurementCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + gatt.writeDescriptor(descriptor); + } + + @Override + public void closeBluetoothGatt() { + try { + mContext.unregisterReceiver(mBondingBroadcastReceiver); + } catch (Exception e) { + // the receiver must have been not registered or unregistered before + } + if (mBluetoothGatt != null) { + mBluetoothGatt.close(); + mBluetoothGatt = null; + } + mCallbacks = null; + mLogSession = null; + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java new file mode 100644 index 00000000..6fe5d8bf --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.rsc; + +import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; + +public interface RSCManagerCallbacks extends BleManagerCallbacks { + public static final int NOT_AVAILABLE = -1; + public static final int ACTIVITY_WALKING = 0; + public static final int ACTIVITY_RUNNING = 1; + + public void onMeasurementReceived(float speed, int cadence, float distance, float strideLen, int activity); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java new file mode 100644 index 00000000..0153928c --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.rsc; + +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.FeaturesActivity; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.IBinder; +import android.support.v4.content.LocalBroadcastManager; + +public class RSCService extends BleProfileService implements RSCManagerCallbacks { + private static final String TAG = "RSCService"; + + public static final String BROADCAST_RSC_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.rsc.BROADCAST_RSC_MEASUREMENT"; + public static final String EXTRA_SPEED = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_SPEED"; + public static final String EXTRA_CADENCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_CADENCE"; + public static final String EXTRA_TOTAL_DISTANCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_TOTAL_DISTANCE"; + public static final String EXTRA_ACTIVITY = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_ACTIVITY"; + + public static final String BROADCAST_STRIDES_UPDATE = "no.nordicsemi.android.nrftoolbox.rsc.BROADCAST_STRIDES_UPDATE"; + public static final String EXTRA_STRIDES = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_STRIDES"; + public static final String EXTRA_DISTANCE = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_DISTANCE"; + + private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.rsc.ACTION_DISCONNECT"; + + private RSCManager mManager; + private boolean mBinded; + + /** The last value of a cadence */ + private float mCadence; + /** Trip distance in cm */ + private float mDistance; + /** Stride length in cm */ + private float mStrideLength; + /** Number of steps in the trip */ + private int mStepsNumber; + private boolean mTaskInProgress; + private final Handler mHandler = new Handler(); + + private final static int NOTIFICATION_ID = 200; + private final static int OPEN_ACTIVITY_REQ = 0; + private final static int DISCONNECT_REQ = 1; + + private final LocalBinder mBinder = new RSCBinder(); + + /** + * This local binder is an interface for the binded activity to operate with the RSC sensor + */ + public class RSCBinder extends LocalBinder { + // empty + } + + @Override + protected LocalBinder getBinder() { + return mBinder; + } + + @Override + protected BleManager initializeManager() { + return mManager = new RSCManager(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DISCONNECT); + registerReceiver(mDisconnectActionBroadcastReceiver, filter); + } + + @Override + public void onDestroy() { + // when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService + cancelNotification(); + unregisterReceiver(mDisconnectActionBroadcastReceiver); + + super.onDestroy(); + } + + @Override + public IBinder onBind(final Intent intent) { + mBinded = true; + return super.onBind(intent); + } + + @Override + public void onRebind(final Intent intent) { + mBinded = true; + // when the activity rebinds to the service, remove the notification + cancelNotification(); + + // read the battery level when back in the Activity + if (isConnected()) + mManager.readBatteryLevel(); + } + + @Override + public boolean onUnbind(final Intent intent) { + mBinded = false; + // when the activity closes we need to show the notification that user is connected to the sensor + createNotifcation(R.string.rsc_notification_connected_message, 0); + return super.onUnbind(intent); + } + + @Override + protected void onServiceStarted() { + // logger is now available. Assign it to the manager + mManager.setLogger(getLogSession()); + } + + private final Runnable mUpdateStridesTask = new Runnable() { + @Override + public void run() { + if (!isConnected()) + return; + + mStepsNumber++; + mDistance += mStrideLength; + final Intent broadcast = new Intent(BROADCAST_STRIDES_UPDATE); + broadcast.putExtra(EXTRA_STRIDES, mStepsNumber); + broadcast.putExtra(EXTRA_DISTANCE, mDistance); + LocalBroadcastManager.getInstance(RSCService.this).sendBroadcast(broadcast); + + if (mCadence > 0) { + final long interval = (long) (1000.0f * 65.0f / mCadence); // 60s + 5s for calibration in milliseconds + mHandler.postDelayed(mUpdateStridesTask, interval); + } else { + mTaskInProgress = false; + } + } + }; + + @Override + public void onMeasurementReceived(final float speed, final int cadence, final float totalDistance, final float strideLen, final int activity) { + final Intent broadcast = new Intent(BROADCAST_RSC_MEASUREMENT); + broadcast.putExtra(EXTRA_SPEED, speed); + broadcast.putExtra(EXTRA_CADENCE, cadence); + broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance); + broadcast.putExtra(EXTRA_ACTIVITY, activity); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + // Start strides counter if not in progress + mCadence = cadence; + mStrideLength = strideLen; + if (!mTaskInProgress && cadence > 0) { + mTaskInProgress = true; + + final long interval = (long) (1000.0f * 65.0f / mCadence); // 60s + 5s for calibration in milliseconds + mHandler.postDelayed(mUpdateStridesTask, interval); + } + } + + /** + * Creates the notification + * + * @param messageResIdthe + * message resource id. The message must have one String parameter,
+ * f.e. <string name="name">%s is connected</string> + * @param defaults + * signals that will be used to notify the user + */ + private void createNotifcation(final int messageResId, final int defaults) { + final Intent parentIntent = new Intent(this, FeaturesActivity.class); + parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final Intent targetIntent = new Intent(this, RSCActivity.class); + + final Intent disconnect = new Intent(ACTION_DISCONNECT); + final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT); + + // both activities above have launchMode="singleTask" in the AndoridManifest.xml file, so if the task is already running, it will be resumed + final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT); + final Notification.Builder builder = new Notification.Builder(this).setContentIntent(pendingIntent); + builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); + builder.setSmallIcon(R.drawable.ic_stat_notify_rsc); + builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); + builder.addAction(R.drawable.ic_action_bluetooth, getString(R.string.rsc_notification_action_disconnect), disconnectAction); + + final Notification notification = builder.build(); + final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID, notification); + } + + /** + * Cancels the existing notification. If there is no active notification this method does nothing + */ + private void cancelNotification() { + final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + nm.cancel(NOTIFICATION_ID); + } + + /** + * This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification. + */ + private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + Logger.i(getLogSession(), "[RSC] Disconnect action pressed"); + if (isConnected()) + getBinder().disconnect(); + else + stopSelf(); + } + }; + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java new file mode 100644 index 00000000..d4dfd381 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.scanner; + +import java.util.ArrayList; + +import no.nordicsemi.android.nrftoolbox.R; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +/** + * DeviceListAdapter class is list adapter for showing scanned Devices name, address and RSSI image based on RSSI values. + */ +public class DeviceListAdapter extends BaseAdapter { + private static final int TYPE_TITLE = 0; + private static final int TYPE_ITEM = 1; + private static final int TYPE_EMPTY = 2; + + private final ArrayList mListBondedValues = new ArrayList<>(); + private final ArrayList mListValues = new ArrayList<>(); + private final Context mContext; + private final ExtendedBluetoothDevice.AddressComparator comparator = new ExtendedBluetoothDevice.AddressComparator(); + + public DeviceListAdapter(Context context) { + mContext = context; + } + + public void addBondedDevice(ExtendedBluetoothDevice device) { + mListBondedValues.add(device); + notifyDataSetChanged(); + } + + /** + * Looks for the device with the same address as given one in the list of bonded devices. If the device has been found it updates its RSSI value. + * + * @param address + * the device address + * @param rssi + * the RSSI of the scanned device + */ + public void updateRssiOfBondedDevice(String address, int rssi) { + comparator.address = address; + final int indexInBonded = mListBondedValues.indexOf(comparator); + if (indexInBonded >= 0) { + ExtendedBluetoothDevice previousDevice = mListBondedValues.get(indexInBonded); + previousDevice.rssi = rssi; + notifyDataSetChanged(); + } + } + + /** + * If such device exists on the bonded device list, this method does nothing. If not then the device is updated (rssi value) or added. + * + * @param device + * the device to be added or updated + */ + public void addOrUpdateDevice(ExtendedBluetoothDevice device) { + final boolean indexInBonded = mListBondedValues.contains(device); + if (indexInBonded) { + return; + } + + final int indexInNotBonded = mListValues.indexOf(device); + if (indexInNotBonded >= 0) { + ExtendedBluetoothDevice previousDevice = mListValues.get(indexInNotBonded); + previousDevice.rssi = device.rssi; + notifyDataSetChanged(); + return; + } + mListValues.add(device); + notifyDataSetChanged(); + } + + public void clearDevices() { + mListValues.clear(); + notifyDataSetChanged(); + } + + @Override + public int getCount() { + final int bondedCount = mListBondedValues.size() + 1; // 1 for the title + final int availableCount = mListValues.isEmpty() ? 2 : mListValues.size() + 1; // 1 for title, 1 for empty text + if (bondedCount == 1) + return availableCount; + return bondedCount + availableCount; + } + + @Override + public Object getItem(int position) { + final int bondedCount = mListBondedValues.size() + 1; // 1 for the title + if (mListBondedValues.isEmpty()) { + if (position == 0) + return R.string.scanner_subtitle__not_bonded; + else + return mListValues.get(position - 1); + } else { + if (position == 0) + return R.string.scanner_subtitle_bonded; + if (position < bondedCount) + return mListBondedValues.get(position - 1); + if (position == bondedCount) + return R.string.scanner_subtitle__not_bonded; + return mListValues.get(position - bondedCount - 1); + } + } + + @Override + public int getViewTypeCount() { + return 3; + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int position) { + return getItemViewType(position) == TYPE_ITEM; + } + + @Override + public int getItemViewType(int position) { + if (position == 0) + return TYPE_TITLE; + + if (!mListBondedValues.isEmpty() && position == mListBondedValues.size() + 1) + return TYPE_TITLE; + + if (position == getCount() - 1 && mListValues.isEmpty()) + return TYPE_EMPTY; + + return TYPE_ITEM; + } + + @Override + public long getItemId(int position) { + return position; + } + + @Override + public View getView(int position, View oldView, ViewGroup parent) { + final LayoutInflater inflater = LayoutInflater.from(mContext); + final int type = getItemViewType(position); + + View view = oldView; + switch (type) { + case TYPE_EMPTY: + if (view == null) { + view = inflater.inflate(R.layout.device_list_empty, parent, false); + } + break; + case TYPE_TITLE: + if (view == null) { + view = inflater.inflate(R.layout.device_list_title, parent, false); + } + final TextView title = (TextView) view; + title.setText((Integer) getItem(position)); + break; + default: + if (view == null) { + view = inflater.inflate(R.layout.device_list_row, parent, false); + final ViewHolder holder = new ViewHolder(); + holder.name = (TextView) view.findViewById(R.id.name); + holder.address = (TextView) view.findViewById(R.id.address); + holder.rssi = (ImageView) view.findViewById(R.id.rssi); + view.setTag(holder); + } + + final ExtendedBluetoothDevice device = (ExtendedBluetoothDevice) getItem(position); + final ViewHolder holder = (ViewHolder) view.getTag(); + final String name = device.name; + holder.name.setText(name != null ? name : mContext.getString(R.string.not_available)); + holder.address.setText(device.device.getAddress()); + if (!device.isBonded || device.rssi != ScannerFragment.NO_RSSI) { + final int rssiPercent = (int) (100.0f * (127.0f + device.rssi) / (127.0f + 20.0f)); + holder.rssi.setImageLevel(rssiPercent); + holder.rssi.setVisibility(View.VISIBLE); + } else { + holder.rssi.setVisibility(View.GONE); + } + break; + } + + return view; + } + + private class ViewHolder { + private TextView name; + private TextView address; + private ImageView rssi; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ExtendedBluetoothDevice.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ExtendedBluetoothDevice.java new file mode 100644 index 00000000..35899ab4 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ExtendedBluetoothDevice.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.scanner; + +import android.bluetooth.BluetoothDevice; + +public class ExtendedBluetoothDevice { + public final BluetoothDevice device; + /** The name is not parsed by some Android devices, f.e. Sony Xperia Z1 with Android 4.3 (C6903). It needs to be parsed manually. */ + public String name; + public int rssi; + public boolean isBonded; + + public ExtendedBluetoothDevice(BluetoothDevice device, String name, int rssi, boolean isBonded) { + this.device = device; + this.name = name; + this.rssi = rssi; + this.isBonded = isBonded; + } + + @Override + public boolean equals(Object o) { + if (o instanceof ExtendedBluetoothDevice) { + final ExtendedBluetoothDevice that = (ExtendedBluetoothDevice) o; + return device.getAddress().equals(that.device.getAddress()); + } + return super.equals(o); + } + + /** + * Class used as a temporary comparator to find the device in the List of {@link ExtendedBluetoothDevice}s. This must be done this way, because List#indexOf and List#contains use the parameter's + * equals method, not the object's from list. See {@link DeviceListAdapter#updateRssiOfBondedDevice(String, int)} for example + */ + public static class AddressComparator { + public String address; + + @Override + public boolean equals(Object o) { + if (o instanceof ExtendedBluetoothDevice) { + final ExtendedBluetoothDevice that = (ExtendedBluetoothDevice) o; + return address.equals(that.device.getAddress()); + } + return super.equals(o); + } + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java new file mode 100644 index 00000000..2c0c57ad --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.scanner; + +import java.util.Set; +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.os.Handler; +import android.os.ParcelUuid; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.ListView; + +/** + * ScannerFragment class scan required BLE devices and shows them in a list. This class scans and filter devices with standard BLE Service UUID and devices with custom BLE Service UUID It contains a + * list and a button to scan/cancel. There is a interface {@link OnDeviceSelectedListener} which is implemented by activity in order to receive selected device. The scanning will continue for 5 + * seconds and then stop + */ +public class ScannerFragment extends DialogFragment { + private final static String TAG = "ScannerFragment"; + + private final static String PARAM_UUID = "param_uuid"; + private final static String DISCOVERABLE_REQUIRED = "discoverable_required"; + private final static long SCAN_DURATION = 5000; + + private BluetoothAdapter mBluetoothAdapter; + private OnDeviceSelectedListener mListener; + private DeviceListAdapter mAdapter; + private final Handler mHandler = new Handler(); + private Button mScanButton; + + private boolean mDiscoverableRequired; + private UUID mUuid; + + private boolean mIsScanning = false; + + private static final boolean DEVICE_IS_BONDED = true; + private static final boolean DEVICE_NOT_BONDED = false; + /* package */static final int NO_RSSI = -1000; + + /** + * Static implementation of fragment so that it keeps data when phone orientation is changed For standard BLE Service UUID, we can filter devices using normal android provided command + * startScanLe() with required BLE Service UUID For custom BLE Service UUID, we will use class ScannerServiceParser to filter out required device. + */ + public static ScannerFragment getInstance(final Context context, final UUID uuid, final boolean discoverableRequired) { + final ScannerFragment fragment = new ScannerFragment(); + + final Bundle args = new Bundle(); + args.putParcelable(PARAM_UUID, new ParcelUuid(uuid)); + args.putBoolean(DISCOVERABLE_REQUIRED, discoverableRequired); + fragment.setArguments(args); + return fragment; + } + + /** + * Interface required to be implemented by activity. + */ + public static interface OnDeviceSelectedListener { + /** + * Fired when user selected the device. + * + * @param device + * the device to connect to + * @param name + * the device name. Unfortunately on some devices {@link BluetoothDevice#getName()} always returns null, f.e. Sony Xperia Z1 (C6903) with Android 4.3. The name has to + * be parsed manually form the Advertisement packet. + */ + public void onDeviceSelected(final BluetoothDevice device, final String name); + + /** + * Fired when scanner dialog has been cancelled without selecting a device. + */ + public void onDialogCanceled(); + } + + /** + * This will make sure that {@link OnDeviceSelectedListener} interface is implemented by activity. + */ + @Override + public void onAttach(final Activity activity) { + super.onAttach(activity); + try { + this.mListener = (OnDeviceSelectedListener) activity; + } catch (final ClassCastException e) { + throw new ClassCastException(activity.toString() + " must implement OnDeviceSelectedListener"); + } + } + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Bundle args = getArguments(); + if (args.containsKey(PARAM_UUID)) { + final ParcelUuid pu = args.getParcelable(PARAM_UUID); + mUuid = pu.getUuid(); + } + mDiscoverableRequired = args.getBoolean(DISCOVERABLE_REQUIRED); + + final BluetoothManager manager = (BluetoothManager) getActivity().getSystemService(Context.BLUETOOTH_SERVICE); + mBluetoothAdapter = manager.getAdapter(); + } + + @Override + public void onDestroyView() { + stopScan(); + super.onDestroyView(); + } + + /** + * When dialog is created then set AlertDialog with list and button views. + */ + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + final View dialogView = LayoutInflater.from(getActivity()).inflate(R.layout.fragment_device_selection, null); + final ListView listview = (ListView) dialogView.findViewById(android.R.id.list); + + listview.setEmptyView(dialogView.findViewById(android.R.id.empty)); + listview.setAdapter(mAdapter = new DeviceListAdapter(getActivity())); + + builder.setTitle(R.string.scanner_title); + final AlertDialog dialog = builder.setView(dialogView).create(); + listview.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(final AdapterView parent, final View view, final int position, final long id) { + stopScan(); + dialog.dismiss(); + final ExtendedBluetoothDevice d = (ExtendedBluetoothDevice) mAdapter.getItem(position); + mListener.onDeviceSelected(d.device, d.name); + } + }); + + mScanButton = (Button) dialogView.findViewById(R.id.action_cancel); + mScanButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (v.getId() == R.id.action_cancel) { + if (mIsScanning) { + dialog.cancel(); + } else { + startScan(); + } + } + } + }); + + addBondedDevices(); + if (savedInstanceState == null) + startScan(); + return dialog; + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + + mListener.onDialogCanceled(); + } + + /** + * Scan for 5 seconds and then stop scanning when a BluetoothLE device is found then mLEScanCallback is activated This will perform regular scan for custom BLE Service UUID and then filter out. + * using class ScannerServiceParser + */ + private void startScan() { + mAdapter.clearDevices(); + mScanButton.setText(R.string.scanner_action_cancel); + + // Samsung Note II with Android 4.3 build JSS15J.N7100XXUEMK9 is not filtering by UUID at all. We must parse UUIDs manually + mBluetoothAdapter.startLeScan(mLEScanCallback); + + mIsScanning = true; + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (mIsScanning) { + stopScan(); + } + } + }, SCAN_DURATION); + } + + /** + * Stop scan if user tap Cancel button. + */ + private void stopScan() { + if (mIsScanning) { + mScanButton.setText(R.string.scanner_action_scan); + mBluetoothAdapter.stopLeScan(mLEScanCallback); + mIsScanning = false; + } + } + + private void addBondedDevices() { + final Set devices = mBluetoothAdapter.getBondedDevices(); + for (BluetoothDevice device : devices) { + mAdapter.addBondedDevice(new ExtendedBluetoothDevice(device, device.getName(), NO_RSSI, DEVICE_IS_BONDED)); + } + } + + /** + * if scanned device already in the list then update it otherwise add as a new device + */ + private void addScannedDevice(final BluetoothDevice device, final String name, final int rssi, final boolean isBonded) { + if (getActivity() != null) + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mAdapter.addOrUpdateDevice(new ExtendedBluetoothDevice(device, name, rssi, isBonded)); + } + }); + } + + /** + * if scanned device already in the list then update it otherwise add as a new device. + */ + private void updateScannedDevice(final BluetoothDevice device, final int rssi) { + if (getActivity() != null) + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mAdapter.updateRssiOfBondedDevice(device.getAddress(), rssi); + } + }); + } + + /** + * Callback for scanned devices class {@link ScannerServiceParser} will be used to filter devices with custom BLE service UUID then the device will be added in a list. + */ + private final BluetoothAdapter.LeScanCallback mLEScanCallback = new BluetoothAdapter.LeScanCallback() { + @Override + public void onLeScan(final BluetoothDevice device, final int rssi, final byte[] scanRecord) { + if (device != null) { + updateScannedDevice(device, rssi); + try { + if (ScannerServiceParser.decodeDeviceAdvData(scanRecord, mUuid, mDiscoverableRequired)) { + // On some devices device.getName() is always null. We have to parse the name manually :( + // This bug has been found on Sony Xperia Z1 (C6903) with Android 4.3. + // https://devzone.nordicsemi.com/index.php/cannot-see-device-name-in-sony-z1 + addScannedDevice(device, ScannerServiceParser.decodeDeviceName(scanRecord), rssi, DEVICE_NOT_BONDED); + } + } catch (Exception e) { + DebugLogger.e(TAG, "Invalid data in Advertisement packet " + e.toString()); + } + } + } + }; +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerServiceParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerServiceParser.java new file mode 100644 index 00000000..046e1e29 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerServiceParser.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.scanner; + +import java.io.UnsupportedEncodingException; +import java.util.UUID; + +import android.bluetooth.BluetoothDevice; +import android.util.Log; + +/** + * ScannerServiceParser is responsible to parse scanning data and it check if scanned device has required service in it. + */ +public class ScannerServiceParser { + private static final String TAG = "ScannerServiceParser"; + + private static final int FLAGS_BIT = 0x01; + private static final int SERVICES_MORE_AVAILABLE_16_BIT = 0x02; + private static final int SERVICES_COMPLETE_LIST_16_BIT = 0x03; + private static final int SERVICES_MORE_AVAILABLE_32_BIT = 0x04; + private static final int SERVICES_COMPLETE_LIST_32_BIT = 0x05; + private static final int SERVICES_MORE_AVAILABLE_128_BIT = 0x06; + private static final int SERVICES_COMPLETE_LIST_128_BIT = 0x07; + private static final int SHORTENED_LOCAL_NAME = 0x08; + private static final int COMPLETE_LOCAL_NAME = 0x09; + + private static final byte LE_LIMITED_DISCOVERABLE_MODE = 0x01; + private static final byte LE_GENERAL_DISCOVERABLE_MODE = 0x02; + + /** + * Checks if device is connectable (as Android cannot get this information directly we just check if it has GENERAL DISCOVERABLE or LIMITED DISCOVERABLE flag set) and has required service UUID in + * the advertising packet. The service UUID may be null. + *

+ * For further details on parsing BLE advertisement packet data see https://developer.bluetooth.org/Pages/default.aspx Bluetooth Core Specifications Volume 3, Part C, and Section 8 + *

+ */ + public static boolean decodeDeviceAdvData(byte[] data, UUID requiredUUID, boolean discoverableRequired) { + final String uuid = requiredUUID != null ? requiredUUID.toString() : null; + if (data != null) { + boolean connectible = !discoverableRequired; + boolean valid = uuid == null; + if (connectible && valid) + return true; + int fieldLength, fieldName; + int packetLength = data.length; + for (int index = 0; index < packetLength; index++) { + fieldLength = data[index]; + if (fieldLength == 0) { + return connectible && valid; + } + fieldName = data[++index]; + + if (uuid != null) { + if (fieldName == SERVICES_MORE_AVAILABLE_16_BIT || fieldName == SERVICES_COMPLETE_LIST_16_BIT) { + for (int i = index + 1; i < index + fieldLength - 1; i += 2) + valid = valid || decodeService16BitUUID(uuid, data, i, 2); + } else if (fieldName == SERVICES_MORE_AVAILABLE_32_BIT || fieldName == SERVICES_COMPLETE_LIST_32_BIT) { + for (int i = index + 1; i < index + fieldLength - 1; i += 4) + valid = valid || decodeService32BitUUID(uuid, data, i, 4); + } else if (fieldName == SERVICES_MORE_AVAILABLE_128_BIT || fieldName == SERVICES_COMPLETE_LIST_128_BIT) { + for (int i = index + 1; i < index + fieldLength - 1; i += 16) + valid = valid || decodeService128BitUUID(uuid, data, i, 16); + } + } + if (!connectible && fieldName == FLAGS_BIT) { + int flags = data[index + 1]; + connectible = (flags & (LE_GENERAL_DISCOVERABLE_MODE | LE_LIMITED_DISCOVERABLE_MODE)) > 0; + } + index += fieldLength - 1; + } + return connectible && valid; + } + return false; + } + + /** + * Decodes the device name from Complete Local Name or Shortened Local Name field in Advertisement packet. Usually if should be done by {@link BluetoothDevice#getName()} method but some phones + * skips that, f.e. Sony Xperia Z1 (C6903) with Android 4.3 where getName() always returns null. In order to show the device name correctly we have to parse it manually :( + */ + public static String decodeDeviceName(byte[] data) { + String name = null; + int fieldLength, fieldName; + int packetLength = data.length; + for (int index = 0; index < packetLength; index++) { + fieldLength = data[index]; + if (fieldLength == 0) + break; + fieldName = data[++index]; + + if (fieldName == COMPLETE_LOCAL_NAME || fieldName == SHORTENED_LOCAL_NAME) { + name = decodeLocalName(data, index + 1, fieldLength - 1); + break; + } + index += fieldLength - 1; + } + return name; + } + + /** + * Decodes the local name + */ + public static String decodeLocalName(final byte[] data, final int start, final int length) { + try { + return new String(data, start, length, "UTF-8"); + } catch (final UnsupportedEncodingException e) { + Log.e(TAG, "Unable to convert the complete local name to UTF-8", e); + return null; + } catch (final IndexOutOfBoundsException e) { + Log.e(TAG, "Error when reading complete local name", e); + return null; + } + } + + /** + * check for required Service UUID inside device + */ + private static boolean decodeService16BitUUID(String uuid, byte[] data, int startPosition, int serviceDataLength) { + String serviceUUID = Integer.toHexString(decodeUuid16(data, startPosition)); + String requiredUUID = uuid.substring(4, 8); + + return serviceUUID.equals(requiredUUID); + } + + /** + * check for required Service UUID inside device + */ + private static boolean decodeService32BitUUID(String uuid, byte[] data, int startPosition, int serviceDataLength) { + String serviceUUID = Integer.toHexString(decodeUuid16(data, startPosition + serviceDataLength - 4)); + String requiredUUID = uuid.substring(4, 8); + + return serviceUUID.equals(requiredUUID); + } + + /** + * check for required Service UUID inside device + */ + private static boolean decodeService128BitUUID(String uuid, byte[] data, int startPosition, int serviceDataLength) { + String serviceUUID = Integer.toHexString(decodeUuid16(data, startPosition + serviceDataLength - 4)); + String requiredUUID = uuid.substring(4, 8); + + return serviceUUID.equals(requiredUUID); + } + + private static int decodeUuid16(final byte[] data, final int start) { + final int b1 = data[start] & 0xff; + final int b2 = data[start + 1] & 0xff; + + return (b2 << 8 | b1); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java new file mode 100644 index 00000000..02fbac6d --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java @@ -0,0 +1,240 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; +import android.animation.ArgbEvaluator; +import android.animation.ValueAnimator; +import android.annotation.SuppressLint; +import android.bluetooth.BluetoothDevice; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.TransitionDrawable; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.widget.SlidingPaneLayout; +import android.view.View; + +public class UARTActivity extends BleProfileServiceReadyActivity implements UARTControlFragment.ControlFragmentListener, UARTInterface { + private final static String SIS_EDIT_MODE = "sis_edit_mode"; + + private SlidingPaneLayout mSlider; + private UARTService.UARTBinder mServiceBinder; + private boolean mEditMode; + + @Override + protected Class getServiceClass() { + return UARTService.class; + } + + @Override + protected void onServiceBinded(final UARTService.UARTBinder binder) { + mServiceBinder = binder; + } + + @Override + protected void onServiceUnbinded() { + mServiceBinder = null; + } + + @Override + protected void onCreateView(final Bundle savedInstanceState) { + setContentView(R.layout.activity_feature_uart); + + // Setup the sliding pane if it exists + final SlidingPaneLayout slidingPane = mSlider = (SlidingPaneLayout) findViewById(R.id.sliding_pane); + if (slidingPane != null) { + slidingPane.setSliderFadeColor(Color.TRANSPARENT); + slidingPane.setShadowResourceLeft(R.drawable.shadow_r); + slidingPane.setPanelSlideListener(new SlidingPaneLayout.SimplePanelSlideListener() { + @Override + public void onPanelClosed(final View panel) { + // Close the keyboard + final UARTLogFragment logFragment = (UARTLogFragment) getFragmentManager().findFragmentById(R.id.fragment_log); + logFragment.onFragmentHidden(); + } + }); + } + } + + @Override + protected void onRestoreInstanceState(final Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + mEditMode = savedInstanceState.getBoolean(SIS_EDIT_MODE); + setEditMode(mEditMode, false); + } + + @Override + public void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putBoolean(SIS_EDIT_MODE, mEditMode); + } + + @Override + protected boolean onOptionsItemSelected(int itemId) { + switch (itemId) { + case R.id.action_show_log: + mSlider.openPane(); + return true; + } + return false; + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.uart_feature_title; + } + + @Override + protected Uri getLocalAuthorityLogger() { + return UARTLocalLogContentProvider.AUTHORITY_URI; + } + + @Override + protected void setDefaultUI() { + // empty + } + + @Override + public void onServicesDiscovered(final boolean optionalServicesFound) { + // do nothing + } + + @Override + public void onDeviceSelected(final BluetoothDevice device, final String name) { + // The super method starts the service + super.onDeviceSelected(device, name); + + // Notify the log fragment about it + final UARTLogFragment logFragment = (UARTLogFragment) getFragmentManager().findFragmentById(R.id.fragment_log); + logFragment.onServiceStarted(); + } + + @Override + protected int getDefaultDeviceName() { + return R.string.uart_default_name; + } + + @Override + protected int getAboutTextId() { + return R.string.uart_about_text; + } + + @Override + protected UUID getFilterUUID() { + return null; // not used + } + + @Override + protected boolean isDiscoverableRequired() { + return false; + } + + @Override + public void send(final String text) { + if (mServiceBinder != null) + mServiceBinder.send(text); + } + + @Override + public void setEditMode(final boolean editMode) { + setEditMode(editMode, true); + } + + @Override + public void onBackPressed() { + if (mSlider != null && mSlider.isOpen()) { + mSlider.closePane(); + return; + } + if (mEditMode) { + final UARTControlFragment fragment = (UARTControlFragment) getFragmentManager().findFragmentById(R.id.fragment_control); + fragment.setEditMode(false); + return; + } + super.onBackPressed(); + } + + /** + * Updates the ActionBar background color depending on whether we are in edit mode or not. + * + * @param editMode + * true to show edit mode, false otherwise + * @param change + * if true the background will change with animation, otherwise immediately + */ + @SuppressLint("NewApi") + private void setEditMode(final boolean editMode, final boolean change) { + mEditMode = editMode; + if (!change) { + final ColorDrawable color = new ColorDrawable(); + int darkColor = 0; + if (editMode) { + color.setColor(getResources().getColor(R.color.orange)); + darkColor = getResources().getColor(R.color.dark_orange); + } else { + color.setColor(getResources().getColor(R.color.actionBarColor)); + darkColor = getResources().getColor(R.color.actionBarColorDark); + } + getSupportActionBar().setBackgroundDrawable(color); + + // Since Lollipop the status bar color may also be changed + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) + getWindow().setStatusBarColor(darkColor); + } else { + final TransitionDrawable transition = (TransitionDrawable) getResources().getDrawable( + editMode ? R.drawable.start_edit_mode : R.drawable.stop_edit_mode); + transition.setCrossFadeEnabled(true); + getSupportActionBar().setBackgroundDrawable(transition); + transition.startTransition(200); + + // Since Lollipop the status bar color may also be changed + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + final int colorFrom = getResources().getColor(editMode ? R.color.actionBarColorDark : R.color.dark_orange); + final int colorTo = getResources().getColor(!editMode ? R.color.actionBarColorDark : R.color.dark_orange); + + final ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo); + anim.setDuration(200); + anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(final ValueAnimator animation) { + getWindow().setStatusBarColor((Integer) animation.getAnimatedValue()); + } + }); + anim.start(); + } + + if (mSlider != null && editMode) { + mSlider.closePane(); + } + } + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTButtonAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTButtonAdapter.java new file mode 100644 index 00000000..32c7c41f --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTButtonAdapter.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import no.nordicsemi.android.nrftoolbox.R; +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ImageView; + +public class UARTButtonAdapter extends BaseAdapter { + public final static String PREFS_BUTTON_ENABLED = "prefs_uart_enabled_"; + public final static String PREFS_BUTTON_COMMAND = "prefs_uart_command_"; + public final static String PREFS_BUTTON_ICON = "prefs_uart_icon_"; + + private final SharedPreferences mPreferences; + private final int[] mIcons; + private final boolean[] mEnableFlags; + private boolean mEditMode; + + public UARTButtonAdapter(final Context context) { + mPreferences = PreferenceManager.getDefaultSharedPreferences(context); + mIcons = new int[9]; + mEnableFlags = new boolean[9]; + } + + public void setEditMode(final boolean editMode) { + mEditMode = editMode; + notifyDataSetChanged(); + } + + @Override + public void notifyDataSetChanged() { + final SharedPreferences preferences = mPreferences; + for (int i = 0; i < mIcons.length; ++i) { + mIcons[i] = preferences.getInt(PREFS_BUTTON_ICON + i, -1); + mEnableFlags[i] = preferences.getBoolean(PREFS_BUTTON_ENABLED + i, false); + } + super.notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mIcons.length; + } + + @Override + public Object getItem(final int position) { + return mIcons[position]; + } + + @Override + public long getItemId(final int position) { + return position; + } + + @Override + public boolean hasStableIds() { + return true; + } + + @Override + public boolean areAllItemsEnabled() { + return false; + } + + @Override + public boolean isEnabled(int position) { + return mEditMode || mEnableFlags[position]; + } + + @Override + public View getView(final int position, final View convertView, final ViewGroup parent) { + View view = convertView; + if (view == null) { + final LayoutInflater inflater = LayoutInflater.from(parent.getContext()); + view = inflater.inflate(R.layout.feature_uart_button, parent, false); + } + view.setEnabled(isEnabled(position)); + view.setActivated(mEditMode); + + // Update image + final ImageView image = (ImageView) view; + final int icon = mIcons[position]; + if (mEnableFlags[position] && icon != -1) { + image.setImageResource(R.drawable.uart_button); + image.setImageLevel(icon); + } else + image.setImageDrawable(null); + + return view; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTControlFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTControlFragment.java new file mode 100644 index 00000000..852ec6ac --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTControlFragment.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import no.nordicsemi.android.nrftoolbox.R; +import android.app.Activity; +import android.app.Fragment; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.GridView; + +public class UARTControlFragment extends Fragment implements GridView.OnItemClickListener { + private final static String TAG = "UARTControlFragment"; + private final static String SIS_EDIT_MODE = "sis_edit_mode"; + + private ControlFragmentListener mListener; + private SharedPreferences mPreferences; + private UARTButtonAdapter mAdapter; + private boolean mEditMode; + + public static interface ControlFragmentListener { + public void setEditMode(final boolean editMode); + } + + @Override + public void onAttach(final Activity activity) { + super.onAttach(activity); + + try { + mListener = (ControlFragmentListener) activity; + } catch (final ClassCastException e) { + Log.e(TAG, "The parent activity must implement EditModeListener"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + + if (savedInstanceState != null) { + mEditMode = savedInstanceState.getBoolean(SIS_EDIT_MODE); + } + } + + @Override + public void onSaveInstanceState(final Bundle outState) { + outState.putBoolean(SIS_EDIT_MODE, mEditMode); + } + + @Override + public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { + final View view = inflater.inflate(R.layout.fragment_feature_uart_control, container, false); + + final GridView grid = (GridView) view.findViewById(R.id.grid); + grid.setAdapter(mAdapter = new UARTButtonAdapter(getActivity())); + grid.setOnItemClickListener(this); + mAdapter.setEditMode(mEditMode); + + setHasOptionsMenu(true); + return view; + } + + @Override + public void onItemClick(final AdapterView parent, final View view, final int position, final long id) { + if (mEditMode) { + final UARTEditDialog dialog = UARTEditDialog.getInstance(position); + dialog.show(getChildFragmentManager(), null); + } else { + final UARTInterface uart = (UARTInterface) getActivity(); + uart.send(mPreferences.getString(UARTButtonAdapter.PREFS_BUTTON_COMMAND + position, "")); + } + } + + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + inflater.inflate(mEditMode ? R.menu.uart_menu_config : R.menu.uart_menu, menu); + } + + @Override + public boolean onOptionsItemSelected(final MenuItem item) { + final int itemId = item.getItemId(); + switch (itemId) { + case R.id.action_configure: + setEditMode(!mEditMode); + return true; + } + return false; + } + + public void setEditMode(final boolean editMode) { + mEditMode = editMode; + mAdapter.setEditMode(mEditMode); + getActivity().invalidateOptionsMenu(); + mListener.setEditMode(mEditMode); + } + + public void onConfigurationChanged() { + mAdapter.notifyDataSetChanged(); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java new file mode 100644 index 00000000..b509f437 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import no.nordicsemi.android.nrftoolbox.R; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.Button; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.GridView; +import android.widget.ImageView; + +public class UARTEditDialog extends DialogFragment implements View.OnClickListener, GridView.OnItemClickListener { + private final static String TAG = "UARTEditDialog"; + private final static String ARG_INDEX = "index"; + private int mActiveIcon; + + private EditText mField; + private CheckBox mCheckBox; + private IconAdapter mIconAdapter; + + public static UARTEditDialog getInstance(final int index) { + final UARTEditDialog fragment = new UARTEditDialog(); + + final Bundle args = new Bundle(); + args.putInt(ARG_INDEX, index); + fragment.setArguments(args); + + return fragment; + } + + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + final LayoutInflater inflater = LayoutInflater.from(getActivity()); + + // Read button configuration + final Bundle args = getArguments(); + final int index = args.getInt(ARG_INDEX); + final String command = preferences.getString(UARTButtonAdapter.PREFS_BUTTON_COMMAND + index, null); + final boolean active = true;//preferences.getBoolean(UARTButtonAdapter.PREFS_BUTTON_ENABLED + index, false); + mActiveIcon = preferences.getInt(UARTButtonAdapter.PREFS_BUTTON_ICON + index, 0); + + // Create view + final View view = inflater.inflate(R.layout.feature_uart_dialog_edit, null); + final EditText field = mField = (EditText) view.findViewById(R.id.field); + final GridView grid = (GridView) view.findViewById(R.id.grid); + final CheckBox checkBox = mCheckBox = (CheckBox) view.findViewById(R.id.active); + checkBox.setOnCheckedChangeListener(new CheckBox.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { + field.setEnabled(isChecked); + grid.setEnabled(isChecked); + if (mIconAdapter != null) + mIconAdapter.notifyDataSetChanged(); + } + }); + + field.setText(command); + field.setEnabled(active); + checkBox.setChecked(active); + grid.setOnItemClickListener(this); + grid.setEnabled(active); + grid.setAdapter(mIconAdapter = new IconAdapter()); + + // As we want to have some validation we can't user the DialogInterface.OnClickListener as it's always dismissing the dialog. + final AlertDialog dialog = new AlertDialog.Builder(getActivity()).setCancelable(false).setTitle(R.string.uart_edit_title).setPositiveButton(R.string.ok, null) + .setNegativeButton(R.string.cancel, null).setView(view).show(); + final Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE); + okButton.setOnClickListener(this); + return dialog; + } + + @Override + public void onClick(final View v) { + final boolean active = mCheckBox.isChecked(); + final String command = mField.getText().toString(); + if (active && TextUtils.isEmpty(command)) { + mField.setError(getString(R.string.uart_edit_command_error)); + return; + } + mField.setError(null); + + // Save values + final Bundle args = getArguments(); + final int index = args.getInt(ARG_INDEX); + + final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); + final SharedPreferences.Editor editor = preferences.edit(); + editor.putString(UARTButtonAdapter.PREFS_BUTTON_COMMAND + index, command); + editor.putBoolean(UARTButtonAdapter.PREFS_BUTTON_ENABLED + index, active); + editor.putInt(UARTButtonAdapter.PREFS_BUTTON_ICON + index, mActiveIcon); + editor.commit(); + + dismiss(); + final UARTControlFragment parent = (UARTControlFragment) getParentFragment(); + parent.onConfigurationChanged(); + } + + @Override + public void onItemClick(final AdapterView parent, final View view, final int position, final long id) { + mActiveIcon = position; + mIconAdapter.notifyDataSetChanged(); + } + + private class IconAdapter extends BaseAdapter { + private final int SIZE = 20; + + @Override + public int getCount() { + return SIZE; + } + + @Override + public Object getItem(final int position) { + return position; + } + + @Override + public long getItemId(final int position) { + return position; + } + + @Override + public View getView(final int position, final View convertView, final ViewGroup parent) { + View view = convertView; + if (view == null) { + view = LayoutInflater.from(getActivity()).inflate(R.layout.feature_uart_dialog_edit_icon, parent, false); + } + final ImageView image = (ImageView) view; + image.setImageLevel(position); + image.setActivated(position == mActiveIcon && mCheckBox.isChecked()); + return view; + } + + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTInterface.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTInterface.java new file mode 100644 index 00000000..ea3c1934 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTInterface.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + + +public interface UARTInterface { + + public void send(final String text); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLocalLogContentProvider.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLocalLogContentProvider.java new file mode 100644 index 00000000..ad23e4eb --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLocalLogContentProvider.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import no.nordicsemi.android.log.localprovider.LocalLogContentProvider; +import android.net.Uri; + +public class UARTLocalLogContentProvider extends LocalLogContentProvider { + /** The authority for the contacts provider. */ + public final static String AUTHORITY = "no.nordicsemi.android.nrftoolbox.uart.log"; + /** A content:// style uri to the authority for the log provider. */ + public final static Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY); + + @Override + protected Uri getAuthorityUri() { + return AUTHORITY_URI; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogAdapter.java new file mode 100644 index 00000000..701e0532 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogAdapter.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import java.util.Calendar; + +import no.nordicsemi.android.log.LogContract.Log.Level; +import no.nordicsemi.android.nrftoolbox.R; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Color; +import android.util.SparseIntArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CursorAdapter; +import android.widget.TextView; + +public class UARTLogAdapter extends CursorAdapter { + private static final SparseIntArray mColors = new SparseIntArray(); + + static { + mColors.put(Level.DEBUG, 0xFF009CDE); + mColors.put(Level.VERBOSE, 0xFFB8B056); + mColors.put(Level.INFO, Color.BLACK); + mColors.put(Level.APPLICATION, 0xFF238C0F); + mColors.put(Level.WARNING, 0xFFD77926); + mColors.put(Level.ERROR, Color.RED); + } + + public UARTLogAdapter(Context context) { + super(context, null, 0); + } + + @Override + public View newView(final Context context, final Cursor cursor, final ViewGroup parent) { + final View view = LayoutInflater.from(context).inflate(R.layout.log_item, parent, false); + + final ViewHolder holder = new ViewHolder(); + holder.time = (TextView) view.findViewById(R.id.time); + holder.data = (TextView) view.findViewById(R.id.data); + view.setTag(holder); + return view; + } + + @Override + public void bindView(final View view, final Context context, final Cursor cursor) { + final ViewHolder holder = (ViewHolder) view.getTag(); + final Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(cursor.getLong(1 /* TIME */)); + holder.time.setText(context.getString(R.string.log, calendar)); + + final int level = cursor.getInt(2 /* LEVEL */); + holder.data.setText(cursor.getString(3 /* DATA */)); + holder.data.setTextColor(mColors.get(level)); + } + + @Override + public boolean isEnabled(int position) { + return false; + } + + private class ViewHolder { + private TextView time; + private TextView data; + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java new file mode 100644 index 00000000..34e79273 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java @@ -0,0 +1,299 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.LogContract; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import android.app.ListFragment; +import android.app.LoaderManager.LoaderCallbacks; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.CursorLoader; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.Loader; +import android.content.ServiceConnection; +import android.database.Cursor; +import android.os.Bundle; +import android.os.IBinder; +import android.support.v4.content.LocalBroadcastManager; +import android.view.KeyEvent; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.CursorAdapter; +import android.widget.EditText; +import android.widget.ListView; +import android.widget.TextView; + +public class UARTLogFragment extends ListFragment implements LoaderCallbacks { + private static final String SIS_LOG_SCROLL_POSITION = "sis_scroll_position"; + private static final int LOG_SCROLL_NULL = -1; + private static final int LOG_SCROLLED_TO_BOTTOM = -2; + + private static final int LOG_REQUEST_ID = 1; + private static final String[] LOG_PROJECTION = { LogContract.Log._ID, LogContract.Log.TIME, LogContract.Log.LEVEL, LogContract.Log.DATA }; + + /** The service UART interface that may be used to send data to the target. */ + private UARTInterface mUARTInterface; + /** The adapter used to populate the list with log entries. */ + private CursorAdapter mLogAdapter; + /** The log session created to log events related with the target device. */ + private ILogSession mLogSession; + + private EditText mField; + private Button mSendButton; + + /** The last list view position. */ + private int mLogScrollPosition; + + /** + * The receiver that listens for {@link BleProfileService#BROADCAST_CONNECTION_STATE} action. + */ + private final BroadcastReceiver mCommonBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + // This receiver listens only for the BleProfileService.BROADCAST_CONNECTION_STATE action, no need to check it. + + final int state = intent.getIntExtra(BleProfileService.EXTRA_CONNECTION_STATE, BleProfileService.STATE_DISCONNECTED); + + switch (state) { + case BleProfileService.STATE_CONNECTED: { + onDeviceConnected(); + break; + } + case BleProfileService.STATE_DISCONNECTED: { + onDeviceDisconnected(); + break; + } + case BleProfileService.STATE_CONNECTING: + case BleProfileService.STATE_DISCONNECTING: + // current implementation does nothing in this states + default: + // there should be no other actions + break; + + } + } + }; + + private ServiceConnection mServiceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(final ComponentName name, final IBinder service) { + final UARTService.UARTBinder bleService = (UARTService.UARTBinder) service; + mUARTInterface = bleService; + mLogSession = bleService.getLogSession(); + + // Start the loader + if (mLogSession != null) { + getLoaderManager().restartLoader(LOG_REQUEST_ID, null, UARTLogFragment.this); + } + + // and notify user if device is connected + if (bleService.isConnected()) + onDeviceConnected(); + } + + @Override + public void onServiceDisconnected(final ComponentName name) { + onDeviceDisconnected(); + mUARTInterface = null; + } + }; + + @Override + public void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + LocalBroadcastManager.getInstance(getActivity()).registerReceiver(mCommonBroadcastReceiver, makeIntentFilter()); + + // Load the last log list view scroll position + if (savedInstanceState != null) { + mLogScrollPosition = savedInstanceState.getInt(SIS_LOG_SCROLL_POSITION); + } + } + + @Override + public void onStart() { + super.onStart(); + + /* + * If the service has not been started before the following lines will not start it. However, if it's running, the Activity will be binded to it + * and notified via mServiceConnection. + */ + final Intent service = new Intent(getActivity(), UARTService.class); + getActivity().bindService(service, mServiceConnection, 0); // we pass 0 as a flag so the service will not be created if not exists + } + + @Override + public void onStop() { + super.onStop(); + + try { + getActivity().unbindService(mServiceConnection); + mUARTInterface = null; + } catch (final IllegalArgumentException e) { + // do nothing, we were not connected to the sensor + } + } + + @Override + public void onSaveInstanceState(final Bundle outState) { + super.onSaveInstanceState(outState); + + // Save the last log list view scroll position + final ListView list = getListView(); + final boolean scrolledToBottom = list.getCount() > 0 && list.getLastVisiblePosition() == list.getCount() - 1; + outState.putInt(SIS_LOG_SCROLL_POSITION, scrolledToBottom ? LOG_SCROLLED_TO_BOTTOM : list.getFirstVisiblePosition()); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mCommonBroadcastReceiver); + } + + @Override + public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { + final View view = inflater.inflate(R.layout.fragment_feature_uart_log, container, false); + + final EditText field = mField = (EditText) view.findViewById(R.id.field); + field.setOnEditorActionListener(new TextView.OnEditorActionListener() { + @Override + public boolean onEditorAction(final TextView v, final int actionId, final KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_SEND) { + onSendClicked(); + return true; + } + return false; + } + }); + + final Button sendButton = mSendButton = (Button) view.findViewById(R.id.action_send); + sendButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(final View v) { + onSendClicked(); + } + }); + return view; + } + + @Override + public void onViewCreated(final View view, final Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + // Create the log adapter, initially with null cursor + mLogAdapter = new UARTLogAdapter(getActivity()); + setListAdapter(mLogAdapter); + } + + @Override + public Loader onCreateLoader(final int id, final Bundle args) { + switch (id) { + case LOG_REQUEST_ID: { + return new CursorLoader(getActivity(), mLogSession.getSessionEntriesUri(), LOG_PROJECTION, null, null, LogContract.Log.TIME); + } + } + return null; + } + + @Override + public void onLoadFinished(final Loader loader, final Cursor data) { + // Here we have to restore the old saved scroll position, or scroll to the bottom if before adding new events it was scrolled to the bottom. + final ListView list = getListView(); + final int position = mLogScrollPosition; + final boolean scrolledToBottom = position == LOG_SCROLLED_TO_BOTTOM || (list.getCount() > 0 && list.getLastVisiblePosition() == list.getCount() - 1); + + mLogAdapter.swapCursor(data); + + if (position > LOG_SCROLL_NULL) { + list.setSelectionFromTop(position, 0); + } else { + if (scrolledToBottom) + list.setSelection(list.getCount() - 1); + } + mLogScrollPosition = LOG_SCROLL_NULL; + } + + @Override + public void onLoaderReset(final Loader loader) { + mLogAdapter.swapCursor(null); + } + + private void onSendClicked() { + final String text = mField.getText().toString(); + + mUARTInterface.send(text); + + mField.setText(null); + mField.requestFocus(); + } + + /** + * Method called when user selected a device on the scanner dialog after the service has been started. + * Here we may bind this fragment to it. + */ + public void onServiceStarted() { + // The service has been started, bind to it + final Intent service = new Intent(getActivity(), UARTService.class); + getActivity().bindService(service, mServiceConnection, 0); + } + + /** + * This method is called when user closes the pane in horizontal orientation. The EditText is no longer visible so we need to close the soft keyboard here. + */ + public void onFragmentHidden() { + InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE); + imm.hideSoftInputFromWindow(mField.getWindowToken(), 0); + } + + /** + * Method called when the target device has connected. + */ + protected void onDeviceConnected() { + mField.setEnabled(true); + mSendButton.setEnabled(true); + } + + /** + * Method called when user disconnected from the target UART device or the connection was lost. + */ + protected void onDeviceDisconnected() { + mField.setEnabled(false); + mSendButton.setEnabled(false); + } + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(BleProfileService.BROADCAST_CONNECTION_STATE); + return intentFilter; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java new file mode 100644 index 00000000..435db497 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import java.util.List; +import java.util.UUID; + +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattDescriptor; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothProfile; +import android.content.Context; + +public class UARTManager implements BleManager { + private final static String TAG = "UARTManager"; + + private final static UUID UART_SERVICE_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); + /** TX characteristic */ + private final static UUID UART_TX_CHARACTERISTIC_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"); + /** RX characteristic */ + private final static UUID UART_RX_CHARACTERISTIC_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"); + /** Client configuration descriptor that will allow us to enable notifications and indications */ + private static final UUID CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); + + private final static String ERROR_CONNECTION_STATE_CHANGE = "Error on connection state change"; + private final static String ERROR_DISCOVERY_SERVICE = "Error on discovering services"; + private final static String ERROR_WRITE_DESCRIPTOR = "Error on writing descriptor"; + + private BluetoothGattCharacteristic mTXCharacteristic, mRXCharacteristic; + + private UARTManagerCallbacks mCallbacks; + private BluetoothGatt mBluetoothGatt; + private final Context mContext; + + public UARTManager(final Context context) { + mContext = context; + } + + @Override + public void setGattCallbacks(final UARTManagerCallbacks callbacks) { + mCallbacks = callbacks; + } + + @Override + public void connect(final Context context, final BluetoothDevice device) { + if (mBluetoothGatt == null) { + mBluetoothGatt = device.connectGatt(mContext, true, mGattCallback); + } else { + mBluetoothGatt.connect(); + } + } + + @Override + public void disconnect() { + if (mBluetoothGatt != null) { + mBluetoothGatt.disconnect(); + } + } + + public void send(final String text) { + if (mTXCharacteristic != null) { + mTXCharacteristic.setValue(text); + mBluetoothGatt.writeCharacteristic(mTXCharacteristic); + } + } + + /** + * BluetoothGatt callbacks for connection/disconnection, service discovery, receiving indication, etc + */ + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + @Override + public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) { + if (status == BluetoothGatt.GATT_SUCCESS) { + if (newState == BluetoothProfile.STATE_CONNECTED) { + DebugLogger.d(TAG, "Device connected"); + mBluetoothGatt.discoverServices(); + //This will send callback to RSCActivity when device get connected + mCallbacks.onDeviceConnected(); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + DebugLogger.d(TAG, "Device disconnected"); + + mCallbacks.onDeviceDisconnected(); + closeBluetoothGatt(); + } + } else { + mCallbacks.onError(ERROR_CONNECTION_STATE_CHANGE, status); + } + } + + @Override + public void onServicesDiscovered(final BluetoothGatt gatt, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + final List services = gatt.getServices(); + for (BluetoothGattService service : services) { + if (service.getUuid().equals(UART_SERVICE_UUID)) { + DebugLogger.d(TAG, "UART service is found"); + mTXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID); + mRXCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID); + } + } + if (mTXCharacteristic == null || mRXCharacteristic == null) { + mCallbacks.onDeviceNotSupported(); + gatt.disconnect(); + } else { + mCallbacks.onServicesDiscovered(false /* more characteristics not supported */); + + // We have discovered services, let's start notifications on RX characteristics + enableRXNotification(gatt); + } + } else { + mCallbacks.onError(ERROR_DISCOVERY_SERVICE, status); + } + } + + @Override + public void onDescriptorWrite(final BluetoothGatt gatt, final BluetoothGattDescriptor descriptor, final int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + // do nothing + } else { + mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status); + } + } + + @Override + public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + if (status == BluetoothGatt.GATT_SUCCESS) { + final String data = characteristic.getStringValue(0); + mCallbacks.onDataSent(data); + } else { + mCallbacks.onError(ERROR_WRITE_DESCRIPTOR, status); + } + } + + @Override + public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { + final String data = characteristic.getStringValue(0); + mCallbacks.onDataReceived(data); + } + }; + + /** + * Enabling notification on RX Characteristic + */ + private void enableRXNotification(final BluetoothGatt gatt) { + gatt.setCharacteristicNotification(mRXCharacteristic, true); + final BluetoothGattDescriptor descriptor = mRXCharacteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID); + descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); + gatt.writeDescriptor(descriptor); + } + + @Override + public void closeBluetoothGatt() { + if (mBluetoothGatt != null) { + mBluetoothGatt.close(); + mBluetoothGatt = null; + mTXCharacteristic = null; + mRXCharacteristic = null; + } + mCallbacks = null; + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java new file mode 100644 index 00000000..e80d212f --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import no.nordicsemi.android.nrftoolbox.profile.BleManagerCallbacks; + +public interface UARTManagerCallbacks extends BleManagerCallbacks { + + public void onDataReceived(final String data); + + public void onDataSent(final String data); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java new file mode 100644 index 00000000..4e762666 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package no.nordicsemi.android.nrftoolbox.uart; + +import no.nordicsemi.android.log.ILogSession; +import no.nordicsemi.android.log.Logger; +import no.nordicsemi.android.nrftoolbox.FeaturesActivity; +import no.nordicsemi.android.nrftoolbox.R; +import no.nordicsemi.android.nrftoolbox.profile.BleManager; +import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.IBinder; +import android.support.v4.content.LocalBroadcastManager; + +public class UARTService extends BleProfileService implements UARTManagerCallbacks { + public static final String BROADCAST_UART_TX = "no.nordicsemi.android.nrftoolbox.uart.BROADCAST_UART_TX"; + public static final String BROADCAST_UART_RX = "no.nordicsemi.android.nrftoolbox.uart.BROADCAST_UART_RX"; + public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.uart.EXTRA_DATA"; + + private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.uart.ACTION_DISCONNECT"; + + private final static int NOTIFICATION_ID = 349; // random + private final static int OPEN_ACTIVITY_REQ = 67; // random + private final static int DISCONNECT_REQ = 97; // random + + private UARTManager mManager; + private boolean mBinded; + + private final LocalBinder mBinder = new UARTBinder(); + + public class UARTBinder extends LocalBinder implements UARTInterface { + @Override + public void send(final String text) { + mManager.send(text); + } + + @Override + public ILogSession getLogSession() { + return super.getLogSession(); + } + } + + @Override + protected LocalBinder getBinder() { + return mBinder; + } + + @Override + protected BleManager initializeManager() { + return mManager = new UARTManager(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DISCONNECT); + registerReceiver(mDisconnectActionBroadcastReceiver, filter); + } + + @Override + public void onDestroy() { + // when user has disconnected from the sensor, we have to cancel the notification that we've created some milliseconds before using unbindService + cancelNotification(); + unregisterReceiver(mDisconnectActionBroadcastReceiver); + + super.onDestroy(); + } + + @Override + public IBinder onBind(final Intent intent) { + mBinded = true; + return super.onBind(intent); + } + + @Override + public void onRebind(final Intent intent) { + mBinded = true; + // when the activity rebinds to the service, remove the notification + cancelNotification(); + } + + @Override + public boolean onUnbind(final Intent intent) { + mBinded = false; + // when the activity closes we need to show the notification that user is connected to the sensor + createNotifcation(R.string.uart_notification_connected_message, 0); + return super.onUnbind(intent); + } + + @Override + public void onDataReceived(final String data) { + Logger.a(getLogSession(), "\"" + data + "\" received"); + + final Intent broadcast = new Intent(BROADCAST_UART_RX); + broadcast.putExtra(EXTRA_DATA, data); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + @Override + public void onDataSent(String data) { + Logger.a(getLogSession(), "\"" + data + "\" sent"); + + final Intent broadcast = new Intent(BROADCAST_UART_TX); + broadcast.putExtra(EXTRA_DATA, data); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + } + + /** + * Creates the notification + * + * @param messageResId + * message resource id. The message must have one String parameter,
+ * f.e. <string name="name">%s is connected</string> + * @param defaults + * signals that will be used to notify the user + */ + private void createNotifcation(final int messageResId, final int defaults) { + final Intent parentIntent = new Intent(this, FeaturesActivity.class); + parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final Intent targetIntent = new Intent(this, UARTActivity.class); + + final Intent disconnect = new Intent(ACTION_DISCONNECT); + final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT); + + // both activities above have launchMode="singleTask" in the AndoridManifest.xml file, so if the task is already running, it will be resumed + final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[] { parentIntent, targetIntent }, PendingIntent.FLAG_UPDATE_CURRENT); + final Notification.Builder builder = new Notification.Builder(this).setContentIntent(pendingIntent); + builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); + builder.setSmallIcon(R.drawable.ic_stat_notify_uart); + builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); + builder.addAction(R.drawable.ic_action_bluetooth, getString(R.string.uart_notification_action_disconnect), disconnectAction); + + final Notification notification = builder.build(); + final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID, notification); + } + + /** + * Cancels the existing notification. If there is no active notification this method does nothing + */ + private void cancelNotification() { + final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + nm.cancel(NOTIFICATION_ID); + } + + /** + * This broadcast receiver listens for {@link #ACTION_DISCONNECT} that may be fired by pressing Disconnect action button on the notification. + */ + private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + Logger.i(getLogSession(), "Disconnect action pressed"); + if (isConnected()) + getBinder().disconnect(); + else + stopSelf(); + } + }; + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/DebugLogger.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/DebugLogger.java new file mode 100644 index 00000000..2c193a8e --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/DebugLogger.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.utility; + +import no.nordicsemi.android.nrftoolbox.BuildConfig; +import android.util.Log; + +public class DebugLogger { + public static void v(final String tag, final String text) { + if (BuildConfig.DEBUG) + Log.v(tag, text); + } + + public static void d(String tag, String text) { + if (BuildConfig.DEBUG) { + Log.d(tag, text); + } + } + + public static void i(final String tag, final String text) { + if (BuildConfig.DEBUG) + Log.i(tag, text); + } + + public static void w(String tag, String text) { + if (BuildConfig.DEBUG) { + Log.w(tag, text); + } + } + + public static void e(final String tag, final String text) { + if (BuildConfig.DEBUG) + Log.e(tag, text); + } + + public static void wtf(String tag, String text) { + if (BuildConfig.DEBUG) { + Log.wtf(tag, text); + } + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetBoldTextView.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetBoldTextView.java new file mode 100644 index 00000000..7e15f533 --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetBoldTextView.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.widget; + +import no.nordicsemi.android.nrftoolbox.R; +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.widget.TextView; + +public class TrebuchetBoldTextView extends TextView { + + public TrebuchetBoldTextView(Context context) { + super(context); + + init(); + } + + public TrebuchetBoldTextView(Context context, AttributeSet attrs) { + super(context, attrs); + + init(); + } + + public TrebuchetBoldTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + init(); + } + + private void init() { + if (!isInEditMode()) { + final Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), getContext().getString(R.string.font_path)); + setTypeface(typeface); + } + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetTextView.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetTextView.java new file mode 100644 index 00000000..ebbde29e --- /dev/null +++ b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/TrebuchetTextView.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, Nordic Semiconductor + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package no.nordicsemi.android.nrftoolbox.widget; + +import no.nordicsemi.android.nrftoolbox.R; +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.widget.TextView; + +public class TrebuchetTextView extends TextView { + + public TrebuchetTextView(Context context) { + super(context); + + init(); + } + + public TrebuchetTextView(Context context, AttributeSet attrs) { + super(context, attrs); + + init(); + } + + public TrebuchetTextView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + init(); + } + + private void init() { + if (!isInEditMode()) { + final Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), getContext().getString(R.string.normal_font_path)); + setTypeface(typeface); + } + } +} diff --git a/app/src/main/res/animator/click_animator.xml b/app/src/main/res/animator/click_animator.xml new file mode 100644 index 00000000..7b316a4c --- /dev/null +++ b/app/src/main/res/animator/click_animator.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/color/text_color_primary.xml b/app/src/main/res/color/text_color_primary.xml new file mode 100644 index 00000000..3d054b88 --- /dev/null +++ b/app/src/main/res/color/text_color_primary.xml @@ -0,0 +1,27 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/battery.png b/app/src/main/res/drawable-hdpi/battery.png new file mode 100644 index 0000000000000000000000000000000000000000..dd83f9bbaa1b65990f0f0427ff2480e51ac8957c GIT binary patch literal 392 zcmeAS@N?(olHy`uVBq!ia0vp^-axF(!3HGny!?I_NJ*BsMwA5SrSV zY-i5tcblKO;aZ|-w~<_ZWv|=i+4Adu+C^lZU1nTa_e%Yk->T4SI${+-P24&_1gFd7 z&ugTe~DWM4f=|ZPt literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..236bff558af07faa3921ba35e2515edf62d04bb9 GIT binary patch literal 161 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 VmAn;cuKy}O0Iu^yyHe98^gsUU-`@ZL literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_dfu_feature.png b/app/src/main/res/drawable-hdpi/ic_dfu_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..db59fae82b0e31240ffe5a0b4ae23485cc562d47 GIT binary patch literal 3079 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 VlfF}PPn-Y%002ovPDHLkV1i!qzPSJZ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_drawer.png b/app/src/main/res/drawable-hdpi/ic_drawer.png new file mode 100644 index 0000000000000000000000000000000000000000..bb40b7230dfee7aac8f56d0d0a27d9d075b5ceab GIT binary patch literal 2755 zcmV;!3Ox0RP)|D^_ww@lRz|vCuzLs)$;-`! zo*{AqUjza0dRV*yaMRE;fKCVhpQKsoe1Yhg01=zBIT!& zC1$=TK@rP|Ibo3vKKm@PqnO#LJhq6%Ij6Hz*<$V$@wQAMN5qJ)hzm2hoGcOF60t^# zFqJFfH{#e-4l@G)6iI9sa9D{VHW4w29}?su;^hF~NC{tY+*d5%WDCTXa!E_i;d2ub z1#}&jF5T4HnnCyEWTkKf0>c0%E1Ah>(_PY1)0w;+02c53Su*0<(nUqKG_|(0G&D0Z z{i;y^b@OjZ+}lNZ8Th$p5Uu}MTtq^NHl z*T1?CO*}7&0ztZsv2j*bmJyf3G7=Z`5B*PvzoDiKdLpOAxi2$L0#SX*@cY_n(^h55xYX z#km%V()bZjV~l{*bt*u9?FT3d5g^g~#a;iSZ@&02Abxq_DwB(I|L-^bXThc7C4-yr zInE_0gw7K3GZ**7&k~>k0Z0NWkO#^@9q0fwx1%qjZ=)yBuQ3=5 z4Wo^*!gyjLF-e%Um=erBOdIALW)L%unZshS@>qSW9o8Sq#0s#5*edK%>{;v(b^`kb zN5rY%%y90wC>#%$kE_5P!JWYk;U;klcqzOl-UjcFXXA75rT9jCH~u<)0>40zCTJ7v z2qAyk54cquI@7b&LHdZ`+zlTss6bJ7%PQ)z$cROu4wBhpu-r)01)S~6}jY?%U? zgEALn#wiFzo#H}aQ8rT=DHkadR18&{>P1bW7E`~Y4p3)hWn`DhhRJ5j*2tcg9i<^O zEt(fCg;q*CP8+7ZTcWhYX$fb^_9d-LhL+6BEtPYWVlfK zTBusSTASKKb%HuWJzl+By+?gkLq)?+BTu761jmyXF)a;mc z^>(B7bo*HQ1NNg1st!zt28YLv>W*y3CdWx9U8f|cqfXDAO`Q48?auQqHZJR2&bcD4 z9Ip>EY~kKEPV6Wm+eXFV)D)_R=tM0@&p?(!V*Qu1PXHG9o^TY0bZ?)4%0 z1p8F`JoeS|<@=<@RE7GY07EYX@lwd>4oW|Yi!o+Su@M`;WuSK8LKk71XR(_ zRKHM1xJ5XYX`fk>`6eqY>qNG6HZQwBM=xi4&Sb88?zd}EYguc1@>KIS<&CX#T35dw zS|7K*XM_5Nf(;WJJvJWRMA($P>8E^?{IdL4o5MGE7bq2MEEwP7v8AO@qL5!WvekBL z-8R%V?zVyL=G&{be=K4bT`e{#t|)$A!YaA?jp;X)-+bB;zhj`(vULAW%ue3U;av{9 z4wp%n<(7@__S@Z2PA@Mif3+uO&y|X06?J#o zSi8M;ejj_^(0<4Lt#wLu#dYrva1Y$6_o(k^&}yhSh&h;f@JVA>W8b%oZ=0JGnu?n~ z9O4}sJsfnnx7n(>`H13?(iXTy*fM=I`sj`CT)*pTHEgYKqqP+u1IL8No_-(u{qS+0 z<2@%BCt82d{Gqm;(q7a7b>wu+b|!X?c13m#p7cK1({0<`{-e>4hfb-UsyQuty7Ua; zOu?B?XLHZaol8GAb3Wnxcu!2v{R_`T4=x`(GvqLI{-*2AOSimkUAw*F_TX^n z@STz9kDQ$NC=!KfXWC z8h`dn#xL(D3Z9UkR7|Q&Hcy#Notk!^zVUSB(}`#4&lYA1f0h2V_PNgUAAWQEt$#LR zcH#y9#i!p(Udq2b^lI6wp1FXzN3T;~FU%Lck$-deE#qz9yYP3D3t8{6?<+s(e(3(_ z^YOu_)K8!O1p}D#{JO;G(*OVf32;bRa{vGf6951U69E94oEQKA05C~JK~zY`V_+ES zfbswT|NqI>%*e<{NDULMeK7Pb7zHB$jApdaj5Z2JGunvAXaHe~3>G=PQJnw)002ov JPDHLkV1g5}IgJ1S literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_glucose_feature.png b/app/src/main/res/drawable-hdpi/ic_glucose_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..9ea9243977fd9593fdef94c0b2cea2eedb307812 GIT binary patch literal 1373 zcmV-j1)}B-ZSmtndRLZUG64Vp z00000000000000000000000O|7W0d1nr4<|*$Zz|Z=L4tQ{Fucre@D=?RMG=vuqzZ z5xH2ORr{!$%N*NB*#%5xfy~9PiOPq%%(U$4xG&fk$| zC>t%ss?=R{Povz8$Sx>SFII7;8JsB&&&*8ajXP>hqmSMu@LxT)je80$qmSxQ$V}gj zA2z8LY_GlnbYon7R4Eqh@rn!2m4qj6{Nkh!$|5S5QFXKC(>G0-CHh6`O>_HHUr~!; zZ+^?re`6X^-L_X2EKj+i?!r^~4o}NY+tj6ED(i0FNU%-ay876sW@VNiBwN-g6l`X3 zQ!vSUJD!c}9J3UPRyiodDiPy43WjIHaQ$|HF(3ITEE%49^rO#!z9*@E$iqFZq(5xF zKXK&C9p<-2$*FoC2_9-;YL)Uwf z7_I{tR~lPjJnm^3)vXSUEAFW)>ZuIlvM*fSgku#+4b~XfIBX-j&ExNmCt+M88hwI~ zLK=)K^EvvoPceKN4q2Ang)pwkpBr&OOrj-Bu8NEnOcX8QO<7JkKEt>uUsxZT;c1q;a)Rl6}|rHatH<71mdPipT<# z3x&swbdsC3p4#wy3t8CdLBIl5A+n#bv`)`Pu?}ns*FoIKtCh7 z#+}QCvoo$zqj8;`Z9MC3Eo>*3jAiHWnv8K3g0FuOQ`0Q1@u7#^o#XJ7!r^&{IXof+ z*vjeUh!00`!UahB_^$JBAq}vvyCOMZL$q@E+BwG+QHUymX=^#+;HPmE$8(T;9dE8& zA8Qr}ytipL^$^V+HrKU}jq{x28c&cmmZvwizKV`Iwi!nm|I(cP-=Uhuz6{=C{7|47QnbnvwTO>oPdP|GOl~VgK=>bhwxxrfN=rF1=)zggK=SD zgTS}|;{y5ctT8Sa(lldSFp3cf<4Sxasy&9s>F;Vlq#Ez>hz{RX$drb0!Sx|39IZ%i zs3wMH%a$tY4p4=0fo*tBSEkDwk1%6g%EPldcOvwLZ5|kx^5*&UXP##7{(RZfTw`3y zo91KR?@at>&k)9?I6Uuv2xWOg*f1^v^v1Z>SN@%O7dnhfd3ZLqcgwqxi|}Avy1#=5 z?3?C`#s$#Vzw{axz%|CTqAGApfR^k}hN0GVBs?%=1fpRE00000000000000000000 f000;hzXcco3jJ&j#qneK00000NkvXXu0mjfwRCYb literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_help.png b/app/src/main/res/drawable-hdpi/ic_help.png new file mode 100644 index 0000000000000000000000000000000000000000..459bed76c5b9f546541383271a6c9b9ff9943093 GIT binary patch literal 1544 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_launcher.png b/app/src/main/res/drawable-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..628705f7ac5efcf4880dd83d5bc3805bb1fe5246 GIT binary patch literal 3948 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_menu_settings.png b/app/src/main/res/drawable-hdpi/ic_menu_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..3e4580e0534c913abc5560067866b162e2972945 GIT binary patch literal 1540 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezpTC$r9IylHmNblJdl&R0hYC{G?O` z&)mfH)S%SFl*+=BsWuD@%qp275hW46K32*3xq68pHF_1f1wh>l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s00+w{G(#^lGsVi)$k4*r&A`yq$-vFf(ACh=#L&{!#L3yw z&D7A`#K{n**Cju>G&eP`1g19yq1OnfUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dHn#w6 zH+MC{Z5~u_3U0R;;B<>V&@uX;s6~oum=G}ifSB-v3*^9)erg^ty%zx!wp~edHv^DGL3_8x3M>HM>74`sP?u&i^;e1!olzNpA@uje7l2lq4t4XhL7>= zJysKrgx(i;l6IN5aoXW9cGIe#*Cf7arL5B7OBBc`es=Upt>hN5O|NHaJrMe!k{G@$ zYszwF-jjDG{ynfo!2kRLVe3gMn;KLdCQbT$YxRuJyO>#L&wJTx^K#Cj7F(-ou{6FE zi_lflZ8qUEk9e8(-52l*sF9izn&)9*CD^du_ufqvr42kcn0pM}f2k*&b&UJNu#E9} z&)Rs&rcaM1gs=Sfc5cLy)?FcH$xPN)EZ=YOc5Inoqq_YwCofaK3oNTbR^G_p zTKbZEs>k^!5}JY2wuGyx{`u0n=?d4(V$El7tWN1YODUaVWZI=&_G+_!%Jsk%>-|dJ zai=cYH=#u=sBoqEuP?2~Wc9wT+j1d~p(<_imq{z83aiVSp3E@VV*4m_;f}*Co<~`9 zI-Aceu?#+T|JXFuN%~4m<{`I2wu{}jU|%p-rR~Ht#XMav;T4i|?3O(G*Z<l3^w)^1&PVosU-?Y zsp*+{wo31J?^jaDOtDo8H}y5}EpSfF$n>ZxN)4{^3rViZPPR-@vbR&PsjvbXkegbP zs8ErclUHn2VXFi-*9yo63F|8hm3bwJ6}oxF$}kgLQj3#|G7CyF^YauyCMG83 zmzLNn0bL65LT&-v*t}wBFaZNhzap_f-%!s00+w{G(#^lGsVi)(#YA^#MRZ*$-vFf(ACh=#L&{!#L3yw z&D7A`#K{n**Cju>G&eP`1g19yq1O$kUQlAlEdbi=l3J8mmYU*Ll%J~r_Ow+dZnrq& zG!Lpb1-DyVaO%|uIz}H9wMbD769T3m5EGtofgE_!Pt60S_ab1zu6S6tl7WHoj;D)b zNX4x;GxvKPaS%ARxx89VJxP&6Eb4~Fin&Y8%J#Li7H#ddYv@nVOj`WNxMS}RK6Ng! zuxbAslP7iGKOl1=G4Wd(+o89I)_a$IzkSAhre{p#G|##2$}4|%FfD4(Sn%v{_>MA3 z9Y*#oMeh^dRbQAawt;ik9*=lKC65C$+Zc9jOIA6M-6G%{qrt6Fuc-H6eZ|y!dscO} zo8K1``yi`yh`p)T0YddvTarCi6fsMI2}Ba zIoEei-2ZtVb?ppa%XVqxeG!;&4Qwk$7adUDtz z^=~%miGogBUPcyZylLdu7Phuq8Q%JDN#IrHsb+~^z(G}b6Mw<&;$U$7x5hc literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_proximity_feature.png b/app/src/main/res/drawable-hdpi/ic_proximity_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..5b80a88113502cd7f0e6d16de351f466396917fd GIT binary patch literal 2271 zcmaJ@`8yMi176IL%{3v{n!8Yrg;tVd!%UMAvm_(Rky{L-IdiXlU8ybPzKY0~K9&2( z%^c0gwd77sC?cOe|G?*cp7(u!d7tO~>3yCz=^EBtP(WG$000Q0Es(fBPW_ksynl4r zjQ#&VCKZgr2iy921cwp>-2uk8{aoE)=zGLF?l^biZBjt5y8!^ePeCJ%?ZQ|aHz|*v zTsYwlzX6cbkc$&)yY62ULlwxj6RF`^R(sjVwX4=r4!Fg0U(LmqB0P|MsarMaDE^xQ zXBPYl4sDIu{&{q$$q`5Wsr?V6bnQiA_ua-$ec5x6{pB`&3K4$%ny6|vu)v6_j(Tw{ z$G-IPcbohlMvN(%0r&i8MPG)=)=1N?}z5rl=3gwUpGJYIaWvTmXIe0<^A z7`|>LHC0+^fWL4&yV=}q+H7n$y5-@U5Tc1y^!m|;%H6UIA>U7-oqj{$n?cv8s;G!0e{jLMy2_$h2)l=)MAtd*;OzWZ6}M)l%!8mxI$T ziP;P}gYC928t=mtp`uL(51p4w7;;C`=AC{Qb1LdA*$g{GnNNZp_e-r5hr1e;h>;q@CfU%@av2lO4xJH)j#B| zd1y$&AxqtPL0*HA(%9!x_#6!}6vNXp!Z z8J7Zm59uS=4!kX}A2H!)_M@MIAhJ!a5pls5(&3i*SVDDN*rBUQdRfA{K&;V5-TTpS zrdZoS^@8(!vxHT?88j>P9VEp&-H|?6ztRWGyQCojdXk!H9ZwKDBe-bX=Kr}v3K{By zW(ZuClkiNa3dWq6-Rs%0v`e_j=Xt?#)us}zkZa5U@WXExH!VcL^#-(Pk9kS5^P9X% zqHWtaW)w9VRqrNt?%DpQjM}YcoxBRgkmHvqH>1;r@>{l!D|x(!^X0I9bU(}dx>^kT z?R6IdBo(b=KVxW4Z}Yh`cWQ4gL@kh&ss>&u4JHj26v7)HHEn#mb1NkllS4<-rU?FD zp?Q_}2#BmlfwRZ~^9PH%NYIxzNV5#vC9yk)w8f}n5@xc6z!zmd8zwUyq{i^K1PQ9N z$=?>Wt{B+WZ9@2x?V|CqA2&o+(2(1(l$JiGWfhW*#Q8fwMee}T94Y~ukUeay7I&&b#r|g7Qmm}6NoBc+ibMygbB;PL*L970rYAr*ykq^DpH7% zOM+aak_c(c7V|{4TT`GYkdVL5wkOl=`i;HL%CKdNp%u!jpw#(ku`;4>x#JWq5l{NU zqGg>n|I2CXgzSu4*}kQ`_5G5`4`%i(?yU}K{XnLVn7GW}gC|L9Tmi3pEEDCQhUk`7 zSGY)rnQTlBb~e!GDQLqJi) zV=+rB5Lp6rOTx9U_x)mmF|My7&i9D%lOSHB!^5v#1%jxmFs^%LZzQCvtoxalWws-y z*iFGMWc(X*?kJk7`@`jAPck9ho~y0*upW%LuKm0j@)jDkeH~kC$6MDL!eapw#}y9y z=CV{xGZImZR8ew6D%r6y=*F{@kkNthWD2obqy#x@al}krQ6E_(d-Uz~L=&o*AFV-WWUzRgMV~>5;RGJ*0=7D?Pa~B(*tKJkCS$NLc%FMO)z| z`K}xn7pHyR`v4!5_`oQN7|`(QtF{VZQs=WiMN=RrG$Yrp|=_#~XO?k&^-72B6th=OBl&&HpCRC@iwZ#3kk*SYIVt literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_rsc_feature.png b/app/src/main/res/drawable-hdpi/ic_rsc_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..8e45929ec27e9444b841f7d9e4d9c8c14366d53f GIT binary patch literal 2525 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 IM6N<$f~#!pfB*mh literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_rssi_1_bar.png b/app/src/main/res/drawable-hdpi/ic_rssi_1_bar.png new file mode 100644 index 0000000000000000000000000000000000000000..72b6996ad4d5af7bc00ddb9b96eb14a242ff0131 GIT binary patch literal 1125 zcmV-r1e*JaP)N-}bIxzh+#+XLRwjjcyndTpE;Dg`hGJNAItH>* z#32_O7{F92<)m7z9@S_x&LbAHneW(QsU+LkNhk98{D*3_y2vnApqk%2=qcY9C5P}+s0<-BbwWV z8@He@yFFf|e=Tq?lgTpde>RB0>+?@g0|wASvB-9s2?ghqx~@*x(RP+hrFQwGdQ;H? zG1BXFD^_c-lSFVz#S)V*6t=6C%5Irqf=GFn>c4{&-KAEk`V>lKx3;V6uvXipLWZqL z!S#)|rBZ3Eskk-URh;xKm&$Ufr4G7S)-&+C>;LAC(WTdtfjQi z)(kqA%T+pQS6ehjcOlkx0#+wl|3cT4QS>x~lK>vE7ZPflE5+;8x}jJ83rz}Jf0pv8 zGx$z47LUOgQbDXg!Wxezjthd%7TJo1a90=tZk1Ym4FnQ=;X=dWah=1WyZ}IsU8oIx zXEvMqNZLX!V;Dx3NF;;VTyE4c(7#0NkhE@uHUhW?bCB#f)_qurD$+8jb;(`;>^-p3 zQtWE0-LCcgf@2q4!>Bi%KX%l9UPuk*^92TFLkL|LzgDYkgzI{!)9LI6gI*;tmIV~c z2(=onsW)$x722KcsXX6y5e(gb-&1_2)x0CCZ&t);C?I9qfkQ0K?!BVba5HH58*W{- zy9;ya1r98>Xf;AZ`qI2Eg75kh0T-6&SlWZ8(QmhE8A)J?fNL)fj8flfmO3zB zXsKW&0d5B^B`o#EqtWJGy|yiW`5ek-|NKi1=;$EP)w4SPmi0E;ZtKqJ&HqP+X-hBX{Lf|eOHR_H{r|u3_y4~CcR3Z8N+ppH;+gkZ#A1=Q z)_2GTzsu=Z6~YcN*T4WKlSv2L+S>NZ<#LxnuhY?8OH!05l}g96+3cUiVsSj5FO0gJ z_Hau9d*;1Ti9~XwL!mgO(P~`VicYQD6^0yfNheFMA!1Ly`xmRe1ig3}3IcPn_b znIw|QbvmJ5H)%mKQYn?QX0yq~CgD&dmCtT$tP~4{^;|w5M49(?`EO80celx8Hi=Z) zp=fV^M4@PxA;Hc`!G*Dd0TwQOtAf_La$o~pXy_M!@jfsU*yPH}2AjLdhsV?DOpb0A2UY-9HA_(7RX*=1 z+b0wb-=Y)d&>e1uwAWG(dTnj3&`Mry&={QnTbm`Y|LQPIIacfTPQGiE7xI;~_w!6B;)e z4P8tXjs5VWJC#bE2?hdBCzA;Y8*f>yHd3q8U43)pjc0JyM`Q6QI`HG=u$;XB0MJ-8 z`m4v|u~8Js={zi#Zxgv(uAtsv*w4o6oB@CO*%tvmKx=__@7Z$&*W;{#zaJetF*`GJ znr-MZ6}anuoIHvtNF5d3tJUAKzYWBjF2ShrbyC;BBiTYCa;#gJ-v)WoDuLxpL`zrXLiOyH_IALrr(BN zA9|5#mcJVbKSdY5_wl~pM~06+PgjSG;r;1bT3iUNuGW8rY_~fy+js03!f7Zr@8x}u zeRpmYl{f!zBXE^UB~q)^uksqw7cTx}8NYV*A!vdiP!@G#-K$3O^|$9PO-@X_P@OLT zw(p52yN(=sDa?D)s)mN}wL2VrT-3>Wp?+&}a^gWnz=dU1mL5PG493iRC*M_z1d!A3 zf0&L&mkC^0Rxje=LC_kZry{mGIsb2|)kP+R63DpG<>i4`EJ~n;zT!JnpNl%ZKB3p^ zKYnen|AYVCzlYVJb9e5H&}~1VZL~X_r}zZt4H$-s>FFsO&RU!fYDNP$QvM;y|-$Dz*$57n*NaUV)iH3jxbJFkNV& zUtJP&4PA75rm4gK#^>4}W0MKHwcv)yz ckbeaj0F#H1@EcOqi2wiq07*qoM6N<$f}kjL?EnA( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_rssi_3_bars.png b/app/src/main/res/drawable-hdpi/ic_rssi_3_bars.png new file mode 100644 index 0000000000000000000000000000000000000000..ae512dbcda218d9d2d4ae63db585a3920a87fdc9 GIT binary patch literal 1356 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 P00000NkvXXu0mjfInv_8 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_stat_notify_hts.png b/app/src/main/res/drawable-hdpi/ic_stat_notify_hts.png new file mode 100644 index 0000000000000000000000000000000000000000..4fed0936cdd6f424f75e0c95be61eb11d9eeac0a GIT binary patch literal 551 zcmV+?0@(eDP)NuUm_0QVx|TVLf>Z>deS zl8!^_!$SOsdQ3g4R{B2Q>dQ91kG+gJ(j(Jq8{e-ofjX%d0|gWjs`u4b>WsQGM-IJc z<69V5g$4?!TO0dFQ&&%_d|Kl_3+w@wftwN0>Nn7sdKoyE0PX^t3h_rk1rYe2OQ9Oj zNY~qo?IJ=!~boW(YrQ5dA zHIUj+?*I>gW+BuBrh(h)fh>}$BkDEvw7TS<_E|lzURSF*6xyGr=?1X1O?(S*5!eh& zYD96+-PYP~gb|T?X>}C13cLq)rLpEyB43Dz prLr~~>V@D=;i{cv2fgKI2{1xy8u@QISt8(2@yxQx4Z{Zsps{Xe) zfZ>9Cq}MQ?<4pB;<2)wu27c-l$hvaV*Z2iPxV~TxR7{=4v)u;SkJoXc-0^1VZ^9|O zQ~g=Y_rfysIE)9ep>%ujD-Kuxg|gJvUH}bXEjHm%d|$44zQ*^J<#t@e-fNmCx6?%n z_z{2L)3VNR0e)P$YO2G%2C*G4Rv64;a=Ada;wp?cg8N;Z!!c~`aG$s8FsOuj2rpx7 zxj@%p8}?$ZHavx09jxug&RVm8ryHqbw5&XEF)llf_wW+7b-3=bTC<3!N_QKkE00~U z)-}roT91+Cyh*{#;S9#nSMdj*;J&iXIQqMND*N$%Ba`2b-|;1`F5M*V#cSBuZJ=G1 z7B=9H%1_fZb~lccrHP3r2_EisjkF!AJ%c0F{^&y8)HZ(vw{#O|Pvxvu9rvQgHASCk)lQ5Gom@*_Qu$j9cE+x7gM8F$hGh*C0ZjARDd_R?4%7hUKrvA84Ih`1q1`^y%7D=kd8#bzACHom!vPVVPEFI7}an%fM2Yfck&>rsW09RH@q}um`k#xxWfn sp@@joi%3R9?nGomDfN{51M;uz6}K5zIQvFeYXATM07*qoM6N<$f{2vV%>V!Z literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_stat_notify_uart.png b/app/src/main/res/drawable-hdpi/ic_stat_notify_uart.png new file mode 100644 index 0000000000000000000000000000000000000000..a0811938253dfed1dd2c443909cb306415f6e8e3 GIT binary patch literal 696 zcmV;p0!RIcP) zOGs5w6o&tG)My~|L?_L{1`Ps1C89}D5QI^Lvmh)QG>K?Z1m(O36cjxM6-YuL1ST0p z*C>J>LP$h`h1tWTAkFmpy61ciTGsYzm%^N#Z*tDR&boX5`?dC!Qc_Y4T(mk~%)j_8%6EO>bKG!|KDqvfX)9rn=0KJnwez`(wlThxH~%*G|%a{W?Lk1zE*Z>y=K$i7K>>^V;)z46>hVt-aidOmGo2eTBp z^Q|P*1S4q&t_OMoXavTBSSyeT^Z;-b7!P9CfX+alilGb`0(Sgiw{Zu!;8WSp91SWAnx_(2mN%%oz#$;#dfas;IE6QW zBf)Pz1BZhHFv%XE6c|XLwm^ZP*w_9NPy*cd2C~2=H+|V-jjlKPQ62y)y`87-u)%Zc zgMoYp$`jZCj3iK2a4vzplj{oX4@T9N!1lb6)&VzzLe&K93chC(*aF-Oa!z~OuYj{a zRM1cii-FN#295*0L4k{BD1iAoH$&0v2byD;5A5^Unu2#(uykupdf->dMWl}=jm`23 zNsyM9R3~XS(y_?w;9nV%q=`6QSR6$S30fJM%KSt!3pW;-Mv>l{bl%L`6R^mP^gm8Y eN=iz~EcgNF=EX@6J!1U;0000Eal|aXmSqq2Yf3&+`K}eRwh&S{oZ1CpI=Za-B*)5^%5~PlF*bkxf2Y`;azJ2ZN`p KpUXO@geCxxc^)zV literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/item_background_light_p.9.png b/app/src/main/res/drawable-hdpi/item_background_light_p.9.png new file mode 100644 index 0000000000000000000000000000000000000000..74947f36ac78e7db805e84859dffcfef052efad6 GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c0!3HFsSlX8YDb50q$YKTtZeb8+WSBKa0w}2C z>Eal|aXmSqq2YhPnFEIo9Qd&R!J+LXY;0_8oNO`wXG#<>XlkS#Sjm*9!I16FId8(W Rk2OGj44$rjF6*2UngE-_A|U_( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/list_divider_holo_light.9.png b/app/src/main/res/drawable-hdpi/list_divider_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..0279e17a123f8cbb3c7e3a9ce5c5af8e693b6977 GIT binary patch literal 76 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1|-8Yw(bW~!k#XUAsp9}6B-)+^LX%RmN2q0 Ycy4A9FVZ~13zTN?boFyt=akR{01+Y(GXMYp literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/nordic_logo.png b/app/src/main/res/drawable-hdpi/nordic_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8b9fb39d9758d3953ad55b34a4296038b872f558 GIT binary patch literal 29716 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/proximity_lock_closed.png b/app/src/main/res/drawable-hdpi/proximity_lock_closed.png new file mode 100644 index 0000000000000000000000000000000000000000..65220ea49d6e26f909e5561337e52d4a259ab05e GIT binary patch literal 2675 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 J%Q~loCIGUAC13ym literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/shadow_r.png b/app/src/main/res/drawable-hdpi/shadow_r.png new file mode 100644 index 0000000000000000000000000000000000000000..ae07b59379f5fe0924138b29cab52307382a0786 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^AT|>R8<0#)^t}M2I14-?iy0WWg+Z8+Vb&Z8prCAK zNJNQqer|4RUI~!Pz~Eeznpl#WqEMb$lA+-4=^K!um&y(lH}Z6G4B@yQdwe190R;wz zgUr#*hZoPBSm?c6LqdpS`ko&Q`TylqLPSznqPvgt{8|0bh%r8&eUr=-Jp+)jp00i_ I>zopr08LIT;Q#;t literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-land-xhdpi/background_image.jpg b/app/src/main/res/drawable-land-xhdpi/background_image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f8dfa38cd2bf3be58bca2f4b383ffee008a41c0d GIT binary patch literal 27426 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 BPP_mB literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-land-xhdpi/nordic_logo.png b/app/src/main/res/drawable-land-xhdpi/nordic_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..24a9d4e768cf261deeb29285d700189cfb0e8262 GIT binary patch literal 55949 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-sw600dp-xhdpi/nordic_logo.png b/app/src/main/res/drawable-sw600dp-xhdpi/nordic_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..ec31045888f9ee11963635c837e5f1947e176372 GIT binary patch literal 51335 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

ce;d3z%%@d!7!!FX*-$v?$7)bmS`2^JHtYY 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/background_title.png b/app/src/main/res/drawable-xxhdpi/background_title.png new file mode 100644 index 0000000000000000000000000000000000000000..db5c4f5e8fbcf4980ab331e7c8f52666d9c6b959 GIT binary patch literal 13468 zcmW+-b6A~kAAhp3md)j5EZ4GaE_>OwmRq%KEZbUM%eHO%eSYuxqpRy&b#6TO{r!G) zA{6B%P!RDE0RTXek`z@200;~4cM5n|@MjB3+&=&y1*AlURo$0PecV*Bq^@1Z0Fl768^2!zCdfruw1{oaz>C8+zN zNg4Hg_Uz^H?=mB5T191A@73AG#RUzU2x}~|Z<|G4UViW9a7pz6;ZJ*{Q6GRS{%L?; zkYaze?c3Jik~SnT5hE9E=~K1Z;_{1wfgRJ`-MzZuc%F@eox@jp-w$JV7fV+xBxJsh zm5u1q{pD@d>;5DNAsUaXYJK7UaJsky0|SFOElgtN@5=9^_p9elM$af0SJwn>ZSC*w zd|75DHlieGEt5)WyPGLK;s;47q$`Cx0y69q^&#!5?i>#p;6WR^51t;Gdo zW8-fhW1?f;sHL8!ixouXKO4aE1u&bmoSmKh>+*ebd?U-?bAUWLKJpjIjYAg^!3~{_ z5mR(hnO^3gS108_LGi$dxPb<22FWFqlpOx;p%9$3wzdf?NgakwmR43)^77J0sR;=I zt>EjeoB`-V4>jr*A%}<%O*dS~=Fo?P2&cr@K!EPvyaZ>=MavT3P@5-mkdjTpn#t=n zyUOdU_MaOPhLSi%JFn&Dsz1XBc2D;zhd{S9m=;qeuU?CtN#(b(`U>O-1 znFs{^#Phy=b3PyYMgMGogN|vUrlJA&#lwTNrrJ9-rxf9(3Q!;g;w7PpiHRAgzTi<& zQMwQI57>&sfA9-T=0Sjlluc(xm_Jrkn7NryR8l#99lRUOM3-Z%@X5%?coy(`LwXs!mTm`_Cg?c6WA_#bs||Az37- zC7j>S^fq>O{zy_P$45k59=`1s6coCp>u6(WN)`}9_`a1OIHh&Jz+b|?mp;5ndxa172 zL-{IBLCM5*4UNnd8Atf+T~sv9Xa{?*`~S?orA0+q)YY8bTobFS%tesp;II7n(h$ z1J>5VPznFMEz~{#9OL<(hNs0aFz{(sl@5z%X&DBJgkPD+)}4ZqvLH%`v>Ta-DDLOa zu!OB|%^Szdkidr9_FlLSKj)_bB6LWeO#SoSj-I@C7bm3ah{Jj4w) zTkk7HWM<;WT2{6gc|zVSINX(lrqoV=x z`C}6Bv_II}FIoA>U!9C82#90hxVX3`CZ~h;_RJ<`XZbJrP8I_TDd3ZD5+0^E4Cw-d z0Dd1Ix=^ErzEzwL#4P02($ccMp-*1ywQnl$-k1*tt4_6bweRJ(L|+Rf>;?M23ZWczkRd zV`N;|DKtgq=H}iiFE88ZzurHgh_7*eWW8bD5MIm@d^7CZzTDW_6K{4rJ<8doFc2pP zXtJ$2HLR*xhoy!~>gql^I68hhIyl0;>nIYGAt@{@YA`o3sh;xmyg0(gkND&yiyX$R zo06)*BB8&(WAmAjHrMaz2H{VCe*nX0d1g+QF9k(Kt#owkZgxAPWuF0N;=yiKwoL%{|?u-4Y51_p|>q_?J@FlF5PJb0 z16x8`Hr+c|Lyg=4|BIoY(q+;kY6iSKL+0|C34ez@^omML$!-QCa}rdbTB?e;_wUqAE&6L<)MQ|OAG9*np*Uh+qu6aWne}--_Y>z2NM%h zH-+ge*8{jfSM38`Dhk>{MjFbbw8Uf>l-t`A3Lgs-6Ura*#X&70Few>Xus`JG|4vOQ zOUg?JJ}C{gIK1)%$QMJUi5zC}FDtT>^Fb2O6nr4U3*p0NgoFg!h5l?rz66<|Ajx!= z01+CXsHG%@@e}>L#buglUs%XLG_ivp0KPjp^-b-L!X=rS8;@?Covqp0@!%k?w?j-d zVG=@y8Y#wQqdD^s{mbBc466&;COPhC$45a%c^I62@NyAweUOy5uqYW2XJR77h*+QY z$3=#PhJ%3!ki5CSTiO`!?aixQ8!ZnOAwz3XItV=Xz{b;Bw5z&3-jwqdsIIQXxNv`Q zLyH90*i>vjj^TzjF*|Lo+hE4wr*B96E4_6I?NCE3M2v7SmN@y~@Q`+)#+Cpb9{Rr? zudfh&7xQ3xvZq7wl_GzhfXjaBhTkd0w67>;#(~-rSlH=^H&7KVFgh($yC`hHlBArv zcaxEmg5b$SJ)$d<^qc!VfQ0kDqY$oO$id8haK*I05QB1YaZz1fQbrd$Nny&u z$*ju6!~_@F{J=B{)xLke-syU4Rr37sVXjhF>Seazb8I5!*jBIegeK%U5o6uh||Mi6JR1yCWqp4@-Xe-ZcY5s&l@^~tVI>w8BnparXe!gff9D8(qd%F?oVOZkfN$&gIn|R^A-p*GAd6V zPMZ?Mh|j)`(9+W0x>h&r7ET{-Y#b~Q{z4aYZ^!FvjSwY2{@xM^P5wa=#2T0Gp8z3K z(_K@0g{nd?w{uvq)j>i+g8Pxvk)MwX;bB(7C2;fExQO?OL^TYx8LKDUenOj%& zbPX|Za3n{EZmO%R+vhVlQPyW?Vbqe7FTmnC+}D>Mhfab9)_HF`Bt7(?VdMY^$K}zr zE+((nrv{pV>~!JUH0$W%s@hlN=Qz^9FG+*E*UC0 zyDuyRCxz&gTW&2T;yBfuXe#0jSyWb3_HxkEw?YwyTFSw}5s@~|!iW+ZsS1{QP2NAu z$cC5>`$I!CYmv3J10#`$G&D2-h}uZeBO1!e%1*(;uc@GbmXwqvK(qB6IweR+Ib%EbKDCNuKTcqkbMn)stVOGCM5-JNQyfHCp2);b{K}jOtnf+Mh7=Xvk0T35v46mQY2jg7DK09A=Cr*KKUS}3UDgF z6&$w#+!odidl~<3In<>b8Xe5w9|iO-_(_!CYwR4?9Z_ykf)7e8{9y333JQyUaN4gp zBayM^;cd3Cnb&mLRI4P&3Qx1Mk3s;bBz!k2EaTI~@+zF}o@5-RSUX4U7j3UAFV;pA z`wtQBYE-5LzjMOpDztvd9p_#mQ?oHL`mB>{aQ)#;gIjI$LKBk^t3$;em6MiE`QmuM zEGH_2UP?<#p|Kxwu(s;O^+BW-$}3%f1)P5bB5SRrzBVj)g;4Z5o$;R0ZySde*C3Qc zML)nrh@CbO@v5QR-o&Gm2&RMU8Jo+-aveQa7ZDRHd?gJ^p6Gdnn@~L)Mn=I>+c9j) zp`l}?gCV==tE`?%n8N$T={{&(QsTR}ofg>6-=R1(jZP^5X{Tjq9JNzW5FeFzokL-# zqQdr>g5P-Zt>YP;>E5Iuw=8r|M-vMqz$QXIh)7XpCkvev`VwAG=2EOM2v=9RGJg6m zZHY(C-D_(L-RSWlViWefu33KfmF^R-L$k?hZ054lmFSx|LcUyfb2lBXyI0AkQM$VE z-KzTalh%EYzyC7)AmiNe4OGBNs4?=z|n4aEKW#Z^KkAt4?UnKNIZwcO~rTc&L3 zfKWh5o&EiKKu$0i-LAS{I2gTn-gDehONzFjtR#4@O3TZ$I;3^2e=H?M{TgdDMFajC ziS+tQ(ZN=TAleJE@cCj#*s{$JOMh_xSUH(RalFR|k>@89FcQ@lmzT&8SXk4IO`^B9 zws4SD?c$@3slg%H$9og>H8kD_gbMl zs><6d(x(pPEyIi7yL_#+vvmXuRR39pB0vkAQ&s!=1L-6!)bmMFP51+2bxnt&zP^KD zvsa%%FkB0xvoK#`GcM=#UVeU9Z1Wvcozt>wr5>*4B1T5G0l>`c?1Uoy0tF0+f||s{ z5)%>=3Kka^xA)W27 zzSYnA`j76#ZspI7`Jq9ktifUHQk@YmRJ6GbQ0e&#QHr>#W2-AEL13$^GX;rcd4f&v1kbL2rFZIEKtsi8 zW*QGqbM%d~yNY7<(_~QCPN(UQEN*$KsHpRl_~ek8B+Q}FF&7E=OBAXmE;iDa{-{w= zj0hT18c8k=w(GZI?9)cu^-i0BAgFe)d(>Wo_6Zau6#fwOExgGw+`F&odiLT&tIJIt z6cps{o%M}*yYw2piN!rx7#Le#7;jgV91ZM~q-2;T9fm!8c6MhQdqtm0D$8oGyWA9P zQU(02tgP<#Ow6~5GBONrTV0Ole;c?xe9!Lb>S7cRmUwxrX>`3eAtna-eED|=r@Df0 z73omVf8aqo`BR$M^Yrv|mzS4UQI(eu5!M$Y!@F|T=CV1^U`@(E4jC#gjwO$Tqa7I$ ziCh}HzvQy82K5}Ihs~({w|}g|W$_A2=dEb$x7JgQDjkQAq9S^perNEk^}IJRL%YNK zTE||jiwpDM3}$_iWyg_@c!tR5U+k93lpp|kSkPQ(G=AQPP#pkGk5YOnA9Yt&QXqhb)fRq+ zw4~&uUDTsT{9q+_cqDq%;Z3auPQKdic*6-c?oRN{KE}O;oNX`ofH{<;DiqHxhah)zgIKr=Bj`L0~5THR1b5grk_ zLhyOlx;-baXvxybtZ}wy@&hXy>&Ec*U?tog$p*>PCSLC$3v+775rM#>c|l>?+pGdh z-(p?nGjeO+-1XD#F^}!(Nuc@Bfsn7S06Y@XvtFBHvRgPVQ%YJqM5MHI4wrRGT}sMc z|NeNEaTglPLop>)MR`>f98Zio-}us!sFGBTJEiMEiz`v%^}XJv^?cP}O?B;?^Xoki ztW-qAv5t-oL~I{cTXRcVNm&_k`FMy7&g8B2d`*j!97(acY1Y)#98b)#d7P{h$X=#c zSrxB0p&qiX84;1a|6VmQhu3|SmXp%!A0IzoyW2%NI5;vhF*kj$PH*wvmA13Q!~2g1 zdXHz(BZ7jG+ZXvCG#nhZ$^QQSUQQ|>Q+2dO{QbI{&u#Y&%?F#CTMT|{we4MeH_fNW z$7aPt&YVlZ-l=hCN&1=GL2~G%UZpb%(lVxGHPsC{VTgw;-gzEupP+0$GP8o>Iu#mB zLvwRKW~aUAzws+>I}1wC0Q3039*{T;jUO|BaeXwq^0pft9peG2jXS%$HI)W!pHI}Y zd(7)8^M03&NEa&Sc2@o{JwIE8i;R--JwIQ3`PjXEi5n!}l#mktnPkidH*}JnogP(F znnm)Nh#>2@0@jr~-y&MOnWN2E2Y2c#v(`RLw>XjUQ^6o2Atq#EFQAPJ1nmgJ!N8XJ zyuG9~<>y1SFzF-5fZAw`dezu+qkz@R%^@8U5>irfa%q46fFp9l_r=Lch*6E-0GrA* zHI&ES*RMpv3RwUS4o*o~sZVV+a}{o>KF(*KsO!&KjjB?blHpHv9vh%=swD0y?x`z_ z3`!h9odG??htmxbzsDm5>NEgCsj0CEF)8gi#>>o|W7vLuCZk0FxqY?E z^W8?mR>EQa?4y?G!#o;^0MO+R(3F?3$KLr8Wu|$7>OgLJITA>$eYtl}u4d^~BpDcx z>5?P+MJ05`rY2vV54Q>{YiqA!@~Pr2LA#)~zBcg34^&JdEEt*9)%%n6wyJ&8KQhOD zkr{Z-JVPTRA~M$2J(_1+b=8K+3Goo05+ms7>D;H4l_g&@Q?Sa_v8*gDCzqC%NCgEA z?gP5s{de+83nM_Qg=>F*udJ!Dv6s)1%= zOyQr}BGo+C{sl8{1k(rONIp%=@{z zHsWW>!?~iOR_j!66#v5_W>)w!Gn0f*@DYl3csMR0;i$O0ysqH6<+erLY9x$!Sd#tIJ)XOE3@kx)5QRMSd3+1fi| zPq@O`-JJlPiIqg^pp5pHHjoy_ma)>0jOG>v-dM?x!R<{;MRd|&f8k;@RqALidqk$QwT97S7kSjX%WVmPY~#U= z`q*(iFM?$@@lT(+`}?WRYD_Mx!`7oB;oS&%9h1h4hZ8E>n(V)R{R(yXuR`ZLSVQB! zhz}Tk`v%G5>B+ooamVy)Z5j_*QB@f-G8p>IQuCnXTth|WHZd<;1(e_K!H#u+m-CO3 z@=vzya_wz6cxu+nb8|tJ1=c6~djFp#sNgz*@|TdNBs{?joWs#y%X5!CY!z*4Iqe%7 zQowC@%Cz3|G+n7l4AkeGo$G_5e=~SnSy&L43*e`xYnqx;{f8gURy*cFO<;&~(D@(Q z;~+aeO3`>K1lT|*GDGBH0IqXIDE|2hYerhywDzIZ4#$8F{{I%{yI}K?5cAK}$_zA!9}K4o zq~e~7HU#hF_nc&F%s*_NrR-s2@?;7e??ik=e`LiNz{*;1BqAIh2MXZxc&Kh`ZN)FLwEpjW48|KnRUK1NeKMM2ojTUT zX{B*;aw1siazjHG(ZvmIfB>LjU~0M;8K7NIP~6{67UPr4HGCdnYNXIHv5B!-Skhz- z_cs6-n2;t>atB!nZV-W>gTT|w)aa2%``f_g_ihu`fY?|xlieMB3wG^Qq1=*9AxaDf z@W2&*O|EII`2+#9`#k@n`TS{bFKU1M7cUP_5>J<}>9C|i*h4e-cNhHymALHe0Cd&? z=96Pmwq#BK9RNxyUYjYYXbHa7m<+&G7VU{Bmfk0|5nGVL4ZV3LxyGDh}$(S(Sa zmgP#XmY`QCbWo2WsIH=8qT^2JJJvc?OX(&;f*zMZTS0+|+IL0tW=8D-SOCvw6hu0= zk|0pr-X9RJu4(WoEh!n|_Iz3Ji>4vZ%SQ+N&qI)?+FVaklR+p1%AI+iUGC9u+q{a+ zFdLykCQ`5^@W;BYm?+9M&Qam>y(FDx{d1J%qNRBC6F zePIM!`W=voU!0_IxVh_NO+9(?q)EhNEw6Tlg(&0wCG&f>H%K`iBG_C(9`oag*v`(* zY`a)t7|5ZfWI%3obuGr>UdVn(yI*fGrgq(Vs1as77w(3V6&4o21}Fi5j*bp3l+UNk zcW^xR6D6ey4h{iQHUU9#U7X}k!&IV3&^1jB55HgpnrEN=2EDzBGX-2CW0FHm_3h+Q z^Cm4qZ&6VEfbR2cR`~7jp#2YEB`0SZpCq-b?_pb2IXU_(2mwPTSN=7ofWIwoV;86; zH@s@}r6!?K4T{dK<>{tTxD;a8{ zqR{yG_!~0_*j) z+QwzK#4SiIXx{@Kq0fl$@IrEOD1`jp?wU-Uepbsd*7Gc0a9+hbGf9u2cMZi}EY}Ch zykry{YE>sbi_L@wUrEtPsd)(q35lBac6Vc2I|73OZU6lFbJEtFoiJ6=XM>y$J z>%@%QCjwdzj?FDCWPE&tA|fL5Oa?WC5I}Hf@Dk`XExEb51trxxFFZ!!q;1=gLJ=Zz zByhGkobqt44=hbD4eY^#tPjM>-tw-lj;ba}7y*)mb8WwDP5#hF?(x(Ot# z8xmDK-#~+g((mQrLqTC-59s`{iDihqr=goMf&T72c$vOxXyAy7icUZPmG_G_9E6@+ z8vh}=%b}p6@F)^fX59ZEiII_!Ea1OyG+yICWr5sRg8Jh}B53g>VdErDO;7n#z-&N_!eP9kucT0xG5oi#8Wjl@4Oahji(-b?mz<^xl&#Ouo& zwAaA>%G08__PoNo%tl zN6*&Q36MRgVPQ#2Nev@C7nh@O^gS4l+c}>eH3)+Elj8L^+$-q@1n0Wv+h-UtvH#K@ z(KGD*M+~r z2u1*4%h)*0$Y|UySODciW>JMtV?zTL*lf%j-|uuLnOG*WNn_Vy#OGh_vb5TK`726G z5xyC8B)EUTE>bu?#B(ev{hg=Fts+q@q9_Ru)k0Dbh-C?uwY#(?s+M@LrZ{cDVlJd^$2a*oRS{P^;Wn6M>K@ zU)+~C7+aIqE5iRlNeP`IF^U=48n1Lpd_a70iOq}|PxccwE-no|4h|fqgF{?G3UP9V z0Z|nc!0o(K4GJZL){p_f{n;9a_X`cP+u@a|#r%)V1!fiQAJr4pPmd`nv7m-`Gdl7& zohyZ@JC1gT7<8tS9yvJ`wUr^k<(`8s~~D?1iKprNH}+1Q31udYB0b^nFYS)Sl13%s^N3q$VU9nF+3+_KZ{u=2i~qH<5n zR!{qFe2Wn6MT5E-f2dqp zSs4L?ZvVCBLMke|yGGYh{kH~5p46XK+{@@bC2!T|8=XFWJ3Bl6zcW^v88NS}u1ecl zTZ~Aot;rY}XKj0!pKd~hKI^uIyPhr_x*hMyJ%cQXst;E8x2=sP$bst{>xDeE@g=3D zdm+7^mChsT>ubN6P8`PlN`zt@8zZG+M2Y&zX#8rL!YytO)mL5lky?Q@SX4CUbQEWy z%dKiD_Z9BydC>7W3|;;y<7A=1saQx%3(vq-4nrH@N}HZvnLp-4Wh)_34<8ptDu zwZX6y0U;)z#dcYFIT`H7F)$r*u~{D*tGzlHdr{MP7gi_adb%R@Pg3Eh{?R5`jmz{N zlj-?ro)>?du=w@a&5SDg2doe^>$$imPvgNKgg%KGNd=yFH2hvxpFYU}81ZoIu(J>Q>>3%YJStUDie z!T8)pCL2`gcK#g(17wLUEee@DUS@vp6cS<8@pmW$T-YEr?tY$9zB2h->1Jwbn)5qP zWVPLN6z2g4s*ky#f}as2^M9v|FTedKr}(@+xh%W|8fnf?ex$|)yYR&0Eq#W7i?l5` z%;Rg*>3w$TBcb5sZTDJ7#_jDb^ZF7#DE`ltT3eYQb1(ER2+~%TS80S(psU8j#N^i0 zd@xYebU$24t1GF$=@{^@D<1nb@!EFZ_|j-RxP~*H9TX4%@%#P?@>3AY=iA@qRlf#% zdUCByOrW#z@h?D#%9P3Pgq@s}gjy0i>rJ1Om|W+w-*|d65r-Z-G9n$9l9Ga#l5={3 zV`$=VX&)w=D5pl2iccH(K`N`A=He_a8|ajKN{aC(;6=?&%n$ElvbB%wB5Zu4@kho#6((LyggdL zcZX(5T>}lp=Sj65jGUVNN_FOof`8w9fhqU6##Jen7XxW_U>4sdD;EccgM*{EFW0N0 zt_|VH-=U0;Bm^XW=V$yTImNMAf?fl?J;Mm#gK@BnTFH1GVdZ2oN=!*EyuY~-GV|mq zo^N&8YrL+Q1Z`6#QFmxWBovj=e}AR@9yZ9dJHAmZwL4IN`!O*&8zOjja!6R!C<6HR zZP$3r&FO;dbBULick@Sfc4Tgr0MEG>u~@JK;mh5b`a%CS4o92satMgnlvGV9zdJfY zrpexUVSng!sUM$BFDkS&wnjR&wQatsXGgWPv^+RE;UgEv_JVzf`R?e7NL^FiTw-lu z82uq(N;WfX$=us#bZBeKnJyV|Qb~#KiOpqV@@v@SwnPA&m$?;40yy@^AM?_drYHN6 za6m%_=`SNg_weE)8W?E%={w6y^u@JaC|Y(dtu!AB%v2Vr2nbYr_D5#ang7cJLv!!| zX}6%z(eO64MNlygkMl+#+>NZLMp}zVFL6wGZN-Arm6-1!n!oGw&_~ zzyR)E#updZ!r~$dz#sIZrM-3emYTenwCk)2$AkOL!lXPuaqxIcf+CW?yIn5-&c#Yg~sXWi)^G-fz@c7pNzm&~FhRt?!W6;$pj1FZA7*ByAhDLE zp9Y_M2tfI5gJdn)@%9Q!6dU`$e|rv_%H=9ZNJ{b^S)Hv=`YM)8OHUgj3KP=4j`8qN*Iq9h1O_U= z6vf+wKE^kb0){Gov%`ZarmQY>_zT;wgPK{{iJ2d1Ka)p-w0dZ)AFIPRv+YnL;Rrn2 zw7)vI@+|Swhx%+M-!9`?hWcGH&!W>L!A!;D`n^O|osv-uTluvJCFAD+Fx`1G_#_{IMxs@z zUsJ0mCEqC{FO3hH>0m_Y{a%2Ajx@ZWpDHf241cM`mKPDhw+tQtwHZgzl`WHV|D;{4 z338354-PVBW+}UKV>(O8J3DQdCMI2neWUk!BxC}<|Lt1R4pv-xt@LrGj$13b$O;g2 zLP<#ad6ZtN2vaVNHN?u;_Ib@~dqG|yBRBt=hk-pw3)D0>_x4&R?=zShd%XHeU>Q+S ze;~^-GGY@F8{D70Zag!CB}e}w0(4PQlIo_#?aA0C=<~X*xmjsTTTLd@Yb-gjvf)u; zVxcwq!wMoGV}g;m0Z_pynmlwiWX6pSeR{$W@O|U7 zCLqX?)8Q>a63K`=;np78Y1tK=%@`AchPvkxqbA;QXLF3jN#d7gs)} zi^=>?!Et|*z|GiPZhYs{2e%@mkV?DG)fSnFBoB{H0=v`Bt!qiO*7TN!F>Va&m%F zWpmhY55Bs%l-=DN{wW+yF)A{1nm5E%pBZHYWnKnuLOV&j_>_1LIZ6zPKa6OQ#D+^t z)A~SnK{(E48|WT?NA|nSlhGFz4jVQBGo%w=3me^BU9q{DoYV3IM-69XSMef8=2z|5Hk~S86w)yYTAAk+Ho?pCR#2Rf% zdHNp;7w>_fF<~rcv+wQF`pE7+&We<@tY;iJr<|73#p83+s&}uuigzv}hL--1593Dd zus=Jeuk;-|{qEPW8C_5cNGYP)=e*2b#TFJs`QM)>vc2D@p9cB|UN2s9YfC>d2OuB= z!RVW6sy96l@Xs5N1Umm!v_3X)1Q-M$%w=^$!}`B>JcE(#qLnZ-;vwd= zzwS^_P~>oMa0LYg6X5qy2uEc&aa(weg|~u z(4j+z4jnpl=+L1+RO1Q42f=%x7M%-1!7rQ1meHqTVju62D0Mk{er`ivuztf73N~;61}c3 zXk5*_+@--Mkjv&drq^$eKwn>NB7aoaX1!i}418{D-w5P#)pdipCmGhRHV=Xda|H>V zdY$%2h~9#YzDS@)^m^>Ec*HxyyyJ1b9(ybv4~#&rj#0gDtLGyAEC)I)foAG;*yAxX z5CToq>#xVdBL|FLE*{#Wt4@|NV#h2<%pH=*w9Hu2EUqf6vN~9EvXO=Rt7wu$WJDyv zcp=up(2l$D3yNCk0)xQ>r-VU}a0uq`JkaUjrGjLBH6{%K0YUJ}GeD-S$;MBY9%E~{ zge+b#WU?|ZH?pG=sPo7pJLzMQSaaO~`X@y4&hFFPwZ1O2&$Qb)FsB~_5-f;<@4Y;( zQw1`jBiMXnF0w3BTyLZA2Zs|s^Zo5;W%siN%1=Xj(-f~`Igaj$s zU~owb8Ih6(iHjF*rvIxescEryuvh~33{OFtH-x|ME$8FHQwV~<1EbTB?j6F|c$w}7 zv8%q=#&WCb{wL3=lQ5I$9FEr7NqXTM=C3={@k$p2-k8>x5vef@{L4zVoUB0<1h(It z%gg!QEASt76(#`lhQ;&5xMTq8TI?7_fe51kgD5ciqhnNBo#aHx9J?)7^&Sr`+rz7y zOI#bFR%fydl_$=tv$nW>WI79P7#r{-mLEF9155X?_3kO$z5Ec1PN{s?4w)ZjWiviC z61&sYEHzdqq5vlv98CSPm}aR5sIWPM;`r+&>10M5$&5BKG}*$S#7K(DYniriJ*RIU z0Fun{8i(dR9-cIybtBZ0NDv^okDDX{cz1Uh4=mji@FT7qn8v>Qr}DwB5*F<|=3W*V z*58=TbKmVJ`}MWNm_%YsB3Us;dPf_Xm>x;fe+}mDA>o%^;U$n$=H033s)y!&v6};x zO}xCRm_J>T2BOIE+9uU=BaQ8h&2uCQp-rYmqSv;Ru;X;#@hO8SaBp5;>K>iJi(@0e z-sS^xI2oN3!B<6PoT+W%v6V%t_jviDWN^wCE`c&*jH&^;qKXDi*INOZ$5s?Ft8WxI zWDZv~A*)E1X1j`Xsy+qHO(4mk`8k1vtn+SoTTJ--4?(M=*a#yJPwdN)+xodkB*|b9 zXtcNLr{#w$RIiOO8!^n^dW&zgTF_Af+{m9|!X3guSXUDSQcnKtDU3d~`SfYAg)~1s+Tt6g@ z$0qkDuXj9=Mv)=O(JZ^IfU7>(#Z4lqzCGS}gA$s@Htf-o1ONudfeTQOssD^)zrX)*tyekU7t4zIo=T)7<234gO5P>|{b`?!_EGG3R zY=lwdr7MQ>+QuUaVqG^P`@9Sb%PwejU0R;VevkOGP7GN{=hQCQKSc~xF!0$(0Hqu6)H*gpKH z#NqL2p(c^ZWKxjm{|pUYN3S3V7)6n{uN%#Wv&Io?HuBApa{jvcIRF2uTvi`B!;>ou z-LC7K(5|1*VS~Dg3q*wp+OfJvS02D7Y0n;-+BX@gjf>hpF`92rdw1RU?%hjGO-)!x zG$hi&4ex%(pEeu``g3LsNaen~emr)`K<>-y$J^J9;nq=EOkKF1FN<33uffUD?iWjT zsILm6NH~WeMxuu%M6mCs9Jl>-RtNDfeCv7>8AhbXl5879+O@hj2jieCvL7)=n<0T0zfBsy$v{LGvv)&0e_%?cZ7Pgy+~F%gtE z+SqeOsn!B=4K@#IU2;G}HN+%#KNU73Q=LHjD;j;ax%XGKP~B`-1l_I~m_%1YW{i=a z4$0u=k(n&Nt$+`ApJeW5JE&^5h4i@#t{KI`>&I|;-*}C#9oa>q#+vR&ppi-HBO{Bd z)VnKEqt#`%7y%7(+L(e+@#D2jY? zQ=VswMRGt>ZTBKjYNWcGzVmdgmd&k-FN>6JY5&BiE=8azeG)XuzwFimp8f6+;xo(7 z8@`t!P>Uc^{o1Nzh!^O$a1|QR7L)weFr&t<^#A81+UdX>hQ= zqF&+dzC2@4mmp7s=w#K;Cutsk{F_3mY%Y@g^xr$lcxeUS71yz*xRyDe?;-lxr4&^J zW~&{oZscH}%iS+y!*`DVLBW~}B+5+41g&@Cp^74Z1v0opYn%e=Dj zsA6APlQL}4;uIP3*LAEqQr>Y1_>c9>9GvcZJ2)NC(%AJSkQUk+#cg3WYQNg|#np=K zB#W8e(VaVDB_$MfD;i%s^ex~G4zt<^jA1M5#z@z#vKT%2b1FKXkIz}nQc zZ6HBICs%8XFZN^))L3PfA5uo9Kf8HCXot6Y!RNQ+X&x(Uu(I=vf2!hV|K93f97>j% z^{>suH&rq*$>{%=?3BRP+%*Yw`_OpJ;@Bm1ck{=xdIoqfkpHmefMR=8dR%B{X?Vbx zR0|Wcv|}p+UtNjhXH{=I-N^P+zI#gl-gA<#u09*6ZRwzK?3BRP()9>*$KW{C{TohH zYl_;Pr|TKlD^ByCJ5DS6xFU@PZX222DQ^3=c~dlxf3&xhMn}hpJ^t?-xPQrR?2_jM zaZPrKKdjt~y}?B|!Rho*g(<#WC)llBi$D`nBYm=E6#BfRnz0$$-49l$z&qQE75n~j z)rhbYX!eK<&1uk1S!T}1I|7>8{Kx4-Fh9G31zV44s`dHn4zlRd))bb8Kn1bvbaldZ z6#_*Y)l0PIxONBMuCfNk_wpS6e`&*E#dboZ2|*5DI>$t_z8`p3SAT=PS`E7?|?zW>V%ar>wzM z_TQ}7$J4{zCH&9&#|NkJBu7{9!qg>DRkLS?JG^;Sg24Y>qnx2|wAiyF4+TYCR#_qAl~rW_>03VAcS`lz%X^#s`ih3-k#jfGPw_LhhIos9Y0I-Eghtij3AnxhrkqC6sr{QP_(BU@FO!)_xS2sweS%~2obx#CEr*K0SQ ztf3$?!RvW|cNP&5K|w(Q0|yS|e-F#({whrCrMHyUcrB3C;UqQ6dtSuy zW+x?eN{{TtD~2Hw+-w7VV@)3WyRLeFQ&6AR>?46HRR*dhCns~;sNUUQ0%>u?n+N9a zS2*XBZEY&v!Sm}5;lzMha0ac9?CtADX&x)7Yhmrl;LQLL1t@Fu&5o&VQFpax^h@sE zHqeYLi>8e6l|Wlh)sYkL-K$!EqK4itt>E6TcCn?jhI__mBRzE`)~Bw7e@GjZ^o)j@2~#oJ3+95}-@gVWrk zn7axSx{n09C|$h|?87~$e7?uF({)^u?R^%3(Szr6^T zsrKdU{0^04!8O`_Yp3d4cx~&+kknsQv)!-uuGNU@-!LS!3r&WMKm+5n6KmI49e&+Q z%ga!>@=cx%<=(N8#2WpR;bT%Q%o(knXXlFdHioQWBoEn4R0*U}r;$dndlKl?$!VHj zip}AVS0uCUL^Z?Hyd*9V1b(&5bH2j4qy0;|^nr(=8s8tQU{7V}(&{<WYzS; zf*>GtM*>aNn2Gw%kN%2$flViCnBs#W{pPk}kH=r1ITC~58+q>-nZfXM^#N^8S!U|O z&@N(K*=*OGU#5ls>{GWbCuhcm%!&?)8*dQ6tYNpjv%~kyS^1gqOz)S>75!6~&^wNY zFY4z>0I}w%_cSI+kp`B|DbO56Xfg=gz4%97pQ&v)zxcypme0)(cwLPahm#hEQ`Ody zoH7FwqnJIi7fTM7Q|p5o|G4lpcaL-L!g(;SH|xGQ(0$@SW)DVhX}$V*+rcT(Ovz5< z(wrnFWhJQ2IE^uTe%)RpGkIv)9{%jXYx>u$aiqtX$%<1CP8OEebNlE%L~A^&&gx*x z$r>KLcp%}xKW`ZAvICp#tUgx7>f==`KU~hiO803vT3O3}Iw%!55HfGugA3BJ^e)pg zEqr^8dS|Ba^fJYEY=n_ZauSI$8n8-E?2^-M3Xm+z#6=httM_PD`0i4V!&(g@j82bd za!!()Ko@||_LXwF!HU*M6DJ}MOw2idZM@m&r^~I4xCoSgkN@94BE0Ec=1)`)`8U`cESNbwq_c0P z+YV`o*!Pd?mAMU#KiZ=3B-_TGE3>aofu8^2wBkTCVAT9nePuV>~Cv>UatGT-p8jtOgz|HTFYhc`7^NX0`kHPqTu#x zUp}|vZD5m}q`&MwnJ>yD@=!rvo}N00(HXIBJ^wFnILa4AXH?&5?3+JuqFv&1QGh$g zX7TK_!OZCIKF_VNypc;526syH-?kPj8hh^OOqR`=z%x?^kq~KAsMGImpV+Ccf2XOi z;s-Bt+c)8@^$M}?c=Afk>wmFSIh{rn1xg;ej9xLV`GlT2n+PHM)inxYT>tOw)I2hs z_{i3Q|F3R7&dzp;JKw)y6t|9Sofh-ki~9pGZ^>TXXk%-wE3RgLMFT@p0$*@$ry?Ja z%(K&S&p-Fd0VzCr$pEUG?euwd4QoSAo(oikRW#Z7`}Pt=MOXZKnu0v-$r@u;8k}#o z8(RC~dgUTrTw8nkpVWP!E{i8D&nI5YX zs3X`~s?47}u2;O~%+Yf=`oN_MH};V>w$SMYD<|t(4f>=g6L*dEJcHxUR}NKdmo->} zQnuW7D-OQ3y@bU1-}2Ahr3xp!GY#i%PoQOom4oO1IMw@ND=ATCH@ElPipWb2D%Ym? zZy(m)h>I{Xx=k8lntP)88eE+BWb+P8+2+eKo}1r}4<&A;+Bt;)%IrN`#)JT6V58$>D}p3ah6 z#uKF#ER^B%{bgLUXqz8*)_datn5YN_%FJJX)TiqjZIYWB0=TGM8of^neOqh2ZJV2 zhaz3d%_Dj#RG_iV`T!eCYBc9qox`f5$|RvlUW|Bu(0)nGM2m^M-tjD*J%N_rUcp6u zl+pA+7pd!U1R9zeLqeMdvpJj$cBW`Y zK01@9rVJn_-ooLkCLUjPfRFZ_QmBJOi;;WAdG_2sE-b_BVHK27X|W7VjiJFVG3DJ& zIA!Sd$||P!PvQA#gPG9VrDhLTH*v=o%4}<+Ix!y9Z3#3gJ(kz58pVuls^-Hv{Xx3=eW1H?QV8UA)&Tl)MGH>rF;q4tI?F>;tVf&nXXsXxuo%{JN zkH`Nwbr4Ua#xVBH^=(wGz{(?)_ddEMY-e-<6?W-0DMjbG&Du;|7yKA(SWZW>2^ zd8y{{@x9~u@t(bUh_R$L_Izn&J9VHM|Qm+ro2GS}v&`fOkm{ma;m|K)!`&1%FM9TXpaNGyrHD7g=00%G}s&@N0}LrXd%hsTfE1gF+iTm zT3p*qS)&cfDU%XqVqlX0`5vQQUPrSeyJUu6$rVJne|UJ4D|DF6LCB^xI60cZ$wY0vf?5GQcHm%JKjQeyd~uFqQ}`lIyxUZfqE45t_&Tz3e(ZOI49@?(xKZxI&>RI zhi(Ju(4iAZN0%p%px0}Uv4KL;m9gej6C7#4;dF+q8ia1vY(j{sAmHi>GKd0V+rNT< zD1bvgdzNt4H5b%AcfoHl5E26Ye9hU>f91s>JM|AgY&LS+O!O)pql$$zg;pY+BUJ}< zNN77#Q?sGsgifMxdRc1ZIY$Vg?QwLCs9}l)Q&uDi9?&;c_OtX z5gO{Pvj_x`oCQ@UgSLLV4o@8NL>@GVgu6r%1fNJ0zVSdwnNWR7mqg)GVW>!*wyH}@ zA_dtCvjV}JEtl8}YEE}e5{28fJNLYxK39W0YD7{ofixU3Yaj$F0R{xM;u12TwhXsL z(FK)?)!Hv;gf!Y;Cws4N#rbO23m%B3cCOZ6RIU-cyia?7U90>;djjE3AfHI3@;{UY zLZHH+69^za9qP(KEl#ARdIc}XI~vLm{Jh><*hKKL9D!~N-rRT}B~p87EP)Z}1@2?4|CV>PXJmR6LPM1UhyYcuy6hYl zR}PFoE)qQqycm``Xs+*~lBk=E0Z=6lsP=bxA{0Ey{llLPTmrR{s0>I8eLKluZPe9S zpoX+6aeUriK}B&IzrV_BBly#mkq;aTO9ezkgRNOtXB`ti?P5C`#Gze}eA{CV+oisc z$3F?=l0sJjUx!Cy$Y5(B6r<>RloV2^H7~>ga7zD+Uyl0NPs;j5qPu{%!bT#yRVPu0 zq)@x&RU0tY{v6r)0KXXdS_huyH;KY4i5xbaM1D7C`^9TCNOO){vV0x)4__R}6a6Jo z4zM|FhP7nZ`O(p))gq1SpK=89xp(NXKq=c%B8A7rmt}BDx+DsuN!zP2L3osVhs+Pr z)BGZl06YRbPAI!QWZ8GmOqM$|K&ne4pfa7mt`2wsQGCu@kT84%Qj%#bFcX*v3I&}0z{11JW002ovPDHLkV1miBR5$ + + + + + + + diff --git a/app/src/main/res/drawable/background.xml b/app/src/main/res/drawable/background.xml new file mode 100644 index 00000000..bb025afe --- /dev/null +++ b/app/src/main/res/drawable/background.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/button.xml b/app/src/main/res/drawable/button.xml new file mode 100644 index 00000000..fe223802 --- /dev/null +++ b/app/src/main/res/drawable/button.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/button_n.xml b/app/src/main/res/drawable/button_n.xml new file mode 100644 index 00000000..0b903215 --- /dev/null +++ b/app/src/main/res/drawable/button_n.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/button_p.xml b/app/src/main/res/drawable/button_p.xml new file mode 100644 index 00000000..d79ca8aa --- /dev/null +++ b/app/src/main/res/drawable/button_p.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_bg.xml b/app/src/main/res/drawable/ic_feature_bg.xml new file mode 100644 index 00000000..b06fc4da --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_bg.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_bg_n.xml b/app/src/main/res/drawable/ic_feature_bg_n.xml new file mode 100644 index 00000000..339a37ff --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_bg_n.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_bg_p.xml b/app/src/main/res/drawable/ic_feature_bg_p.xml new file mode 100644 index 00000000..5e0aefcb --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_bg_p.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_small_bg.xml b/app/src/main/res/drawable/ic_feature_small_bg.xml new file mode 100644 index 00000000..8134d3db --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_small_bg.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_small_bg_n.xml b/app/src/main/res/drawable/ic_feature_small_bg_n.xml new file mode 100644 index 00000000..324d07db --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_small_bg_n.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_feature_small_bg_p.xml b/app/src/main/res/drawable/ic_feature_small_bg_p.xml new file mode 100644 index 00000000..99ecdf8b --- /dev/null +++ b/app/src/main/res/drawable/ic_feature_small_bg_p.xml @@ -0,0 +1,29 @@ + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_mcp_feature_small.xml b/app/src/main/res/drawable/ic_mcp_feature_small.xml new file mode 100644 index 00000000..01d2b05d --- /dev/null +++ b/app/src/main/res/drawable/ic_mcp_feature_small.xml @@ -0,0 +1,26 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_rssi_bar.xml b/app/src/main/res/drawable/ic_rssi_bar.xml new file mode 100644 index 00000000..e37a8b74 --- /dev/null +++ b/app/src/main/res/drawable/ic_rssi_bar.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/item_background_light.xml b/app/src/main/res/drawable/item_background_light.xml new file mode 100644 index 00000000..b1d87923 --- /dev/null +++ b/app/src/main/res/drawable/item_background_light.xml @@ -0,0 +1,28 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/start_edit_mode.xml b/app/src/main/res/drawable/start_edit_mode.xml new file mode 100644 index 00000000..de9d6192 --- /dev/null +++ b/app/src/main/res/drawable/start_edit_mode.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/stop_edit_mode.xml b/app/src/main/res/drawable/stop_edit_mode.xml new file mode 100644 index 00000000..d5491ef8 --- /dev/null +++ b/app/src/main/res/drawable/stop_edit_mode.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/uart_button.xml b/app/src/main/res/drawable/uart_button.xml new file mode 100644 index 00000000..0abfeb58 --- /dev/null +++ b/app/src/main/res/drawable/uart_button.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/uart_button_background.xml b/app/src/main/res/drawable/uart_button_background.xml new file mode 100644 index 00000000..3c1580e6 --- /dev/null +++ b/app/src/main/res/drawable/uart_button_background.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/uart_button_small.xml b/app/src/main/res/drawable/uart_button_small.xml new file mode 100644 index 00000000..fb981d2d --- /dev/null +++ b/app/src/main/res/drawable/uart_button_small.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/uart_dialog_button_background.xml b/app/src/main/res/drawable/uart_dialog_button_background.xml new file mode 100644 index 00000000..fd4991fb --- /dev/null +++ b/app/src/main/res/drawable/uart_dialog_button_background.xml @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout-land/activity_feature_bpm.xml b/app/src/main/res/layout-land/activity_feature_bpm.xml new file mode 100644 index 00000000..3677f245 --- /dev/null +++ b/app/src/main/res/layout-land/activity_feature_bpm.xml @@ -0,0 +1,286 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-v21/button.xml b/app/src/main/res/drawable-v21/button.xml new file mode 100644 index 00000000..4ce2cf21 --- /dev/null +++ b/app/src/main/res/drawable-v21/button.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/ic_feature_bg.xml b/app/src/main/res/drawable-v21/ic_feature_bg.xml new file mode 100644 index 00000000..8b53267d --- /dev/null +++ b/app/src/main/res/drawable-v21/ic_feature_bg.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable-v21/uart_button_activated.xml b/app/src/main/res/drawable-v21/uart_button_activated.xml new file mode 100644 index 00000000..e00d0b72 --- /dev/null +++ b/app/src/main/res/drawable-v21/uart_button_activated.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable-v21/uart_button_background.xml b/app/src/main/res/drawable-v21/uart_button_background.xml new file mode 100644 index 00000000..c2a17690 --- /dev/null +++ b/app/src/main/res/drawable-v21/uart_button_background.xml @@ -0,0 +1,30 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable-v21/uart_button_normal.xml b/app/src/main/res/drawable-v21/uart_button_normal.xml new file mode 100644 index 00000000..e754af7a --- /dev/null +++ b/app/src/main/res/drawable-v21/uart_button_normal.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable-xhdpi/app_drive.png b/app/src/main/res/drawable-xhdpi/app_drive.png new file mode 100644 index 0000000000000000000000000000000000000000..e64055116744ecb47f713503a8408cfb0d142507 GIT binary patch literal 2573 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/app_google_play.png b/app/src/main/res/drawable-xhdpi/app_google_play.png new file mode 100644 index 0000000000000000000000000000000000000000..14e0258a971aeb3bbcd3b55c7db2e515c7f52528 GIT binary patch literal 2247 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 Kr=j3;`~L;S=31fv literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/btn_default_focused_holo_light.9.png b/app/src/main/res/drawable-xhdpi/btn_default_focused_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..73488f35ce217af556736a04c5f080c525e93c4d GIT binary patch literal 476 zcmeAS@N?(olHy`uVBq!ia0vp^W{MK~REfLv$`X7Rp6u+_e_^WVg>6Nvmdv+JcrtRN!XaC;#HM{z6u6mJlYlGIa z*M_A#W|+nJNb4=*6~Elpoq71^mc*ztPpXYBE2jxvPMW&!MIIN336lgnCY5D%Qkwgj zbu->r_e&`L(Yt-BraaJmlVEq{(abdtcH*rkkGQ>T$(bb}os)5ti_@% literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png new file mode 100644 index 0000000000000000000000000000000000000000..fabe9d96563785c7d6b008bb3d8da25e816c343c GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^{6Or)!3HEd1bTh|DVAa<&kznEsNqQI0P;BtJR*x3 z7`Qt@n9=;?>9s(?08bak5Rc<;uP@|nU=UzFz%6x@#ly{E6Z5RU$2Hhw*i>Gs`(~~C zr~2_>(e4Ka`gpa)&de}Ks*u{@U5E@m-v9X3<$3NT3r3p*`<7|@n1Ecw;OXk;vd$@? F2>^8yH@N@+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_bluetooth.png b/app/src/main/res/drawable-xhdpi/ic_action_bluetooth.png new file mode 100644 index 0000000000000000000000000000000000000000..40451ca66ac3ac2041d930b5767d49fca38f152e GIT binary patch literal 685 zcmV;e0#f~nP)3f*XRWC6MR&E&^cwweLFV>G|2dk+Nc|A7#z=BGF_bOM0E zT?QF}(7!c?z+r>eUGIl5(qP)XDwey7jDXy!pE@mv;&@Kx>I_2hX6M{)y(CvccFxMU0FS1gGaSB8h{ zzr3OAqU}hpA{CBgcjD4m4=7VINVNbOEP*UFjs6co@S6F(!P5D9=ox^yfNwq&3-;b` zmpm=0>HsVN{z`-b-PyLlu=RF#seAa)tQl)Ah1tR8;6z0_dh?sYUkttPGsH4cgdwa|R=I4|*%>|$Kp{5Hq;W| literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_bpm_feature.png b/app/src/main/res/drawable-xhdpi/ic_bpm_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..681e2617827779ea53c5fab4c34ad2aff60ea6dc GIT binary patch literal 2076 zcmbu3`#%%@9>+hs$QYTsT-t~dx#Zp#yBJQZ4$_PWL#FdBxlF0n*Ty$dx+om^s*tZc zxn%k3WLp$-30ZEbkg`OXikYz;=kYjy!8z~8nj5QR7v|i z{WqQWA0f7E(*Nx##ZB9mq=!oOz6S||_08r$R zJPG7;Zx-$ioHhv1%BUw@A}eJpAmP>I7|6tvFEHvN!O<7R=y2-SG(8V(@kI%h4B^r{ zyE4@+$DZd|pft=WS>(fh8T)9^Ds6d|u>UQiUreF|n_Zn@FelxG{nxrew(@L4R3I1t zpy2;OZdZs3q1BY+AEU)<0x)mL9wg?qo>DL-YdS7ke#%xKLA^CV<3R6J1Kp#@r0x?e zwrDiRxkUAWg58U6eRA|(Q)=Tz>xZ<%5X;%c>7_zrdXl=&Cf!pJPUj__WJ{6W<}e?CQkGB(zk?GalJdV)99 za=uSjq8KdycAJ>!0hok-c`mHDyLJ$&tu6aisqnoQU#W>myR7V&3p8XXH6nJu<+IFf z51^|mOxHmX5@ucK4JLnM+DzdNJ9QZ9dx5y$m<1Vbf$79j#FWBONmT20ZWlulg<0g_ z$^*^>*Nv%RSm_+*_D0z|1b(u}Aa(_oHSNZWgm}2W=Wb18pUC;Kx%W)RWB@8ubzDadok<32Z_cr6R^vqScJP8CI^w%1?JY4^3xQP@JT--XH zKNZrtq$P#GZ3W^-XgsS7%2!99Y-_xW&K9d(8;1>wL*D9LUU}#QH?LZ3xj2y^QGp3Y zkpU_hlaZ4+wN`TEeuah?ERh_iLs7f_hZc{wB%4@JJjBUsinLwVum91Vwb877;Tm`% zP1!g8;uCO=`Zid}*7?j536u-8Fs>iFyO360uR~`oyxYTHuF3QzVFgCWy6imVc>L;U zr>Etg9Ox>i=aF1M7k|vS;wt^{u!i$B*?pVr`;a5|{9{qfR&>hL*6p04(IeG3i{m9w zL#YZgX0^s(Lnd^%lM`4!9N_bH7oUvGj-CA#+rdotS2A69hiBTaI|}DKTE<0|`Nj9x zw-ESwd)#`D*=J+?MT1H2SJQ!e2%+;vv&|G%*wM|B+N0X|3#2KpI*hiOcL2kvwuX8( z_@|>%$}|@KQ3I`p^C|LR^XWkI)Jxp!U<*b5w7uRh%^i-QFUNgiuL+G(qBUMS7^x4D zAuAqRxpqn`C`|2eI7R0Dc{C~%)(m=Ton&42 z#?@N#B_}WCvE-}0^Sb2I+eK$AXQm&^ozLA7#qm`z=WbNFzF+Vkq5X9O-6 z3V{Ej4`CarTmb8Z9^#|vEWk6=)1G2{?=lS1p&pWr!A`Y1{f@?~Eqz)3X{~-Rd?Buv zNn8I=KNoYQ&SR$3byl~eQlXM;QEEzhpo_;ITm0B16i784ZuUkWk1`-?pv-kj$(MD!GFw|nDQn2I7DE9chESu`i{&(tw4OnUt!Rj?cU6o zlxd}ncRAC;w{N&#-E-w~!iWh^vm)CqZN9PW%MQFt>|oGD80IEmsK{*%=x{`)W<~A< zeEf%c*$%6y8gEvT*B93p`QEjfCkCeTUoN5`?H~EOX?axLcx%G2UX2Exp&g_ng0|!O zI`tsX@|j%vkwN5>T#wN7fL-{JqWi(Oi;G2K$7PxPlUI~W6JsRY#W&e1r^c#?v zUTphU=vaDe;vC&4-_ge7{W3d8*_OaMXPT{+VBo_4y}WZce17{>wf1eNO5d~2vyCI7 znulQ2;#upA^-#;Vh9Qx&BNvZ^o_nWePRnIus~4Y^$ok{Q;Z8;^en*o96R)hngFvy;#m> z*@eISRv@EK#;=M6dp`%M${iHLs_Z{kKGy literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_csc_feature.png b/app/src/main/res/drawable-xhdpi/ic_csc_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..ba5e6243c317b26e106c7e92c0a6ee9f3fb167e0 GIT binary patch literal 4224 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 Lm}oaXa7p+d))%H@ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_dfu_feature.png b/app/src/main/res/drawable-xhdpi/ic_dfu_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..d7065e0569e208c333ff258856820d5009032afd GIT binary patch literal 4987 zcma)ghf~wr^Y$kR1f(m7fHWnbKtL|N_ZARPI#QJqdNK575EYebKzj4io3sGZB#MZH zrUB_C!X=TGpfte%KfZs#`_Alhc4l|a%sJ^+W|AS_(Ygxk?VE-*TtMCVmceau*KKO?SqbuOLZtpJ&yO!j< zB@EIPeqpfbokJQHYP=!%?Az_b?Rn~AJT=zFYS&_Uda(~Rwn+6El40rpf7lBBPbdp; z0EuT#QLsrd45k(1B8m6h6dzSK*0@i$u2NYRKya|_FHi0~UBh0L*dVu?!Q4BtMY}Op z^|}$6rF&_81?6S1)XY$9xx8}$(oCgnEA0_fhS{D8n~@5+ty6Y;jDkMJx!?kDP}(fO zB4^XUZ2dC6w_F4!kVo6TNJNs2@A+-q13qp2Q8PVmF8_srnrv|Hke9P2{UxpnsJK|T zF$RNnf)K1useca;lo;+EzJcGG!AvrYKfP>~=t3W&ty`5dAxBnuV96%_b7BI!9}k@rE~wt1T8pg363J{|^6i>n^@r9#`X1u|2et*@ z2Av~;N5L)PBRS(}9fe4W81bU-I0H_Hn{h4lbT@M`Bg&q+@Ln02O7CRGzi?s8&Bcao zP>4yL-JivSwmex2z3uhP+>t>v~yzSwJfF%S&z7DEO zOOuzu?|QY%($k3o?4YGI7^4>ulSdx-K`TQ?Ff0C{ibPEZpz~hQeJ~*gjY9l3IT%2a zOtL#IpJvm1w$qJ%kHw*p>g}3bZC}E9zxMYuAEyO}=s=4YXqRSg{XQI*)x!onR6dPQ zhsgW98~sfGUEy>egpBfT1yN$%+~93-SNK9rZQHw7il*9FN{w0;e?-vJeL&%~cgG&2 zE@|Xtvh{8_%<-}0el<8GHK!3uVRfrP&|-xG5Q~C^)aS2>2}xkJGXb2^hIYXTra`bE zzdf`Fdz}oRAil@4G9T3y>l0!C3p#m%lUq<}O`1F(v}f)Esh!y>OCSq1Y#c+f=XkQc zsVNw|K{-~P_Veuy8U4fJ$!=jAtJg+1C4l!C8BI82^vJl9P~%KWh<6wZzb0u70yse-!y1pHX8a^h|?{mU)}ABm0YeF6wJ=R`1nPo z7g?8m+e1@LiV76u} zSVc&<77q1GRsNS_aKbHcqsnBPR{3E4-X^Enz{`viRr`G%AT^t>ehxkB3_KwRfP=&pOiJ^{PY6+7!K$8>il*p8UVAI?8f{c)dRX_u>kUirhq zEj~xVY!QH4-a`^_%Gbk6j&A?kN*;=OcuOJQz8@uDaBFHp^HjCPC&I0z%FOOlJX8&9 zueA1Maz_Ex;l14zkoGb_HZ>!WYevM#Dk`hfVeddgeehi%*^tBAFil);*wTsZ>N3%1 zb#TL(XZiB7XnS|7bvUKO-vsOPP4VA7fO5dK_5f8!n2q@tiGNMru*ncmr;i$5sKF{e z>hE6~#l86+`QG=@jRT|Kf0Yl{NhTF*NrIk=nV}}mW?@!GvSsY-_AB2B^QSuF8ZJ+f znbo8e{J1*4K3jfBr9(4uW)Z^&3kV$F$4se_6`u%FjpuYPCB#2WEWbRaGPlr=*pRFd zH<}T!L_mdn-h+NQ%r0NSL3Tm7Imq0p&}Ft z)w4^&v@=)#xFV1;n}4b5Bv~3SO?l9BWg|j0jh{RPIYb<9mRBH#jfvXig%JYV<4oxx zCDDDneP|boVzWFSoxNE^w?T(Mp*PV|wKNukg{u5%e+kA)<9zbny?t)rBQ<2q2qreRTNAQ61gZ%qFf>$LpM1BG z{$Z^=JZvmZcpZWm2S?PlJT4@mbj=A0#Zpc&UMgfk|E9pNC_&K9c1u{o!N{M-n9v9X z$JKDNU0uWt(`Y%*BX{(VHzj2kjk|OluBgO-M25M5?kEWzD$?xpw|E!d|k?@1&a{7yt=0S)q)qx5#%;!1VfS^<2T~bpE7U&iATpUnxB-9$G zpk7PJ-Es~om5_XGc<_?s&K^Uxs|3CrhqO-@qMGS&4-ppS?*fewi6ce5NA90D|0cO` zNJ;?FCisW>$g=Xo>$OF;2$OF5h?Jvdr3nq1Z?`NRZd%Tz&yeu<6)!UUx04MuN0Fmd z)@9k0uydXh9d%rahZKF8odH)VCSa|bB@>1%gwom#_s*LLa z8+u$eo0nhK_0C;ThC<0O&6pJ{vlbS0T;b!$Ygct1gBX=$#5-C89*cAx!j_N<){$!} zln~@g*xj?WSIJc@*qeVJ%m~vje43TIbdB54w=_(=QSx|oq0YL*KMOn3k95X@h@FttiNkbp8dJDMvwOj5_R zA=KZfQ8nyTEZsId?u)H(wnZ9S+WCz;mPm-Q_zH=dyV2p6deSwk(vc-8p4sAyKE3%+ zTy$75xl*J5y270~oYSjSK_M0LQs7sL1$#O^sG_CHwmy2ID9o>a`hNweQL2%5qU_hj z^WL3AE3|=wn)J${Ca-feRfqw9+5m^cyY!=cF6WQ7&1s|r1=^|QuBR1zL+2zF*Oph_ z9yavU(z=s*uAKXu#klr!>Z`IKSn^1E?@)A?UlEwfFD(Hq!QY8hLt}0_n^5vdgG>Cm zzmD5#VRw=>0hi&(UW@Au*SobeVB2M($@1wrxNl4+fD0SjjyH&ua}CIraFn1H*T$N{ zxsS!2yD|rA`HRzw-fnGK7bv_DITzfV%3%~Q7HZq- zSK+v8&k=ml_pwo)cm*R`5%Qz{L2BLo(PdU;3&No#cb?T|`jHCxo-7ty6gNsL%xV~A z012IOq#wrh-UjVFYY`%8w&B~5b-PrNbtqz5@+4|P$UxR5N^b2*{~GQm8~98HL9V#j zC(-Ql98Ut$DS_8o0}Rq=t|t1!EsOhqBvi)`FIL$zv7UHoZOL?1a`8(T;Bv<^(cW%x z@I9syoKw^C7u!+Z3Oj*qv!s-hAsV|M@b6iVe_a10Sx+B4)?g#r|8Q#VzV2&&WUfTb zXvD}*TAk%o?)MF-RMy@@{BV+SmsAKzv^JIzw(XE&REX--`kp^>%FnNN*7s971Ez7_ zWt;{^$BR(SqbIJGPh)7P(&hDA>(wcqUUe<))?L8P(Z;H`n|}G&Sv86>-K>#?qC_Fm zxg(RW7NOo)eoC=BXiOTjd@pyU?E=~ZzcrgO0F@YPyrsETs3yIVz24&i=g7AZJ%JOc z&RM^X_iO7r{Nc_3Y$5;Gu^3|6v^ecWQI;X6OSd%eJu8I; zb|k_) z-#KkJjSr{fI^0F$j9!POAAC3oAq<{cAmm_ig3-7OES76!iH=_I=uQ-c={p3+Rl*0% z*ci?RoN=wPy6>B2&FQIhfFUX4N9D^q`65Z-Mt!w-jIdeCBHmOssGGvd!N`FU5 zf3LSTd}<}6bz1ADbM9yYyT%hAkhIdY#M9J{k0p9nbxP&b2OQY8yrj9?0t(Q1#Ro-v zvw}^!PmeRJjH!7A1_9H_nNzBgbqSn&h-wX#d}c&Joq^B9U7UnPf#$sTgD?iMsF!UQ zl^30)C1TjXOS@R4DJHf1hyJ|A`t;u>>@|bri8N`WJ|W_kAvd+;A)`{`eW+OodvxQ_ z{r+`Ut={cUgO#(tY1&$-f&5vD(8HNP0huxVCl`4S8#>5KT~4a$%YkG}x}VvAR&vxE z@}7gF-Q3%6wR4*u?ZBU2yBeO;V{2R6-rKC&YH24x4`Lk9qgtNoDmfgU*->qHRQ2{3|2Yc0;GMll0kcoda2!@zfr|g z^I2odN>o;4sX#&pZc9r zZ6b)4ZaT7ZocRv8cGBy%e<+th*+10^R7bJnqS>6jL-k{f#Er*=?`=wItSvuWRggb; z;-T$mdN0w_i$zW!q4mfof!fXYZnEcAu`mx)k1>BN%hsg?u|w{?c+&*P=;jK`6Gu#Z zEK5p5GxuL;d`T)UGyLbxQ(@(cxdJ+XfAv1gUEDxFJ&t{}8_!9Xh^pLV91>8N{6Ph) zpE+B<-}TIr;Yg#?yct}1Q_9Nk)ftp$B`Ur{^xJmhNHSiCt`}n#P%^2^SP2pF-J!61 z#*RhdMEBpVH-3ZM2aaUFJtZcqGlZ%y|J`C?n0<8L2(hWf@eINa8TRF(yPELJCU*Ii zbA2Y6U3-Mll*KhrDxQZCI;{IdBRneF!qdz;{dm{umk=}YOg#Z_Rd z`@@diikQ=%g)#FmdHe!>eojmBu4-^}OQl%Y}?d;EXz`h_z9 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer.png b/app/src/main/res/drawable-xhdpi/ic_drawer.png new file mode 100644 index 0000000000000000000000000000000000000000..0f04c4972d0507acaf96fb519b44760375e8b4e8 GIT binary patch literal 2767 zcmV;=3NZDFP)|D^_ww@lRz|vCuzLs)$;-`! zo*{AqUjza0dRV*yaMRE;fKCVhpQKsoe1Yhg01=zBIT!& zC1$=TK@rP|Ibo3vKKm@PqnO#LJhq6%Ij6Hz*<$V$@wQAMN5qJ)hzm2hoGcOF60t^# zFqJFfH{#e-4l@G)6iI9sa9D{VHW4w29}?su;^hF~NC{tY+*d5%WDCTXa!E_i;d2ub z1#}&jF5T4HnnCyEWTkKf0>c0%E1Ah>(_PY1)0w;+02c53Su*0<(nUqKG_|(0G&D0Z z{i;y^b@OjZ+}lNZ8Th$p5Uu}MTtq^NHl z*T1?CO*}7&0ztZsv2j*bmJyf3G7=Z`5B*PvzoDiKdLpOAxi2$L0#SX*@cY_n(^h55xYX z#km%V()bZjV~l{*bt*u9?FT3d5g^g~#a;iSZ@&02Abxq_DwB(I|L-^bXThc7C4-yr zInE_0gw7K3GZ**7&k~>k0Z0NWkO#^@9q0fwx1%qjZ=)yBuQ3=5 z4Wo^*!gyjLF-e%Um=erBOdIALW)L%unZshS@>qSW9o8Sq#0s#5*edK%>{;v(b^`kb zN5rY%%y90wC>#%$kE_5P!JWYk;U;klcqzOl-UjcFXXA75rT9jCH~u<)0>40zCTJ7v z2qAyk54cquI@7b&LHdZ`+zlTss6bJ7%PQ)z$cROu4wBhpu-r)01)S~6}jY?%U? zgEALn#wiFzo#H}aQ8rT=DHkadR18&{>P1bW7E`~Y4p3)hWn`DhhRJ5j*2tcg9i<^O zEt(fCg;q*CP8+7ZTcWhYX$fb^_9d-LhL+6BEtPYWVlfK zTBusSTASKKb%HuWJzl+By+?gkLq)?+BTu761jmyXF)a;mc z^>(B7bo*HQ1NNg1st!zt28YLv>W*y3CdWx9U8f|cqfXDAO`Q48?auQqHZJR2&bcD4 z9Ip>EY~kKEPV6Wm+eXFV)D)_R=tM0@&p?(!V*Qu1PXHG9o^TY0bZ?)4%0 z1p8F`JoeS|<@=<@RE7GY07EYX@lwd>4oW|Yi!o+Su@M`;WuSK8LKk71XR(_ zRKHM1xJ5XYX`fk>`6eqY>qNG6HZQwBM=xi4&Sb88?zd}EYguc1@>KIS<&CX#T35dw zS|7K*XM_5Nf(;WJJvJWRMA($P>8E^?{IdL4o5MGE7bq2MEEwP7v8AO@qL5!WvekBL z-8R%V?zVyL=G&{be=K4bT`e{#t|)$A!YaA?jp;X)-+bB;zhj`(vULAW%ue3U;av{9 z4wp%n<(7@__S@Z2PA@Mif3+uO&y|X06?J#o zSi8M;ejj_^(0<4Lt#wLu#dYrva1Y$6_o(k^&}yhSh&h;f@JVA>W8b%oZ=0JGnu?n~ z9O4}sJsfnnx7n(>`H13?(iXTy*fM=I`sj`CT)*pTHEgYKqqP+u1IL8No_-(u{qS+0 z<2@%BCt82d{Gqm;(q7a7b>wu+b|!X?c13m#p7cK1({0<`{-e>4hfb-UsyQuty7Ua; zOu?B?XLHZaol8GAb3Wnxcu!2v{R_`T4=x`(GvqLI{-*2AOSimkUAw*F_TX^n z@STz9kDQ$NC=!KfXWC z8h`dn#xL(D3Z9UkR7|Q&Hcy#Notk!^zVUSB(}`#4&lYA1f0h2V_PNgUAAWQEt$#LR zcH#y9#i!p(Udq2b^lI6wp1FXzN3T;~FU%Lck$-deE#qz9yYP3D3t8{6?<+s(e(3(_ z^YOu_)K8!O1p}D#{JO;G(*OVf32;bRa{vGf6951U69E94oEQKA06a-VK~z}7?bX2v z05AvyK`;IHe5oN2@H6`sSp?Y`ER(kVx-iMh{Mo($f#VGTEzkl2-T=@7Eg-NhZ~=*U V3>+Y!q<;Va002ovPDHLkV1fc~JN^Iw literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_glucose_feature.png b/app/src/main/res/drawable-xhdpi/ic_glucose_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..99ab2f537c141abe6fd0cf11554013e67efccf02 GIT binary patch literal 2091 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 IIVCg!0CTakTmS$7 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_hrs_feature.png b/app/src/main/res/drawable-xhdpi/ic_hrs_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..d28b50d487ccccac454b5e37c631ed18d01b6631 GIT binary patch literal 3695 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 O0?au}ljla*g#QCj002mN{N(C? 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 IM6N<$f?*=KrvLx| literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_about.png b/app/src/main/res/drawable-xhdpi/ic_menu_about.png new file mode 100644 index 0000000000000000000000000000000000000000..e4be458dd39a5fd4bc2cae830fb5b5db8d753143 GIT binary patch literal 951 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 HoD!M<*h&8R literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_proximity_feature.png b/app/src/main/res/drawable-xhdpi/ic_proximity_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..d0e7de15703ea5925dfe5abfb8007a0be7b91ab0 GIT binary patch literal 3156 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_rsc_feature.png b/app/src/main/res/drawable-xhdpi/ic_rsc_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..3f81e0bbc0c86ad727c581c0e0c0c7ce82a8017f GIT binary patch literal 3436 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_notify_uart.png b/app/src/main/res/drawable-xhdpi/ic_stat_notify_uart.png new file mode 100644 index 0000000000000000000000000000000000000000..4255d2b2fdd9c9be7f58af4fc1f52aee1f01eb88 GIT binary patch literal 922 zcmV;L17-Y)P)b8zl>yY7-erq={705QWpOzl$&^p&){GB}lu(L}+8XHo8d*tSCx~ zDCkjb3I|K1T9m07f}>2CaW zNF)-8L?V&s7uK(Z51yW?OtxB53=CagBXqIkmqycWTzpw;P7X*~3A_lb1#SYa=<_B= zpaF~kyUlEGPX{Co19k5n1Kt4+Mll+U381||rzW5x7%;dMcpSLb$KEotCwe*X6>vAO z$IPB~*^|Iyz#wpg@5n-g_RoTPFxw6grAG}u0BFTntCmWWbP1m^Nor-f*8AHulc?F# zOE>EwZ+DR$%Gq~Rl48{A?&l`$m!w?($J|7X-ru zk=I>!u*)ti^|3=P3Z1z_A@KGCWdC?Lo*VvhSv5?#-n%(@J=gxENBfK18hZgQFWXt* zKu%{5fSH{H&gAV1W`B5dHE`U_x`%NVwZ=W%;vR1=Y{pZPh9#XV?9hf7^@yZqPJAv# zJs72pg*iqg-6!d}!W<_g4MpkYZXqQ7ZQIU&&sox0NuvNUn|YjlV5{4;&Ex-pi#hO` z|7C03^B?+YeHOLK?f6NOCfcz)Excwrz?(j>(PMUZAB)&{DcErq0uYXvQ#+%J*(bmwT4DRypGcMXyQ2BU~S>`%#=j8hUYE^6DRnvJN zpkmfgE~NtRd72ypzA3EndCBZlCfxz75bPVMR-3cGj7TR7MJ=2DZ|UJEt@m*2a9+~= zQF`(j!0S$Y!VC_EcaXE|3v_f03Vv!j=E&Sa0<9aFci$bp7VnyN_X0Y zdw8eR*9FH6CN9CPR6tp9oxyFuOF&KVYB1aUpI>CHEL&C%;RWEXD6R^|(q2FRyk9PY wU}S3`Gy5z(oD+#eB9TZW5{XN~UjzP(#Lptu?EnA(07*qoM6N<$f@m+jNdN!< literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_1.png b/app/src/main/res/drawable-xhdpi/ic_uart_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d737be597c4f0fe9cdf469ea9b7b5ec18ba8ebe3 GIT binary patch literal 493 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGovY8S|xv6<2KrRD=b5Uwy zNotBhd1gt5g1e`0K#E=}I|Bn_x2KC^NX4zUH#T}PJBqkH{4?ED#e3Bcu4zfC+ms@r zZmhbo#JD#@v1}SwRKyPv!?pSex?xTe8rCjVn5~dlb}UNT@laa2#eLy7cP7t#le3r+ zY#Ed|GdCzYAaa_m@$3H)OSZ&af4=od+y3v>KT6X%dF#V3W#*ipt7`Oz+4K0MMb<%! z?=e39SaGttJ~2&w(xMpeE!GJ}GfQs2{noo=>x_DrK(>N&xifF>T=Mir|M?Y6BCZ$D ze*WWgsZ2|sKXA_M=7R@LZMt*v^B=pV58XF1&ncdrR;H4vdUSR{*yDrwGa} zQ)u~MvfcHQCX*){hhhbjPTmjwb32`xLhOI|zyJHRz~YVR?6cwbnpVmFJ6vM5_ic%l z{GPTj>mTOt|AtOWJ^zO@-1>+9`@eTHOm6uX{@8ktQL*Lt&788kSzGVz?6_Jz{ZD1$ zV?Vdyjn=NZixa&t;uc GLK6U2#>1%q literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_1_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_1_small.png new file mode 100644 index 0000000000000000000000000000000000000000..cf8880f83b4af0af646dd7f9ff5acddfef28340e GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEVAS$-aSW-r_4b;f-(drZwukSx z$0#a_vPB3mi+gBU25!68w30bVC+Q7i75BOZ3r1%1gbgBwB@dW<)@ZmYr9R>~GVPCD zwA$_bDSxH`4FwvWsk8j7iSK5U&9nDEmw5bZ|MilcGIlKmscEZMUO%hkaJ^Lh+|I2k z@i7gnRy})ck*6|uX~g~IHh+>f&ZvHGK1na=tzu-uvP?bIyR&aro|^tZSazT3=4em% zmG%ccnXi=A+RQ$??rhG?(_d!lIB+P=xOwV~U-7PLAF%_L<DD$~A^-pY literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_2.png b/app/src/main/res/drawable-xhdpi/ic_uart_2.png new file mode 100644 index 0000000000000000000000000000000000000000..db2432c1bb3ab05b9925e4ca6fcd04ffa3bcfb69 GIT binary patch literal 1278 zcmVOXWsn0nNX7~4jJ?+cPd+$5*d-G;PB!mz` z2qAkDOUox4hstlPJe&@lK_SR?AprTGINcHW`ZF2VtRV|{P6H_AOUQF@B90e zQey!6uJ>5XJm>rVX~%JX58F6Z*g7;jJ8K6)aKy5#_qJp5iHHE~wQc*;AP5d;G8xDn zaFvoXFfcFyV1J{|!OUMxO--E$OGye%0NHF-4Gj&w)5yu+6v8J;srMy-O@bg80r28Z zoQs)RYdsQ+#V*JiKt#1#?N%asVaKjI0G4HqhGFb>C^})=M*t{;D_0ZIxgZG6dY(7C zxVX65)zxJs5{ZQ4ID3>*`-tcOfSU|LNPC{QHx`S{wR`}~{5cWb4#2ren_oT8JK5IO zws6^39uZZEXqkx47mLM@5{X0xzytNpYgyJH5zV!H39>BfORe=`W-k8E4kH-t8Qt2Qw|F|*vf4i>x=HTGqmY>?`h4Dw?ZRoWq7K@$9WOAm?;=ihtdPMGk254_@-)+$BPboo-d$LL!G|Ni> zjoa$hUehJr<0j#a9^#FLzVDbGhEPZaO0OIlZD*)Q-T>a;5 z+x}Ss*k-=(4+40!&g2Ka@4p+Sem6w`uIr|hQg0YEopK!Kk_52LIyyRz87#cZ#bWV; zu=PFi0cfos2k@Z5!aLF3-CdCYwo$cO-38!iy>`re#1~4--qa4RMW$@Iq zQZAP#!#a-0{vM#UKB$y>$)Md)+qP%II*v%*0iNgG2H=oE>G?X$lOM?d3WY+OWm%`{ zy=-IVl}e>D8TRo+E`Z+N-cbO144!)4>gwwHM*`U1-R?dB!v>}28{4+Oi^7;96M*Zw zNu|_rgUMg1R4Nlu8CPTi*x2pfY*2dMjzZ~)Q~+A*#{fKJSbDyVQdtds0M%->55SmV z>6xU633UM3Y*smrbF$uUcT?#pMlFC)?}WA1&nu-~Hn{rFDy3eJ;-)gRcR;OHy9L0A z!Q`(->8U3Y0Tc>_HruvO8~ketG4n(eOHZgvP!I%T0G`_M$pG$d`8&Y({dd&V*q-ng@h&mt@Qx_4^xW?O#lF1r4|&X06HW9A%qY@2qAn+a07*qoM6N<$f>V%N!~g&Q literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_2_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_2_small.png new file mode 100644 index 0000000000000000000000000000000000000000..855a88ccbcec585e1bde07b5c565a39ef9e0660f GIT binary patch literal 903 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 Y3!;AGrga1Q@&Et;07*qoM6N<$f<+ckpa1{> literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_4_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_4_small.png new file mode 100644 index 0000000000000000000000000000000000000000..68b32fd90ebc31d2c8bcb21f7155460d2fec39f4 GIT binary patch literal 559 zcmV+~0?_@5P)FkVm@6+vU@#cMI-u&1F1VIo4K@bE%5ClP(HYn7N8DqWx z*m`(Q)AZ0q92H{nTI(fd{#i$?7Xcv-vWLqGJHB>xvnafJURS z3*dd7F@q@qW6U}LQ+HeyNb)NHe)x#(T|kl~i_E;|YfJVjpwsERveq6GQNvdsyb0*_ zddgaRKtykS4uUrUgTY`Ez$f1&=tV#r$7=w-R@<5RV&Vm8tv@QIw*K?#GRv~_y8Bb> zIiS^Qy-`XXRpT=A^=LHu1Ar%1K)2hSDa-PRh~_GjN|wlfYs_oz|6n;{rthFb3p5IRNHkc&I zJ7(U0e9UF$djO|-p5KIU4{;_yYd!n#m^=Hp>;e2v)ATx&Tc|4mq?FnxqJ_$$cb;Y0 zRY>0;oZP_L?e+!{eRtXMr}{{$93=nQb@HK?zz&`fPcDFnW~N%eb7SfS1ovyq7<1-w x)t4C{0z`la5CI}U1c(4Z5ClOG1VIp{o4=&Rf);HQfI|QP002ovPDHLkV1gSp0onin literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_5.png b/app/src/main/res/drawable-xhdpi/ic_uart_5.png new file mode 100644 index 0000000000000000000000000000000000000000..190332e1384b0a08694159bba6e10674115bf294 GIT binary patch literal 982 zcmV;{11bE8P)Nkl`A$Uy|n_RvEq#9*-C#e-Nx@Zdl2P!YvL@y|h#B3dK_lpIPe zJ$MxCRgi+GDm{2o>s~?$v=K$wC}JA4li8)aGxMH@F1WOznMh{mCwxEW*_r*l@67Kv zZ)TSW00000000000000000000VBfKCU&zc_BO5&PV%6gnoP!7e0RRF(0Du4x0F0jd zUp6lu+`r=rKmdRM5C9+m1ONyCeZXk-`~8E?xno4MKt%Tw(bQlpH;L#kBKn<(uBvKl zV`Jloxw*N%w>^z-UueHy$e3A7L>D@p&S&*{{RRRUaR9?XnAu7Y1YcndsNzgxZivW7 zs`?rNs5XdK@;rYL0aP2p>uH)EK>*bS;DR9du+?e>2%x$U?ps(`cnp2O-tJ_&M0812 zzs|Dkmv+0oIXgQ$Ha0d^cg`IWk%x%rDQ1oehH#vSD!nW6?lx3aFEaDYZG|@?`Z7t9 zvyDb0zT4-wwzejwr>Ea#<|hj_bx+r7wKk@pfh0+uH?xaF#qX%<8zQp2Tk(mAW@cu( zBJ#oTKJGdNI5&?qU`V6Uh(+Z6JkL*>*|jXoUUklWzt{c5alA5^vUZz><}n48H=Vu5 z%+Ktyu3Qn3mvIGD_gG^JQ&35=EW27@vpNDONw3%YyU4PG07|mHzTPRaR3LzoG@H#@ zkyZc!lw@LJqDV)40|AsI48yqsn_Wi$Wi>g>hYM`BfdI-2;8=lP;YS2eP7iRDnGY4{ zmRAwL&INo#RX<77^zdFkyS=@AKtxUzIQx^;)zviwaGO@E6^O{&%>1x(?!2m=$+GO| z($dnd&#wCY{=vz~$xoU2-U5fZw79sKS2|7l7(kxqFNnxHJDjn<5z#lQdO6FopEox* zuaA$9yC{kdgkgAunI9#h$C+6QUS%(ZVYr3>hQx8)h@$8MGne{^z|6iCkvFRzuXj^W z6h$XSQ2c(Hrl)-vuU7%|dc7tQJzMs1%KA7AXGw+6RrQ>Rob#$#^lc3o{Hoyu5k1Gu_v};gujP5Z5{BUw-^T0RB0Tt2!0}ZX4d|XMOQPsoagz;<>lq$J{I5GK46E%`2pwLJTpH?L`}N&9(Rgvy-v*N-#=#j zK}0{9*;=>T{m#e#0{{R3000000000000000004}@KhOtRhm+;_1ONa407*qoM6N<$ Ef-m^V?*IS* literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_5_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_5_small.png new file mode 100644 index 0000000000000000000000000000000000000000..192fde118da5a8b7f0801a52027d0d89248c7def GIT binary patch literal 735 zcmV<50wDc~P)5@H8?a&of2 zTrTg%MSwQ|rkc+lfJga!{`u0Hu~Dyf(&M2XL*G1|l-n?AsPnQLesP zt-1pP1D{D=0PxUpoaIWTB7b;iV`ymT5`c3py7<*vA}l5+sghMlV%$GIPy9dLAXG=IGK zrhf|n<}Aya6A=^&1^B)X^6&nG@B2?`60)z#IlINb-_B-z!bvDWkX z{NpGl8KnTP0DN!5pMRFi5<8Rz5{J$4CV@ z`JIW0i4l?)MP!&{zld}<3!4UjLjXSkd;zdY^1b6Y-=HXpq9}@@D2fshzX3AA@@6ef R>30AC002ovPDHLkV1n7+M4kWu literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_6.png b/app/src/main/res/drawable-xhdpi/ic_uart_6.png new file mode 100644 index 0000000000000000000000000000000000000000..7b8879c30cca4df7bd202e4b653aa17c3f72df39 GIT binary patch literal 1516 zcmZ`(eK^wz0RGLg35%VghTBZX+JP!Hm2p(`|4wRsJ=nXTZQo1+-#rR9(*v_Nw`*(nraz$IBJ(d_-1N) z7*25^%tz#?e${ApU(%>1E0mwhrj-?`!}fHH&gK8)4CHLvr1wC|fr5D*WQVhpliVn5 zE+^9yZBgSvpxtI3%gzSp@p~AfH6!NO>%O>wlyio`AE$exV|zOZ*y>5OMk11%6h4jd ztW4UAZLl#BiLDtSQ{?W%UV&mCaZ!qF>{)RaX9n1)1g!Py$GERzvG@sb@k#3TZ|AY= zlEh0N${^Qf6OQ|JTm{qedP~50(t+}<(MJ!IKWI;lKbx+)dBF(Ds8+{K2%=XsU%J}( zzf>?Gf<#`3U)r$O#*O#1^*Gl;1Avs_wQ)b3cer^h2}2&it9MbBB*e-U@9D@Sd~|fB z?iFtyMjn;7mQ@@RQP<(r6cr5xsn*yf7sD=JLc5*lz#>ODw}2u|toi}z{ks*0k~6#l zWju6Uqp|0zMBrT!I4m}6v0H@iZHS9J-Fj9iy6iNu@Y8DlsWx(M5daHu+AcP(`EVd8`dqSsg| zgp`Q1^|x&cJnq8(m~q2=1kW{H&i4xDQh7Mmi*YMg^1ejC*?>{FHUEj8ZCrbOef=9u z!o6AqriRv5DijJY+Qv;NKeNn|246Kp*ladb9Jwcz*V$PUxJO0zk|iHC9T^`dYSBZP z4}F?mC!{+lhCE}lCNbKp(hEo!C3F_(xV zai@AI*sHNlOjf7upMD${WCtBQi6}y^u4Q(GvWFYocli+7k&Q3$&07I=5je!~<3u|% z#f%`_9TR(EbKj!}Do|Dc+UH3pdHg^SA~imGo#ZGh1V4Rze2eLmpPye@%Jt%xU#2Kk zP2x;yMPDrT0+%RnAKg4VuF5*kl-lyVG5#PlxdQ?K%z)ZLW_D*T``f4VgIRaSztB|f zWM+VsOeSkJLAsx5QV-02Q1_g$>kq3`oY`MhR~HLIcEu+pq2Y9msQmVR!>>-rjywFX ztvufFj!P?I)<+{FBh@A*3{&*54lMR^1SRn8**2r=zPpvRSs6>yA>_uL=hD*nHk>gm z*%YwLKkY;G27=(gejuQmuTT^cXsf+f^kSvllkfib8Zob6*^u||F5Zvda*DcH3^;Nq KkkH^wy8I8Kw9?A} literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_6_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_6_small.png new file mode 100644 index 0000000000000000000000000000000000000000..1aa1c473de0926bc6711d77f85da3d96ce7d3911 GIT binary patch literal 1021 zcmVMweR+W0}zfhG(sOqK1 z_R<5Q>ZuYWia1oNh`pPJSdEGxG-+HxFo@W7%*6A0NjX&Z*n;fZ3-dYd+p*_;=goU> zMhjRh7K_DVu~;k?i^cNNLA^2$*LBlG^bUYGl~NOPb90Yg3IVd&>{|d%6Vaako-y-M zwOajhVPT>E!U`azOfd6@MD$)WJ2TG>4-bDcJw2_%oQKm5=Uvx*1;A%SG~RM$h~B8z z>)T4D(#}Dq#b_AR<*#0OK3RB%~#X}PylgaESqJ6CvpNM|wg;Q8)TR;eL%wR4u^Y&~u zd!C360NBaQ8vxb-+$W;nwbrw~@Bbak!%#Y%9vB=P{ECPYhUC{ydaTU7{g!SlS4xKx4B z5Pmbs%qQbg1-7?|5Cvcgz)W9X-#sBjLn*Zjz%c;t8pa)#QvS4+onu%6m~NUjHV;0x z|Mz?e!1u1}E(;;fHr)qALTfz^V6xY@z!QUQs)_SY@qK@qnQs~r?7^PT0YtQJu;n`# zf8Ai-6^A5PGpt}I-Q68S9@rKK0m`imjYi{1TlH$Ss=+)MhdyB0AV9L+`2PO>euKFh zha9lfvOG9W+a}3zoRq;_iGu*QHV-q+qT@&h5oCJj&z=`xW@hFgfQ1&~24~OTHO@kSt4#(YdsMJK{=F)g^2Jx zZ-kjY0N`~vq|VHf>+9=37mLNvz7&c43z1AF^P1y0hXACR`E>w0h$zX-iip+#{Kd@k rT5CTDf(k4ai^XEGSS%KcB?SHjMp=4wJV``#00000NkvXXu0mjfjMCrA literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_7.png b/app/src/main/res/drawable-xhdpi/ic_uart_7.png new file mode 100644 index 0000000000000000000000000000000000000000..3e12930e3a5e63fc1a88b4cf28ad74e4d94fa68e GIT binary patch literal 901 zcmV;01A6?4P)=C@lWBMx!x< zZD{iCKS@N#6asi&EEZb`Af5JaRVtOYIEW?R{?kNsR3U(8<#M@$0McoH&2`xrW1 zA?N&qR-1+_1R#XCDO>zFj_a=LF6%aTx)r2UUL=kvPF-}pPgw(UvT z;>U5^sMTtVTAo`>UVP8<3XHL<3NPQ8k&%%Q0VJ%iuWy2g_DL4M>3N>3?aAHL#jjSY zIU>5QFw`9w82E(%5;in6bb*KtNZKFxzW-Y1>o7I|BAQefw$R(#`yBx!tle&(Afi!8 z`=c-nU+I1=Mh0M6mP-5AY}?*K010cgS|!HV8QHi_r!#FtnM?~HpU+PaktKQjY~*se z&j=u4^?E(e7`vo!@R~K|acWWkgM)+TiDTTf zv<)B#f-zIs?;00000000000000000000 b0Pwfpif=PT!zF?S00000NkvXXu0mjf$JP)M z9G=-+0VMg_Q2w7TYw;^9AP9mMfV(M+kCP-hu(}PlS}hO2D?@m1Fc_R$EnqgA?T}ng z3H_c-CLOCULbY0L4ZsV--rpOK$BESfDwWD}0BeTqA6tDD4#V&|fE`2lV;0$8DFIsR zT>w|oPJYkxjz_1z+$o31>mOL`druTWI1->0ve6RO_Gld z+oIF!_5N5bfaFU<_7jo^S)-1l!R$^O?UisG#2P-q4G>-%X*&?NWsm_uO#eBZyO zwcavhf1s55X|({yah{T_7-IW*&7+VrpkA+60BjqwKUPY8vs!@Xd7A*P8p4OUR$>vI zPiy_mko`E0V`a5~AP63kyln^{jYgxyY5^plnBIpj>s$ZIo&mn^-vMynQ2wV;6#dG* z8|B>kwwF{!2L+IufG`X_l8;P>U$t62v04Ct5b2-00HD`yw-;6m&{}UUiG3;TMw-*% zcZ=jb!{UGR`~B}$3ve7~1Lpsb3I&qa7T7Qa=JR=>0t7)21VIo4K`1AG0m_KJRjDjR Q$N&HU07*qoM6N<$g1%}T`2YX_ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_8.png b/app/src/main/res/drawable-xhdpi/ic_uart_8.png new file mode 100644 index 0000000000000000000000000000000000000000..80d2911bac8d4367bbfe2ea109d7a463e7dd5ed6 GIT binary patch literal 1646 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_about_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_about_small.png new file mode 100644 index 0000000000000000000000000000000000000000..3be3152704e316c2bd85e2c33e3f6d11398c5d59 GIT binary patch literal 860 zcmV-i1Ec(jP)dx?y z?%nsk_wL=DlSCj82m}IwKp^NP(inq`$K!!|j8q%qGsC8%#P!osA zPE;$HT~w;A6%o5vMF39x0=?}6K)^Bt5orLa&!6#lBXM{>kl)TQEJlX#Xs}Z4&Sz+( z9w!g+eQ7ZM5v5!y!}k__71#y_5^s*}D+&Q9`AcFfO#B|a#`PE~YNp!M(D#jxkVrjE z{>l)u3uR#KiC|DwX~-$pt|X)$WdDVD2c*6Tlw3=aUqA`pUBcnSG2wyd-)pZSLEVO0 zvJQvCHqY}@tS12PRQsUbRqD52oIc+;*fS>y4?MrLRS>G^XrQ_(?G@PYDQXB9;vTBD zYfJTf)d+-K@y#Y#sy?nrPGIE&t^zJd9NNZwLDZ8ms>KD4ZL%pG0qA|5`Fmg4-ZB(w zTxJ`L(6-!xQ2o_fQXSfalZyg^?a`Ur}hDF9algCtwhZ06p29b%=l=H#xfykadWFEEWOm z^)@ir^@%M3|13AQhZ!M&He@X}230_k@Nay4q9CR5HW&eTVxw<93fv*Sl=laO0PD>e zXBk|R!o_#NVwc z|DeYk(NH~|X$vFQ21c#};?LjiINalWNbP3I^Z#i^8qKr5-&3pH-RB0h5e@ven15ba za=pm*W9<^ykNA63ud+gh@=hTkN+w1mE|1K`6 zTEEcH#B={;iBnIw6~c`4)>jyR^yPECV3`+nGT+C z|HkLq>3JV7?yM=3&hmd-kd`a^Y`@1khPAf$kLg^QckAJqS*%^Auf(prnZM1?NG{b= z{`adAJ-%q^^G5f-tMDhzy%8mxz4+yXWwt8yuV&N;U%r+8Y47@mDeKn6gk=dDoJh+r z-N{)!S)sgfa(>jwrHA`vOn)vH_^ipq9{ppF2kLNDYbh=u4|LW%zMLzo?8}ki639V&Vd-(myjh}b? z{IGkWq(S|A)i7g$y$pudOJd%6E)sW`oczyyL+Kr{Z+p?6&n>h`#lJ`@+);SJqFieKXOQ(P~TY z;)vW_j>l8D7Iao#(LLt&a>AeFtdstEtR*!i6LOYMKFgJ{wk558z3rb}R#%^>?`F~q zYkvLs@wNy3+u7qAq^*}Mv6}madx7hWto8M8FXa9!{V~-!=BCJjO}@VC&dP)^t}F34 zS!Q*!)Nz{ZrG;O=DIR~4e%|K9<@QRnL;>XP{VABh5FYF8{HIM?A0+MR>gTe~DWM4f DO)o|_ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_down_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_down_small.png new file mode 100644 index 0000000000000000000000000000000000000000..76937f57abea8b0208ae4af1e9a6a58da38aad9a GIT binary patch literal 582 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+7+-k0IEGZ*dNX}(K9i%s(S@ZmxMVn&F$Ft2X*C9jcNenUx5Nv}*F3ZMZeZt7-d%P%!zAqW*I(9!AAC#nGjeaNKlsmRCWFB} z*Yfr8s?6&i9!b{{H2IOfh5PSIp>O6J{y((}-`etVn%4gQk2QAlUHRgU$jepy;rgvT z{pUHa9|=*#&i73-S6j9{$lb>(oX|2&a^ClcFASVM7^UAgPzk>ONUu@0eV17Ky$O?c z<}bbe^_~gO?1SelUg|Y8ZFYDl$QaGu=Fzz8&w9-n=ns3-{3*SQrFLp? z?o4wE+jMF6Imvsj+odvUy~J#!=7=sMfX|s|H=u;YdtN_F0fg${~+s)o!Vb=@`LSf zZ%TU={IXxE;V@rdXY9**S?hPHS4x`&rv6MdH)M0i#IRtrMFKOJ&@Sm5%kjE zsiEm=-NMZI%RgzZWSI7M->WI{$Bt9 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_feature.png b/app/src/main/res/drawable-xhdpi/ic_uart_feature.png new file mode 100644 index 0000000000000000000000000000000000000000..f173944206f1884b7bcb5feb7554104dd57bb12a GIT binary patch literal 5357 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_forward.png b/app/src/main/res/drawable-xhdpi/ic_uart_forward.png new file mode 100644 index 0000000000000000000000000000000000000000..cd5040e39f8da2fb97324c04fefe7afdc56b00f0 GIT binary patch literal 648 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n6x}y978H@y}5ll_mG1~Yhur)r3^s~ycZZ)Rah@D@CG=X zn3ux;`+(gN1}+ZX00t2U#&bO-y#Ys*_^Z#Eey*Riy=R8;H(NiK<;*}Ek->~jI_--} z-5!@QzLx8urk zqr5tv#B1A*2W@XW|K{e(7*4;Z&9V)i=NLoS%Cw$$K6kcZ5T4Dy7^Hkvu;vW@Vpqox zVh*ZyVquGZF3{k3#}u%A+A4*fV!j7a*`BuY%gp54EZGZgM%`msyHsBbEH4)7SRi^} z>op^fJ>OiuFul}jIQ?^j&=#?i+)Iu#Tv?ksVUt1ypTpg#bF2$bT3@VYxF3Dm>0>%? zwTfAgK-d2|hd=cV3KN!^&bV^8N_^e)MH=6BvM>0S=s1VNK|SxERm+AmiEMY)SZ{Oq z&5@POU~b%UTg>53!}AS{?ML3Ty5IhhyRLu14#v$J7_E;k*qT_KmBjd-@reFjp7=W5 zs&mJ;^6%t(xHb2H=Eq&t)pt~O-nL;2_`Trw(YxQIuHAhS(eWStm=iCo~w(551eCLvnXs;)YNWxV7vSC?ak!t zeu52I7c`@Rl9Tpbu*eM6W16t%LPzw}*$g4gepgq0`7v>x9YftRP`W|}Eb&Y{467F; UdI+=${Q^mNy85}Sb4q9e0CIT^tpET3 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_forward_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_forward_small.png new file mode 100644 index 0000000000000000000000000000000000000000..fec20183a9302d1c630ecb75218007591fdfd9b6 GIT binary patch literal 613 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nAkmC978H@y_u<)&*Ui3y1q3mL2HH5!H|H!%Pk>aTzI8! z+h4kW;a^|Yo5Yo_6GM^(+?~!!vWSL!$u*jNfbC#u`cB{XzD75jCmi3MpZ@&YJ1Nhz ziyawQ9IzwP?q?hA-+ce=%#)j9Hv25sefzdJ{=)%Zo?Q%gSblluQ3D6NM?Z?TMpe#i zbBktJVzJNd+`^r`vJEr0avML|Y#4Xo%XIdJ5WBL8{!$74j0fDfea&*|4WE?2}a zH1F8U6eF;5%Em~s`}Hdtj=bbAza(GuLUbeZ4c*5F7aHktKFHXxk#R$z^6N_8%ijD9 zdN+(Sr`*25c*AI4d!J`@r?;*8hUZPak`2AumLJ#2{5~dkW7FS-TnxJvgi>vHuRYiQ zmjBlDga50|B@~Jx*=AKO-c&yAY?oh+%5i5`O@jBVIXk&4zUPYFkD@6I91Ymeg1nE~ b2N*(R-v9f1yXF!w-7t8%`njxgN@xNA4`}`Z literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_left.png b/app/src/main/res/drawable-xhdpi/ic_uart_left.png new file mode 100644 index 0000000000000000000000000000000000000000..c8c63a94445831649058654c90bb0819e5532ac4 GIT binary patch literal 886 zcmV-+1Bv{JP)CSU*rfHPKGrIu*7H8|bve^pZ)n8WVxotfV=y&D1m z0000000000000000Duz?hr<9WloNj%+hc4CsPXsWHzfXBTgBGXa($I^@%!}iGM-jAA8#O6ojXe*I7FiKZ)LcBYvR&y3&ht?Nt2qv4aoQOC!0BBcHc$uC#A2sb|iiy5I-%vGuY6)S?-G2J-MGt4HneJ2q3#T z7l=R6BEI<%K#u4B2fO*6SrmV(=^kq1;&%e^m)gX)J_W6WcJo2wP1Hu8{$w}%%L3GL=m^ZiuD#BT(S=Q*~qCdXrX1d!dl7TC?HcJa-O0LIqxXOh?7S-7{_ zfcQ!Dh0t#9tc+|6Q&1nB6RXuZ9u$?)H{B3x560JM;9nBCJFu|fdy2Vo%yLf_j< z7FwpDmgaa4Lpqj(3pznAa3{zGmL75eY(-!S`mi2It!76-LjW=cAsr`jOG#djD>c1z z=OPcFx&2mPPdfx4e-LgZIf7Mts=h2G3VRo1hw?2(Kwc(-9AQNJOBex#?WvikzmN@Cs!>}hMko|@W@CVR?VWX~v3>mdMngRl;=E$q4K`>~q9#3wtg2i&)0 zHd^13v3w#n3$iWj1|uNjsWBh!d4gr zHQ$YMQ}eN|zx4a&ZnKL7v# M07*qoM6N<$g7=MxfdBvi literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_left_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_left_small.png new file mode 100644 index 0000000000000000000000000000000000000000..ed8ac91dec4b072dc40804c4b4178b065f7ed708 GIT binary patch literal 744 zcmVP)0=8N@8J`wu9@%$5uRVrBx8ftW!IF~j%BBb>Mv#M(Z}`;z8v z>q~mycWuAdYfB}CLZMJ76bgkxAqlNkt4qaoJ9|ROcW^o9p9_@XY&P4tXlq{}`3#qf z++S6c<1|elR;$%})B=Ef9ha+ustQU55vIEqArVHtZwa}_Fj()p-9!laGA@@WWkbjU z!sO<7JdXAU71YH0fFF zu}1R+4Vfqf$l2o(x2L9_;L{$1Y>txc{lXr-h!AXdnC+1!y(2?N!-qWv-5#e@*pefB z+2hp3xd0IYlKW(J^?H-V`$EC#{tFG)(%n=#3M_NLk z8A7Tq<^xe@gjj?kd!*svWUE}XOq|m^?p};^1^F#cRcwz4g>u#Ui{nP0@$h$yr cfcGsE4@0f2fN4>R+-;DEr>mdKI;Vst06F1WW&i*H literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_pause_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_pause_small.png new file mode 100644 index 0000000000000000000000000000000000000000..504389aa05f3d9d05e1ef140cf2ee3bc91b61012 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xrg^$JhE&{ob891SgMt8Sfb$$z_5|MW{fr4xx;kqb6Au37 z75#t0d!2G_w>l$GJq#qAe4{(P=-lz*Ilac-E>~vmJRtFhODUn o98>#dK5dWN$b_u&$1|}6hK>IOnpZ02O$14Jy85}Sb4q9e04*FsRR910 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_play.png b/app/src/main/res/drawable-xhdpi/ic_uart_play.png new file mode 100644 index 0000000000000000000000000000000000000000..97ff9b07714e300ce171cb01cc093b9f96d04d81 GIT binary patch literal 669 zcmV;O0%HA%P))JiLX{;0~P=U z&;SkCfEFO{(!jop?`{Fo00l?^6o4~vCIMwxP1wCZb51hx&5${{_paX#V^skF00000 z00000z&|-04!7)rtbmuW9uOfb;3KT}u;%PYKa+ueZ>)e=3G1-#*ye8PYga({ac;xg zu$FaQf3oE=0y3+xnjm7&)(_i)x>$tu8br<5dYKA1W*gRXsD=#!WCUd1VrwdOK4=gS zi8G-oaXx4fklCebSR+72KxUKX!xjND0*>dyv*)%nQU3X+>9KWz06Ai;vG5veXm3GX z^Wn+MW2;30nI=6knVt_5!=HVg=EIx{kf{I{v4$4`nYJ<(dwUa*F%x@Ro&lFI6MK8D zfS-@8E3NaP1OXY9v3E%VBKtHOR?GnTSmT}w&@mrGWAD-h9M1=l*t@hA)WuXP)H*SA1&zed>B0TMnFG<#@@7`esb(RqXOi)dhAUF2y??0{E68AmqQ#FLxAuQMu6~R zC<1;H&!;|)_5J_>r+q%QnuZ}fK4M{9=>o*#=u!pj(#E&^9WZ{MSM^G=BmpX4%9kKO z^|2Js0tSl@5YUgAqlw-Gw3V^Lxn2aAJ)Uk|fJl6RfNxxUMaiN7S6|YzBw*B-7y*jo zgOUWezp6m1fMPD|&?Z1lOkA3PVlQmcAfV_g%OnMGX`he)6EU$@0bJZFB%rOhx>!Vj z%lN>80P``iN%#j2@&ed+00000000000020{mjD9*W49%z7TW9&00000NkvXXu0mjf Du!k6> literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_play_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_play_small.png new file mode 100644 index 0000000000000000000000000000000000000000..7f709bbf146eea3dfc5cd496b6f9c4127a25c304 GIT binary patch literal 531 zcmV+u0_^>XP)N8~ZMCgBnV%n`$I`Fw3PmED7jW^P=nL8dW|fHqhv!n=UT1t9`~<`TqqRfCF#<4!{9809^YPU;qfm Vpkraw!TbOK002ovPDHLkV1h-P>@ENR literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_rewind.png b/app/src/main/res/drawable-xhdpi/ic_uart_rewind.png new file mode 100644 index 0000000000000000000000000000000000000000..3e66f69b83296ad5960d6fbd9b0f87627903cb1e GIT binary patch literal 694 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+m?At~978H@y_tP5@KAt28}sCBt_w^V4%`bEp6cB@9J{ld zHK4)FfiZxA)q`1+0VsUOT+dkYSaaXWcWpKI&-Bd``dNPe-Tw26r-3$Nf~Eo+IquGl zmv`s?()+jfNYtaVKlWaKIaf&je{I;kz=y$4rwT3Sx)VLutoFTg@cA>=YBfR+A|IW5 zyyaxSdgr2(&!5Q({ST>ZJ)G(7DZlmOpFPZn`a>JEU)!x0z5lA=JTv!vmWq{MD^Ht! zU$A#y>8FN6=5{as-FWVO`tme(VW392+I?H>aubCXFzL+sRrB)UDkqf#Sr=T3LKTG) zY+oqtSY^POk-hNe(Q0?Cniaoi-w9|46Q9+wPRoVKhJEhz)m#%BqUL|!WoJ+xnke*O z18uOzko`@CwT>iR+$G#Q1LGj*6UyYy_G*QRpn;0D<@TN%=hu?pmK zWJh~(R!q4e@%`ysmngRB(^v&Av1W$qZPC(x?6PKy?%Jw+=dD`Ht>krX2U&G`yEhAD z^I!OBu(3?nwArBFL_S7rq^w`MR_=uG&i_c&|a(VEq^(F(t3Hpp*_3cj9{D{v^@y?W;~`W{mgN zEq%+nDfs_{k0rWWS&OC~G@t%Kb+5MvQ+zNhW|T8D2-I*IFz^WTFBR9>&jV86>FVdQ I&MBb@07Q5j(*OVf literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_rewind_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_rewind_small.png new file mode 100644 index 0000000000000000000000000000000000000000..27a2b9e73054c9860d9f47e834c69b3d3b1b6af5 GIT binary patch literal 601 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+7=L@ZIEGZ*dNae&|B!>o@zwLZ#o1(dCOWdm_|Aw(y?S-# z`GxUE^BJ|f`C@aLn!Ux@JqunwQfTJe=Ph^grpcF#`(O1Q{`b~%aEkx`{qfzcCS5>_ zVc>=~U(LK43mLu_Pp2I-@xAP`Aa45Wry==S#XX-)KF)}Hm(jzL{i-wm@`bJG+m37U zPd0D%y0SZI=3T4ftHspsX=HfrwYx5DvT||Mj2#{U;iug#7^+e24AooPw)t_V9nmVyhuyS+;aNKx}N$M@5$gkP*Hg{f6 z_WGiC_43>g4#{#?5EUucJdXYDeGv}uKGm#o!`Sax& zkL#IOj{Fi#V5xup*O7b23hf1r5&N0Aa{qYA`)l8-SluABacnUCkPhIH_TJ1p!iJt53Dhr6Tp lpp=fS?83{1OWS%022TJ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_right.png b/app/src/main/res/drawable-xhdpi/ic_uart_right.png new file mode 100644 index 0000000000000000000000000000000000000000..4ac16d068467428764e48346f64bb54b6cd4ef84 GIT binary patch literal 861 zcmV-j1ETziP)OaU$+Zh!(p0WJVbwvu7SB+;9Q?0d@h&1g8F1N{F=`d50p z&H(@b000000000001Uw4aJWW=;l!WE_ARyvYW!Q_N3kul_&?fh>;Kzp5kG$Pv0a|{ zdhES_#DMdOf0@M}{i4fLHeuJI0YSlH`#bSn{;tcT1OqB_@dxpb`}HlFFsK1>TG_;p zZDIE`Rn1rf&NCIIY3Qo3`!*UkX9Uz`8e8cid(%=p^;&*N6!l&F_)@qgyqFe8!UH3q z-g@vo#myW$OPJ*d%Lq6_G+h>UPiDQ3<~=b2>Wzdntt<+=kF3YjpmJDxe=m%uOAM%Q zLW-KDi|kd}Ma6*nEQIm&1B-C|MLEsy>%1LNWLloW7y*^0qLgqZf_VDLQatrmerOam zZB_Jwcxqw`JD9mrUJqp?@pNt>o|-Y>D4uQv@wCT)`X+Redj#$A)H|a@Vb|{T8S*Js z(YO^Ope|#UBNNtE<7u#NKo(OHPgPY|m^a`ko_2-Z zRaICtVL&!PT4AB0_SCz^uvTFaTzi!nWE8huSXnfYp z@(Adi>_A3ksY)<<_0NS_f2H-mc!T1nO|;SqxLp+gjyvJHakE%__j+up8Va*8KomDe zEs1Yp3d(V_6U5EWmY%8)2E&`eR2czp;^s^s{@AkkszyLgJYOBJDi}0wO175Gi?3-4GF8dYlmQki z8JaP`Y9&KUBVg~!p8wsqka$$4p#S}~mAtr>6!i0T1Zgkl;Y8eQR(zH4@@^d_T%!U2 n0000000000006YYvj77Ci4#V=Z}S*$00000NkvXXu0mjfWLAz8 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_right_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_right_small.png new file mode 100644 index 0000000000000000000000000000000000000000..5f304742f6b035d94ecc9bbfd781e73df9f8f139 GIT binary patch literal 727 zcmV;|0x127P)YQCYi7Ht0k1EPi|MH~WyXp>^jAd0~7hD?*o|7+zUSOmJ?LZ_^s!$gZ3u%7L@{I=7VP% z_a!2<(cVB@qEY}B;TUmjD@L`X^1Yi-;U)bXkac?RG$k<~ew|5Zb_7R-fV{idjgha>@ws{Ht;KCkj zQFSm8?6Kj>9;+mPy8VE^q9>%u-?;9XQRxD|Aiv-xvsxRx6znc_IpYTx zfWH#Qg58aMlJ_bA+ufNEGInWqK?Pv)KiS=j%2b%`t|x@t`LMen0`RADX~rk7pQv06 zWlo5c+MO@257h$(g5A+%H&VMCX1nVMc6aOB?z{=WIWqa27|$1Fc=Jme~K>w1^{LC0JpuQ^5_5n002ov JPDHLkV1f=sN^1ZB literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_settings.png b/app/src/main/res/drawable-xhdpi/ic_uart_settings.png new file mode 100644 index 0000000000000000000000000000000000000000..fe5fec471f17c23c4f274d2594361d5db6922869 GIT binary patch literal 1661 zcmV-@27>vCP)|sA)KjZ*#03Tp{faCz4eV)Z@O%#u9HB!sSNq<#TswhjA`fK%% z)FMJK7z_r3!C){L3$HDGAt^ z#-WWzCUdvt^T*y10E2(5eEkAKkP~{hS5rPe2eM3%eLRc*_j^?P2r}OYnE}^sQS z2A+hE)#f(H$?id03q*4EQa<-wLq-Z?89I*VsqB9pJOP$Fmw%ZEaGHhI=Lm#p@(;?y zofIKJ#FRiO7SxX12LW3LCn`Rc zKx3DLNt9d>-?YB(9Y~e^96}}FU}pAZOt z0xO7G_$pN0!aD>wRGZLpsQL(M1z2kTpYRSQb>C3}dNw0qjF6~ zV@eTDEhcm4LrC5T0F7EU?9T|pR=_1T8S4|;qNAiTw(9=R+LxTXo(b1!u=ZVB@^kXA z_kJ`H0IQ|?-jz=ob$uwW6B1hr%Lf5b!x&BD44VMRaI2=}Qlh9C@p5Kt2ZVFgR>_)Ipw#YYsqB>=Kr9Ydt8O+5@J zMXuD?6iWBW1U+;*>>O-vEvCMRLgvF5+CyXE9p&>o|yDqK8)&CV;epQ@~U zEbs^XGcZ3(BmqK;;1(1+wp0Yz7UZ7m?xFn;fj<x8e zJ{RqGz1kq_lXhCPlz`2*b@pLj(9neD8qplVQR-o43Snm3Wjb{WGlMX<(Ara6`1neF zS{L#qy}vZLhUlSYmz$m$LyYel;_iIZ23_NtY5`6*6K{8YCkE}5&mF)7m@a$A;{9FU zMsouFs^?KjTb~GswJ zeK`+p(rU($g7ZK5s0rlvvz3l_j=eh1P!lm9CL@GCJ}m)9$M$)M zW~VmhghH17Mrn&ZDP&C4ukZN0TjEU&^6R3zQYP-+@eq8oMeYFz?O9Lg#v&({fS28uqHIV zBZTqbhuah8N1lBfaT@o1NvAnU}e*7 z6Mu~c1GYh9DTcoSaJFgO(b})HZc5)@8tk=tb92)x+yZcl4FlFTPIAw}3G#_{5JHXi zB+&Xrhrt~Ko*tAxv`{|E2M!^to71yp2LNFwDL#+r6uLP1AdU}rewa}Fu#A0<0^p6K z3jEW(UV$b+I!F`Sg=DE7bEO!7&k3NOknBlePLLeUm>g56@#F(ODVqPFi2wXhr!;>_ zGNuZ-QyM>L?GUo(6!pP3INu--`A z8UU$r5qa`|a{nwnJ~+vdCK8Et#Qc4h!z;q~siuStE#yx%+2W&Zi9I;71>i4J)Rd$v z7V_tFwy4|zs7M)`>H*6rakF%h z@{3ZLJVvszAuUQETcbrpCXJa|44`SPQ@&=h+WP3qX+Y08u&I#7oe)R(L2_ zN>Z84sdSrU9vQUAnrRZRR6c<2*&VmH653%4#IuNY)?$pclm*4h2_^0+$=X%;7S%O5 zD>@2X81V3mjU7HUO;KY?y!Hh3g~^MR^TMM5S-~xx#+pG&T7@OF5gk?&PFlVm9qt|A z={)M99!4(~cvP)Kkc;{%mH!%A@PLg{Gg+>9% zA;vkmP+=jQ#Pr0zK-9kzU#lSu)=KG`sSI$d@Gz(diN{cMgig)RNEsoXt6F1YMaEb~ zhNt51V2=QNH349r|CqHWVEb~EA7ZN893Zikyh(BYWhdBG$;aLd#L(tHMNa-CrFfB= zM66KD=B@98>IdKi(}csm3*}umLzyOgz tRnh7415chjdGh4RlP6D}3ZUNt3;-0k%aSxwCl>$!002ovPDHLkV1nmLGUWgO literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_stop.png b/app/src/main/res/drawable-xhdpi/ic_uart_stop.png new file mode 100644 index 0000000000000000000000000000000000000000..c86dbb158637543341783c839c001198c041f82a GIT binary patch literal 262 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5XR(QHNhE&{ob7!Mqg9493;3La!Zi`vPI})aK-ii)zIK21z zg{M1evZ9!QYJngj)UYZcH1>U=&aU-69o0_`)E-jZ|8)MnviWDZSOgdtSsWM`1soVC rVLrIu6E9r+uy(0B)J})>?hT9#Jl1agI^tDnm{r-UW|?d(Tl literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_stop_small.png b/app/src/main/res/drawable-xhdpi/ic_uart_stop_small.png new file mode 100644 index 0000000000000000000000000000000000000000..2b07de4c241a5d9257c1dad3ffb913662acbd83c GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5Xnmk<`Ln>~)xwVnEK|#PF(B#}A<_&GD?=x8R?rIE(ee$=h zYeIEPUyzFDB$doV(Wfd literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_uart_up.png b/app/src/main/res/drawable-xhdpi/ic_uart_up.png new file mode 100644 index 0000000000000000000000000000000000000000..5411d8c99a5fecdffc7d8fb15037f9470fb87363 GIT binary patch literal 681 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+n7ln*978H@y}5NT_mF`|!^0ilbuKVQEZ{b9ux8*su=nY` zFMN9sGs!Z%OJ#^?V7$d>#ISXBd56H38#kUw{`23|bcOBad)D7aJwq9RHll)<3whhK zW0Zw{GRNOG+nB3+wsxJjOt+@tk8cK>*KYs5d~L3BvX3{@CD#4w2kpzYZlBbm%h@6S zhrN2nAHhF)LdVQFrG*6afB1j<@T&6GY~MpoEOX@lh*wLn%=?!(*+7-?VfR|@e~)Lz zZ{3o+sL)gXYf0pe|hBUulS;Wd+#X!@QE(2{`cpZu)^$2yQ$~gn(n(r z?3n(ode&?ohgA(nyD}0?&_-;zsRZfl-B~4;yFSy#4x271e-)DVl8GchD;@ZCF zYbN*{d%&NPt@ye(_(5;%HlwR4T>IW1k|=%cP~4g##J+D@<&O8pAG8iWi+u3xo>v`j zZXqYfo>!Cd<=J!c)$g7#?qr*}^wP<_ZznEtGU8;rKKsjKjd2E(CN~$Y71*Wz1Y7`^Tmdd;NaDz10ao;2tjLvg-jZ1K2$hvDmr)i*b&6>8{+tt+X~PT*EH<3V@OULmC(yw1*pUy+_)l5^|4J!DG_m=%x_7N$CUUeZcu3)d^8ZFn9_2 z3br5OCOh~P^driAAg4lYiB(9O9K&Y<-=BYz00b|kdlAydvSSYj{>}6(IT9nlxwb=b zg^Q;XVw^-0+ysJ;qV#Le^oVDN*b|}zJzgl>P<_962e2_kZI3Lm7p>F)7I(S`k5AglNG5OpvW^$L|JnAxNq=KdMKKfP-8za1A%qY@2qAEal|aXmSqq2Yf3&+`K}eRwh&S{oZ1CpI=Za-B*)5^%5~PlF*bkxf2Y`;azJ2ZN`p KpUXO@geCxxc^)zV literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/item_background_light_p.9.png b/app/src/main/res/drawable-xhdpi/item_background_light_p.9.png new file mode 100644 index 0000000000000000000000000000000000000000..74947f36ac78e7db805e84859dffcfef052efad6 GIT binary patch literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c0!3HFsSlX8YDb50q$YKTtZeb8+WSBKa0w}2C z>Eal|aXmSqq2YhPnFEIo9Qd&R!J+LXY;0_8oNO`wXG#<>XlkS#Sjm*9!I16FId8(W Rk2OGj44$rjF6*2UngE-_A|U_( literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/list_divider_holo_light.9.png b/app/src/main/res/drawable-xhdpi/list_divider_holo_light.9.png new file mode 100644 index 0000000000000000000000000000000000000000..65061c0f45e63fe0fea0bfad9c71ee52c07ef38e GIT binary patch literal 83 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/proximity_lock_closed.png b/app/src/main/res/drawable-xhdpi/proximity_lock_closed.png new file mode 100644 index 0000000000000000000000000000000000000000..010a0508adb23d44a304b248fdfc03d8cdb69e8f GIT binary patch literal 2637 zcmb7`X;f3!7RRFo8)G2?jYAQo5KK;a|cb5Qs9)-o^<6*+K%FGHg3Yi0WC1;BChhd-o6sWT*N@+XBhBw-;pVI2$bK zYVXuQU9g5s^VXYeU$a71=r>5`gH^$vnYZm^Ei=Hhxo%BF(ikQB= z+bfQj_>LKB=={2w?T?o?DSYFi@9z_Lm+eT5Jyjy^Q3?kK`uFQb%E_Z!yMkiN&G5(U zj~O=1jiH`uTpzb=5zQ`eP;E3*zQY&TJfoTYy88|<32Z`MJ+3Uo2M(bM^E(55XJP2R zUF|;Xr>GPwk2t|oR0|()ef^>UaF*;y&c#c?}l#* zXU-L}EsgYLc~mv5{{X*ZSWWWV_VpueYF#0GGL#$k{T%J~xX_#stn(`j9TYf~9YnJ) z**U3xYim_u3G0UEvpJI%YtBlAuJ!DZmZ6A<@b#+|ZVt6uAD+%j{xO+TYi}m*uJpe@ z@+`_jm85u77n?D1M!MKYaMz@S?S)_)i^}smCw@w)p4Dq2RvYFQ9M0b+t?JU^`|%O` zJsaU%qo5heH}l)0zm*>YnaY-n39UxPnujCP=VJzA)K?F;EQl;b>-8RA@BZBDFDfAkryRCh9uk$2eH!crzOUdv2L!wV0_SC0^ zj|awZI}LC;VKG+q*PjI3>ojn!+2uxESK=D5#*a=~XIhJI@rT8pf2I!&*wR;~4r_YtuNTNI6RI|!zK0K}( zWkeq(@&9FphrGlWXd%$zER*(=h)L!_7nMB8+O za{N`q`>x>6!=hXZ3UF&(lFBGhgdo^`C)?~hGB}`kba7%`^0HK}DRZhAr9Kk=dAv_% zAr=%rMIq|At*P0HsIDgq0DhNn!tLTxmIl&yGuW?&QM z<(T*t5PCF!dfEw{pQ+wSy->}>o2{l@vi9xa6PC-r==3p6B*Zez?LGm@HI3|VAGTU3Z59ih#@q)Yc{{Ar-phlX=#N|r;!*2CuXDzv z^pEY|$40C%GN)GJv35 zT~oaMW2bm%v^>Kg$&0uYyoBb-^h`m1(8WCz$d`b8BhZiXO zuvBusbp~|dXfL?YTmg4P))RPz*jQ61GC=Ls$eZ$v7fC)R?~PI#{-gbP5=Sg-imMzY|!I>SmA4V6eykG&ae@#`+UmF%!qYgQ2rL z!(}@5JMg4&JcbAN?e4T)q{Z3~C@OehG$<&J{2o*bs)expOPvp!ic?8a#wH+Aamo0j zj9i? zoq;_g!|^4#~aI4#uz<|G^Qn1-dM)hGKEz|g|A zD5JAqOshLnKdO?NC+wmg1%Ezw!uX`)EZISov{>Q8mVxP@nz6mG4ZQsfqzf2kTsB&t?vs8g4s%T z8}t*!P9qJ$*IjNH_$W?N!{$v-V9qkQi9E^jRE+mmq5F~G7tjeiNi)Te3fT06Q1ARn8z4*OQ zZtApU4ef8JWR? zl;~pf4vhW1YT{|8nYz^`JLp&3FA!k#k}OmqD=rFXorGbhR?%VUBaiW1k-&ko|7V$M zz}#b4jsHgJgN5I0QuSNW9Jn0Lv9@mfnB5R8Tc7HGagYU>m2LPqTSptg>5I(&0_}^? AsQ>@~ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/proximity_lock_open.png b/app/src/main/res/drawable-xhdpi/proximity_lock_open.png new file mode 100644 index 0000000000000000000000000000000000000000..d4000316e3ea654c5694cbb506e0e2e7191c0579 GIT binary patch literal 2636 zcma)8dsvcL8YdSVmbS5`a8g5^BsI(&O><1su+$(gs3?h7!SgT?Kl(xlJun1XZE!ynN0>K@3L7@+WX`k92VsVh>|}TKI=bo?Q|k+U_J@b_WH5ZhnAu* zo4&3X8HHEeRQr5m2u_osmy@D%H$t1C>koE(NjKLi?U zR9)f|5>)VtDw%Yh)iyTewRgYxeyS(Mz@Pwva!hdE9y*T>drdm*XhCsJKh zf9=k$TCy{Wv2=1p?5kjKwJXfJS0#wvLWh{1fwu?>ME?EMTKI<0?TOnnVxi`Tucs?i z!`ITB!bBbi*e{u^<_MKq<61b8PagY+L1uuJZ~~F!j_aU6)^_y<`RIU~()%alX*hwc z=K~p8&cM?ir7YXxaW?uD7T}3v4$rBO-S^OqLI|un$F4$ zT)<+L+a>&5Yxwz6!82VgVd=tv=MZ-g)*jto)ta%U-3#~W>yLEDWzua3iW$Fef^GFl z?^bMwUPER=Xe}hEpv&Wfan6C{pBmQ(-`;qX0+&TCx`mWH`t0WN+`?(7FL`LATH%() zPk89$|JU=;Qi1%cAgj^XZf4$lL(Di~vK$!PB?|0$b>O-$Q4WIg{R0`L>kU-yrDLLc znMICq#^P*!Ga+=u2KIBdPJ(9d;n(<)rx!bq-wvE2Wmo4_Z=_!dp+bZSi1O-cEUpV( zHO@%)Q{ zlt>}T^K6m5kDYpgka_E)z-Wa_+DCx|W_`0So|ifQ%H-}6Ge{nn(`{Q$fsFGCaG7qr zW5OCQF}Og zh~%U0?=m)m3|4)WlBja^*9fce{^;pTo@{@lQe$;wApJ@`LT;*#H7uF+91A-6jXD3v zE3pwN$ouwG*bcF^o^Z(FS&e0AM&KT-;drpk?UA|VSb@KEdj-pW16NTuOAZq#c+B9h zp;*J|wQPSPp|puH&ICeZ!>Frif9FjUk9FWNMadC5`hHp=#2~9LutP;q@lIv{9{p|9 zP9RjZvAFn+GYE>07TzOhT_v?7bF%FwJdsqhk!CXA+`|aVf^8h749MLu+Y($c+kns$ zn+AXc?Zp0S{t!_TKjHibf&^{t^M4}$e&O#?TgYU0vK~Nn!scn?lR*v$y0_H9&zOEF zLbffz`F~}4{X9PiD33HR+y}QpnVF?Cq{*~ib$?>v*tb$X7eA^w2(7C+IAJ5wHD6*N&IdXZ3JAaF1Y1CVx|FdelvT@EUrC6Xvg^GW; zdE?(!54SQs3WVC?55)fhTy)Hvw6)cAbEP%9MqaoTP7h;Ck&J-I{9MK1 zs#U!#7qK7vnA6LCCvo1|m{K}_SZ};svz>w_GI&ks2=5Bd5(kV% zalLW7RCoGDxiZUA$*Z{g*MRxC&6!~pU<6M=uXovFnR>^14U7novzjU&swU*;7V68q zoOfYYs@-YJPNPrLwA!V~HU(-(Y7Ku1g*{VZk9j*yNH`(2-h47LjrjaKMfpTLRvVVi zYO^3De*K_>q04^hq04xl$!hzuFO84K7wu=?eP~%P2X!rZyE|ask|s#&F>@dF*dJ2I zi@9^FZ<-%UzG8oP#i*a{iov-lDMgYi&swyBSxt9GE;O`AAYTHZ0{M%2`I(Ya7!5ve zuE)1*Kl?A_29Y<|&q-P4gLq$)zH>M0W}Ptig!8^EBxcwm!hc!HJqXOY*e)#(V!pm4 zn7@SuW+4$V(!vJ0vi!BC@LdzDGPp4%V@TFfJXS;_rNLJ|jiEJ_5P91@gB z9`Ctp|1X9AfqFk_4*%U!PGE*BxBsSR8<0#)^t}M2Og&v3LpZLdo=_BOP!MrA_;(JI z&ARd>LXBA)x?GPxIJf81qW+y5e#gwnSYfek()lO)6XrddYhIzn#by0fRvTylgQu&X J%Q~loCIGUAC13ym literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/shadow_r.png b/app/src/main/res/drawable-xhdpi/shadow_r.png new file mode 100644 index 0000000000000000000000000000000000000000..ae07b59379f5fe0924138b29cab52307382a0786 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^AT|>R8<0#)^t}M2I14-?iy0WWg+Z8+Vb&Z8prCAK zNJNQqer|4RUI~!Pz~Eeznpl#WqEMb$lA+-4=^K!um&y(lH}Z6G4B@yQdwe190R;wz zgUr#*hZoPBSm?c6LqdpS`ko&Q`TylqLPSznqPvgt{8|0bh%r8&eUr=-Jp+)jp00i_ I>zopr08LIT;Q#;t literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/zip.png b/app/src/main/res/drawable-xhdpi/zip.png new file mode 100644 index 0000000000000000000000000000000000000000..eb96135d4e7a3af0c47d1585065b33a24ef55972 GIT binary patch literal 86140 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