From 13675b3567f8cc8b0901125aec5a59849253fb7d Mon Sep 17 00:00:00 2001 From: Ramandeep Date: Thu, 9 Sep 2021 00:01:15 +0530 Subject: [PATCH] SPCA App --- README.md | 134 -- app/build.gradle | 101 +- app/google-services.json | 48 + .../android/nrftoolbox/ApplicationTest.java | 35 - app/src/main/AndroidManifest.xml | 375 ++--- app/src/main/assets/fa-solid-900.ttf | Bin 0 -> 203980 bytes app/src/main/assets/labels.txt | 2 + app/src/main/assets/model.tflite | Bin 0 -> 739296 bytes app/src/main/ic_launcher-playstore.png | Bin 0 -> 64341 bytes .../android/nrftoolbox/AppHelpFragment.java | 75 - .../android/nrftoolbox/FeaturesActivity.java | 224 --- .../nrftoolbox/SplashscreenActivity.java | 95 -- .../app/ExpandableListActivity.java | 299 ---- .../android/nrftoolbox/bpm/BPMActivity.java | 179 --- .../android/nrftoolbox/bpm/BPMManager.java | 165 -- .../nrftoolbox/bpm/BPMManagerCallbacks.java | 31 - .../android/nrftoolbox/cgms/CGMSActivity.java | 280 ---- .../android/nrftoolbox/cgms/CGMSManager.java | 445 ------ .../nrftoolbox/cgms/CGMSManagerCallbacks.java | 48 - .../android/nrftoolbox/cgms/CGMSRecord.java | 49 - .../nrftoolbox/cgms/CGMSRecordsAdapter.java | 79 - .../android/nrftoolbox/cgms/CGMService.java | 290 ---- .../android/nrftoolbox/csc/CSCActivity.java | 267 ---- .../android/nrftoolbox/csc/CSCManager.java | 127 -- .../nrftoolbox/csc/CSCManagerCallbacks.java | 28 - .../android/nrftoolbox/csc/CSCService.java | 209 --- .../csc/settings/SettingsActivity.java | 56 - .../csc/settings/SettingsFragment.java | 79 - .../android/nrftoolbox/dfu/DfuActivity.java | 862 ----------- .../nrftoolbox/dfu/DfuInitiatorActivity.java | 83 - .../android/nrftoolbox/dfu/DfuService.java | 54 - .../nrftoolbox/dfu/NotificationActivity.java | 50 - .../dfu/adapter/FileBrowserAppsAdapter.java | 74 - .../dfu/fragment/UploadCancelFragment.java | 86 -- .../dfu/fragment/ZipInfoFragment.java | 42 - .../dfu/settings/AboutDfuPreference.java | 59 - .../dfu/settings/SettingsActivity.java | 56 - .../dfu/settings/SettingsFragment.java | 112 -- .../gls/ExpandableRecordAdapter.java | 263 ---- .../nrftoolbox/gls/GlucoseActivity.java | 204 --- .../nrftoolbox/gls/GlucoseManager.java | 407 ----- .../gls/GlucoseManagerCallbacks.java | 44 - .../android/nrftoolbox/gls/GlucoseRecord.java | 118 -- .../android/nrftoolbox/hrs/HRSActivity.java | 248 --- .../android/nrftoolbox/hrs/HRSManager.java | 150 -- .../nrftoolbox/hrs/HRSManagerCallbacks.java | 30 - .../android/nrftoolbox/hrs/LineGraphView.java | 121 -- .../android/nrftoolbox/hts/HTSActivity.java | 223 --- .../android/nrftoolbox/hts/HTSManager.java | 107 -- .../nrftoolbox/hts/HTSManagerCallbacks.java | 33 - .../android/nrftoolbox/hts/HTSService.java | 208 --- .../hts/settings/SettingsActivity.java | 56 - .../hts/settings/SettingsFragment.java | 42 - .../nrftoolbox/parser/AlertLevelParser.java | 54 - .../BloodPressureMeasurementParser.java | 92 -- .../parser/BodySensorLocationParser.java | 43 - .../parser/CGMMeasurementParser.java | 194 --- .../CGMSpecificOpsControlPointParser.java | 295 ---- .../parser/CSCMeasurementParser.java | 74 - .../nrftoolbox/parser/DateTimeParser.java | 53 - .../GlucoseMeasurementContextParser.java | 188 --- .../parser/GlucoseMeasurementParser.java | 165 -- .../parser/HeartRateMeasurementParser.java | 111 -- .../IntermediateCuffPressureParser.java | 87 -- .../parser/RSCMeasurementParser.java | 74 - .../RecordAccessControlPointParser.java | 172 --- .../parser/TemperatureMeasurementParser.java | 85 - .../parser/TemperatureTypeParser.java | 59 - .../nrftoolbox/parser/TemplateParser.java | 59 - .../profile/multiconnect/IDeviceLogger.java | 45 - .../nrftoolbox/proximity/DeviceAdapter.java | 151 -- .../proximity/LinkLossFragment.java | 63 - .../proximity/ProximityActivity.java | 191 --- .../proximity/ProximityManager.java | 149 -- .../proximity/ProximityManagerCallbacks.java | 32 - .../proximity/ProximityServerManager.java | 386 ----- .../ProximityServerManagerCallbacks.java | 31 - .../proximity/ProximityService.java | 570 ------- .../android/nrftoolbox/rsc/RSCActivity.java | 288 ---- .../android/nrftoolbox/rsc/RSCManager.java | 103 -- .../nrftoolbox/rsc/RSCManagerCallbacks.java | 29 - .../android/nrftoolbox/rsc/RSCService.java | 252 --- .../rsc/settings/SettingsActivity.java | 56 - .../rsc/settings/SettingsFragment.java | 42 - .../scanner/ExtendedBluetoothDevice.java | 53 - .../android/nrftoolbox/template/Readme.txt | 76 - .../nrftoolbox/template/TemplateActivity.java | 226 --- .../nrftoolbox/template/TemplateManager.java | 283 ---- .../template/TemplateManagerCallbacks.java | 38 - .../nrftoolbox/template/TemplateService.java | 193 --- .../TemplateCharacteristicCallback.java | 21 - .../template/settings/SettingsActivity.java | 56 - .../template/settings/SettingsFragment.java | 41 - .../android/nrftoolbox/uart/UARTActivity.java | 826 ---------- .../nrftoolbox/uart/UARTButtonAdapter.java | 107 -- .../uart/UARTConfigurationsAdapter.java | 127 -- .../nrftoolbox/uart/UARTControlFragment.java | 133 -- .../nrftoolbox/uart/UARTEditDialog.java | 189 --- .../nrftoolbox/uart/UARTInterface.java | 29 - .../uart/UARTLocalLogContentProvider.java | 39 - .../nrftoolbox/uart/UARTLogAdapter.java | 90 -- .../nrftoolbox/uart/UARTLogFragment.java | 299 ---- .../android/nrftoolbox/uart/UARTManager.java | 147 -- .../nrftoolbox/uart/UARTManagerCallbacks.java | 34 - .../UARTNewConfigurationDialogFragment.java | 134 -- .../android/nrftoolbox/uart/UARTService.java | 319 ---- .../uart/database/ConfigurationContract.java | 38 - .../uart/database/DatabaseHelper.java | 259 ---- .../nrftoolbox/uart/database/NameColumns.java | 28 - .../nrftoolbox/uart/database/UndoColumns.java | 27 - .../nrftoolbox/uart/domain/Command.java | 154 -- .../uart/domain/UartConfiguration.java | 71 - .../UARTConfigurationSynchronizer.java | 138 -- .../nrftoolbox/utility/FileHelper.java | 246 --- .../nrftoolbox/utility/ParserUtils.java | 39 - .../wearable/MainWearableListenerService.java | 69 - .../nrftoolbox/widget/ClosableSpinner.java | 36 - .../widget/DividerItemDecoration.java | 111 -- .../widget/ForegroundLinearLayout.java | 148 -- .../no/spca/android/iisc/DebugLogger.java | 51 + .../spca/android/iisc/FeaturesActivity.java | 95 ++ .../no/spca/android/iisc/FontAwesome.java | 35 + .../android/iisc/NotificationData.java} | 28 +- .../iisc}/PermissionRationaleFragment.java | 25 +- .../java/no/spca/android/iisc/SPCA/About.java | 21 + .../no/spca/android/iisc/SPCA/AddTest.java | 870 +++++++++++ .../android/iisc/SPCA/CreatePassword.java | 110 ++ .../spca/android/iisc/SPCA/CycleManager.java | 357 +++++ .../spca/android/iisc/SPCA/CycleService.java | 209 +++ .../no/spca/android/iisc/SPCA/Datashow.java | 648 ++++++++ .../spca/android/iisc/SPCA/FontAwesome.java | 35 + .../android/iisc/SPCA/ForgetPassword.java | 242 +++ .../iisc/SPCA/ForgetPasswordReset.java | 69 + .../spca/android/iisc/SPCA/GraphActivity.java | 488 ++++++ .../iisc/SPCA/Interface/ItemClickListner.java | 9 + .../spca/android/iisc/SPCA/LoginScreen.java | 215 +++ .../spca/android/iisc/SPCA/MainActivity.java | 220 +++ .../iisc/SPCA/Model/RegisterHelper.java | 41 + .../spca/android/iisc/SPCA/Model/Tests.java | 167 ++ .../spca/android/iisc/SPCA/NavigationTop.java | 109 ++ .../no/spca/android/iisc/SPCA/Register.java | 190 +++ .../iisc/SPCA/SPCAManagerCallbacks.java | 10 + .../android/iisc/SPCA/SpaceDecoration.java | 20 + .../spca/android/iisc/SPCA/TempDataShow.java | 650 ++++++++ .../android/iisc/SPCA/TemperatureManager.java | 156 ++ .../android/iisc/SPCA/TemperatureService.java | 142 ++ .../android/iisc/SPCA/TestViewHolder.java | 47 + .../iisc/SPCA/VerifyOTP/VerifyOtp.java | 150 ++ .../VerifyOTP/VerifyOtpForgetPassword.java | 149 ++ .../callback/CycleCharacteristicCallback.java | 12 + .../SPCA/callback/CycleDataCallback.java} | 20 +- .../TemperatureCharacteristicCallback.java | 12 + .../callback/TemperatureDataCallback.java | 36 + .../iisc/SPCA/settings/SettingsActivity.java | 35 + .../iisc/SPCA/settings/SettingsFragment.java | 19 + .../android/iisc/SplashscreenActivity.java | 104 ++ .../android/iisc}/adapter/AppAdapter.java | 31 +- .../iisc/app/ExpandableListActivity.java | 132 ++ .../android/iisc}/battery/BatteryManager.java | 36 +- .../battery/BatteryManagerCallbacks.java | 2 +- .../spca/android/iisc/parser/CycleParser.java | 19 + .../iisc/parser/TemperatureParser.java | 23 + .../iisc}/profile/BleProfileActivity.java | 209 +-- .../BleProfileExpandableListActivity.java | 207 +-- .../iisc}/profile/BleProfileService.java | 262 +--- .../BleProfileServiceReadyActivity.java | 284 +--- .../iisc}/profile/LoggableBleManager.java | 23 +- .../BleMulticonnectProfileService.java | 259 +--- ...lticonnectProfileServiceReadyActivity.java | 250 +-- .../profile/multiconnect/IDeviceLogger.java | 14 + .../iisc}/scanner/DeviceListAdapter.java | 47 +- .../iisc/scanner/ExtendedBluetoothDevice.java | 33 + .../iisc}/scanner/ScannerFragment.java | 94 +- .../widget/ForegroundRelativeLayout.java | 27 +- app/src/main/res/anim/button_animation.xml | 16 + app/src/main/res/animator/click_animator.xml | 44 - app/src/main/res/color/button_color.xml | 5 - app/src/main/res/color/menu_text.xml | 26 - app/src/main/res/drawable-hdpi/battery.png | Bin 392 -> 0 bytes app/src/main/res/drawable-hdpi/dst_logo.png | Bin 0 -> 34700 bytes .../drawable-hdpi/ic_action_disconnect.png | Bin 332 -> 0 bytes .../main/res/drawable-hdpi/ic_bpm_feature.png | Bin 2697 -> 0 bytes .../res/drawable-hdpi/ic_cgms_feature.png | Bin 2926 -> 0 bytes .../main/res/drawable-hdpi/ic_csc_feature.png | Bin 5152 -> 0 bytes .../main/res/drawable-hdpi/ic_dfu_feature.png | Bin 3079 -> 0 bytes .../res/drawable-hdpi/ic_glucose_feature.png | Bin 1373 -> 0 bytes app/src/main/res/drawable-hdpi/ic_help.png | Bin 1544 -> 0 bytes .../main/res/drawable-hdpi/ic_hrs_feature.png | Bin 2573 -> 0 bytes .../main/res/drawable-hdpi/ic_hts_feature.png | Bin 2299 -> 0 bytes .../drawable-hdpi/ic_proximity_feature.png | Bin 2271 -> 0 bytes .../main/res/drawable-hdpi/ic_rsc_feature.png | Bin 2525 -> 0 bytes .../res/drawable-hdpi/ic_stat_notify_cgms.png | Bin 659 -> 0 bytes .../res/drawable-hdpi/ic_stat_notify_csc.png | Bin 872 -> 0 bytes .../res/drawable-hdpi/ic_stat_notify_hts.png | Bin 551 -> 0 bytes .../ic_stat_notify_proximity.png | Bin 782 -> 0 bytes .../res/drawable-hdpi/ic_stat_notify_rsc.png | Bin 502 -> 0 bytes .../res/drawable-hdpi/ic_stat_notify_uart.png | Bin 696 -> 0 bytes app/src/main/res/drawable-hdpi/iisc_logo.png | Bin 0 -> 228963 bytes .../res/drawable-hdpi/proximity_lock_open.png | Bin 2697 -> 0 bytes app/src/main/res/drawable-hdpi/shadow_l.png | Bin 110 -> 0 bytes app/src/main/res/drawable-hdpi/shadow_r.png | Bin 169 -> 0 bytes app/src/main/res/drawable-mdpi/dst_logo.png | Bin 0 -> 17136 bytes app/src/main/res/drawable-mdpi/iisc_logo.png | Bin 0 -> 122806 bytes app/src/main/res/drawable-v21/button.xml | 22 +- .../main/res/drawable-v21/ic_feature_bg.xml | 22 +- .../ic_icon_button_background.xml | 18 - .../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 2573 -> 0 bytes .../res/drawable-xhdpi/app_file_manager.png | Bin 3463 -> 0 bytes .../res/drawable-xhdpi/app_google_play.png | Bin 2247 -> 0 bytes .../drawable-xhdpi/app_total_commander.png | Bin 1596 -> 0 bytes .../btn_default_focused_holo_light.9.png | Bin 476 -> 0 bytes app/src/main/res/drawable-xhdpi/dst_logo.png | Bin 0 -> 35354 bytes .../drawable-xhdpi/ic_action_disconnect.png | Bin 392 -> 0 bytes .../res/drawable-xhdpi/ic_bpm_feature.png | Bin 2076 -> 0 bytes .../res/drawable-xhdpi/ic_cgms_feature.png | Bin 4650 -> 0 bytes .../res/drawable-xhdpi/ic_csc_feature.png | Bin 4224 -> 0 bytes .../res/drawable-xhdpi/ic_dfu_feature.png | Bin 4987 -> 0 bytes .../res/drawable-xhdpi/ic_glucose_feature.png | Bin 2091 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_help.png | Bin 1796 -> 0 bytes .../res/drawable-xhdpi/ic_hrs_feature.png | Bin 3695 -> 0 bytes .../res/drawable-xhdpi/ic_hts_feature.png | Bin 1817 -> 0 bytes .../drawable-xhdpi/ic_hts_feature_black.png | Bin 368 -> 0 bytes .../ic_nrf_connect_feature_fg.png | Bin 846 -> 0 bytes .../drawable-xhdpi/ic_proximity_feature.png | Bin 3156 -> 0 bytes .../res/drawable-xhdpi/ic_rsc_feature.png | Bin 3436 -> 0 bytes .../drawable-xhdpi/ic_stat_notify_cgms.png | Bin 844 -> 0 bytes .../res/drawable-xhdpi/ic_stat_notify_csc.png | Bin 1196 -> 0 bytes .../res/drawable-xhdpi/ic_stat_notify_hts.png | Bin 615 -> 0 bytes .../ic_stat_notify_proximity.png | Bin 928 -> 0 bytes .../res/drawable-xhdpi/ic_stat_notify_rsc.png | Bin 751 -> 0 bytes .../drawable-xhdpi/ic_stat_notify_uart.png | Bin 922 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_uart_1.png | Bin 493 -> 0 bytes .../res/drawable-xhdpi/ic_uart_1_small.png | Bin 355 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_uart_2.png | Bin 1278 -> 0 bytes .../res/drawable-xhdpi/ic_uart_2_small.png | Bin 903 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_uart_3.png | Bin 1344 -> 0 bytes .../res/drawable-xhdpi/ic_uart_3_small.png | Bin 968 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_uart_4.png | Bin 742 -> 0 bytes .../res/drawable-xhdpi/ic_uart_4_small.png | Bin 559 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_uart_5.png | Bin 982 -> 0 bytes .../res/drawable-xhdpi/ic_uart_5_small.png | Bin 735 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_uart_6.png | Bin 1516 -> 0 bytes .../res/drawable-xhdpi/ic_uart_6_small.png | Bin 1021 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_uart_7.png | Bin 901 -> 0 bytes .../res/drawable-xhdpi/ic_uart_7_small.png | Bin 630 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_uart_8.png | Bin 1646 -> 0 bytes .../res/drawable-xhdpi/ic_uart_8_small.png | Bin 1181 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_uart_9.png | Bin 1473 -> 0 bytes .../res/drawable-xhdpi/ic_uart_9_small.png | Bin 1015 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_about.png | Bin 1215 -> 0 bytes .../drawable-xhdpi/ic_uart_about_small.png | Bin 860 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_down.png | Bin 726 -> 0 bytes .../res/drawable-xhdpi/ic_uart_down_small.png | Bin 582 -> 0 bytes .../res/drawable-xhdpi/ic_uart_feature.png | Bin 5357 -> 0 bytes .../res/drawable-xhdpi/ic_uart_forward.png | Bin 648 -> 0 bytes .../drawable-xhdpi/ic_uart_forward_small.png | Bin 613 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_left.png | Bin 886 -> 0 bytes .../res/drawable-xhdpi/ic_uart_left_small.png | Bin 744 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_pause.png | Bin 297 -> 0 bytes .../drawable-xhdpi/ic_uart_pause_small.png | Bin 244 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_play.png | Bin 669 -> 0 bytes .../res/drawable-xhdpi/ic_uart_play_small.png | Bin 531 -> 0 bytes .../res/drawable-xhdpi/ic_uart_rewind.png | Bin 694 -> 0 bytes .../drawable-xhdpi/ic_uart_rewind_small.png | Bin 601 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_right.png | Bin 861 -> 0 bytes .../drawable-xhdpi/ic_uart_right_small.png | Bin 727 -> 0 bytes .../res/drawable-xhdpi/ic_uart_settings.png | Bin 1661 -> 0 bytes .../drawable-xhdpi/ic_uart_settings_small.png | Bin 1231 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_stop.png | Bin 262 -> 0 bytes .../res/drawable-xhdpi/ic_uart_stop_small.png | Bin 224 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_up.png | Bin 681 -> 0 bytes .../res/drawable-xhdpi/ic_uart_up_small.png | Bin 631 -> 0 bytes app/src/main/res/drawable-xhdpi/iisc_logo.png | Bin 0 -> 148037 bytes .../drawable-xhdpi/proximity_lock_open.png | Bin 2636 -> 0 bytes app/src/main/res/drawable-xhdpi/shadow_l.png | Bin 110 -> 0 bytes app/src/main/res/drawable-xhdpi/shadow_r.png | Bin 169 -> 0 bytes app/src/main/res/drawable-xhdpi/zip.png | Bin 86140 -> 0 bytes app/src/main/res/drawable-xxhdpi/dst_logo.png | Bin 0 -> 114701 bytes app/src/main/res/drawable-xxhdpi/gradient.xml | 44 + .../drawable-xxhdpi/ic_action_add_normal.png | Bin 1289 -> 0 bytes .../drawable-xxhdpi/ic_action_add_pressed.png | Bin 1520 -> 0 bytes .../ic_action_clear_normal.png | Bin 655 -> 0 bytes .../ic_action_clear_pressed.png | Bin 528 -> 0 bytes .../drawable-xxhdpi/ic_action_disconnect.png | Bin 512 -> 0 bytes .../ic_action_download_normal.png | Bin 329 -> 0 bytes .../ic_action_download_pressed.png | Bin 320 -> 0 bytes .../main/res/drawable-xxhdpi/iisc_logo.png | Bin 0 -> 631036 bytes .../main/res/drawable-xxxhdpi/dst_logo.png | Bin 0 -> 185075 bytes .../drawable-xxxhdpi/ic_action_disconnect.png | Bin 642 -> 0 bytes .../res/drawable-xxxhdpi/ic_battery_alert.png | Bin 249 -> 0 bytes .../res/drawable-xxxhdpi/ic_battery_full.png | Bin 228 -> 0 bytes .../res/drawable-xxxhdpi/ic_proximity_tag.png | Bin 2354 -> 0 bytes .../ic_stat_notify_proximity_find.png | Bin 1451 -> 0 bytes .../ic_stat_notify_proximity_silent.png | Bin 1449 -> 0 bytes .../main/res/drawable-xxxhdpi/iisc_logo.png | Bin 0 -> 941758 bytes .../main/res/drawable/app_file_browser.xml | 28 - app/src/main/res/drawable/bg_circle.xml | 12 + app/src/main/res/drawable/button.xml | 22 +- app/src/main/res/drawable/button_n.xml | 22 +- app/src/main/res/drawable/button_p.xml | 22 +- app/src/main/res/drawable/buttonshape.xml | 20 + app/src/main/res/drawable/ic_action_add.xml | 28 - app/src/main/res/drawable/ic_action_clear.xml | 9 +- .../main/res/drawable/ic_action_download.xml | 28 - app/src/main/res/drawable/ic_battery.xml | 27 - app/src/main/res/drawable/ic_feature_bg.xml | 22 +- app/src/main/res/drawable/ic_feature_bg_n.xml | 22 +- app/src/main/res/drawable/ic_feature_bg_p.xml | 22 +- .../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 - .../drawable/ic_nrf_connect_feature_small.xml | 26 - app/src/main/res/drawable/ic_rssi_bar.xml | 22 +- app/src/main/res/drawable/nordic_logo.xml | 142 -- .../res/drawable/nordic_logo_horiz_white.xml | 31 - 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/text_back.xml | 7 + 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 - app/src/main/res/font/fontstyle.ttf | Bin 0 -> 45352 bytes .../res/layout-land/activity_feature_bpm.xml | 298 ---- .../res/layout-land/activity_feature_cgms.xml | 220 --- .../res/layout-land/activity_feature_csc.xml | 295 ---- .../res/layout-land/activity_feature_dfu.xml | 293 ---- .../res/layout-land/activity_feature_gls.xml | 220 --- .../res/layout-land/activity_feature_hrs.xml | 153 -- .../res/layout-land/activity_feature_hts.xml | 112 -- .../activity_feature_proximity.xml | 90 -- .../res/layout-land/activity_feature_rsc.xml | 325 ---- .../res/layout-land/activity_feature_uart.xml | 67 - .../res/layout-land/feature_uart_button.xml | 29 - .../fragment_feature_uart_control.xml | 95 -- .../activity_feature_bpm.xml | 299 ---- .../activity_feature_csc.xml | 257 --- .../activity_feature_dfu.xml | 286 ---- .../activity_feature_hrs.xml | 154 -- .../feature_uart_button.xml | 28 - .../activity_feature_rsc.xml | 292 ---- app/src/main/res/layout-v21/feature_icon.xml | 49 - .../layout-v21/fragment_device_selection.xml | 49 - .../layout-v23/fragment_device_selection.xml | 22 +- app/src/main/res/layout/activity_about.xml | 286 ++++ .../res/layout/activity_create__password.xml | 184 +++ .../main/res/layout/activity_feature_bpm.xml | 286 ---- .../main/res/layout/activity_feature_cgms.xml | 218 --- .../res/layout/activity_feature_cgms_item.xml | 54 - .../main/res/layout/activity_feature_csc.xml | 257 --- .../main/res/layout/activity_feature_dfu.xml | 290 ---- .../main/res/layout/activity_feature_gls.xml | 218 --- .../res/layout/activity_feature_gls_item.xml | 58 - .../layout/activity_feature_gls_subitem.xml | 48 - .../main/res/layout/activity_feature_hrs.xml | 147 -- .../main/res/layout/activity_feature_hts.xml | 112 -- .../res/layout/activity_feature_proximity.xml | 90 -- .../activity_feature_proximity_item.xml | 98 -- .../main/res/layout/activity_feature_rsc.xml | 292 ---- .../res/layout/activity_feature_template.xml | 512 ++++-- .../main/res/layout/activity_feature_uart.xml | 60 - app/src/main/res/layout/activity_features.xml | 24 +- .../res/layout/activity_forget__password.xml | 203 +++ app/src/main/res/layout/activity_graph.xml | 196 +++ .../res/layout/activity_login__screen.xml | 196 +++ app/src/main/res/layout/activity_main.xml | 49 + .../res/layout/activity_navigation__top.xml | 51 + app/src/main/res/layout/activity_protocol.xml | 562 +++++++ app/src/main/res/layout/activity_register.xml | 202 +++ .../main/res/layout/activity_splashscreen.xml | 308 +++- .../res/layout/activity_verify__o_t_p.xml | 199 +++ app/src/main/res/layout/app_file_browser.xml | 43 - .../main/res/layout/app_file_browser_item.xml | 35 - app/src/main/res/layout/content_main.xml | 24 + app/src/main/res/layout/device_list_empty.xml | 22 +- app/src/main/res/layout/device_list_row.xml | 22 +- app/src/main/res/layout/device_list_title.xml | 22 +- app/src/main/res/layout/drawer.xml | 22 +- app/src/main/res/layout/drawer_plugin.xml | 45 - .../res/layout/expandable_list_content.xml | 17 +- app/src/main/res/layout/feature_icon.xml | 24 +- .../main/res/layout/feature_uart_button.xml | 28 - .../res/layout/feature_uart_dialog_edit.xml | 100 -- .../layout/feature_uart_dialog_edit_icon.xml | 28 - .../feature_uart_dialog_new_configuration.xml | 61 - .../res/layout/feature_uart_dropdown_item.xml | 31 - .../layout/feature_uart_dropdown_title.xml | 41 - .../res/layout/fragment_device_selection.xml | 22 +- .../layout/fragment_feature_uart_control.xml | 95 -- .../res/layout/fragment_feature_uart_log.xml | 69 - app/src/main/res/layout/fragment_zip_info.xml | 37 - app/src/main/res/layout/head.xml | 97 ++ app/src/main/res/layout/item.xml | 122 ++ app/src/main/res/layout/log_item.xml | 40 - app/src/main/res/layout/toolbar.xml | 3 + app/src/main/res/layout/toolbar_w_spinner.xml | 40 - app/src/main/res/menu-port/uart_menu.xml | 37 - .../main/res/menu-port/uart_menu_config.xml | 36 - app/src/main/res/menu/gls_more.xml | 40 - app/src/main/res/menu/help.xml | 31 - app/src/main/res/menu/menu.xml | 29 + app/src/main/res/menu/searchmenu.xml | 12 + app/src/main/res/menu/settings_and_about.xml | 37 - app/src/main/res/menu/uart_menu.xml | 31 - app/src/main/res/menu/uart_menu_config.xml | 31 - .../res/menu/uart_menu_configurations.xml | 55 - .../res/mipmap-anydpi-v26/ic_launcher.xml | 24 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 24 +- app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3125 -> 2568 bytes .../mipmap-hdpi/ic_launcher_foreground.png | Bin 4450 -> 5394 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 5104 -> 4596 bytes .../main/res/mipmap-hdpi/ic_shortcut_dfu.png | Bin 2723 -> 0 bytes .../main/res/mipmap-hdpi/ic_shortcut_uart.png | Bin 2196 -> 0 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2095 -> 1608 bytes .../mipmap-mdpi/ic_launcher_foreground.png | Bin 2675 -> 2949 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 3134 -> 2677 bytes .../main/res/mipmap-mdpi/ic_shortcut_dfu.png | Bin 1552 -> 0 bytes .../main/res/mipmap-mdpi/ic_shortcut_uart.png | Bin 1236 -> 0 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4297 -> 3932 bytes .../mipmap-xhdpi/ic_launcher_foreground.png | Bin 6341 -> 8526 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 7251 -> 6921 bytes .../main/res/mipmap-xhdpi/ic_shortcut_dfu.png | Bin 3264 -> 0 bytes .../res/mipmap-xhdpi/ic_shortcut_uart.png | Bin 2609 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 6744 -> 6949 bytes .../mipmap-xxhdpi/ic_launcher_foreground.png | Bin 10833 -> 16588 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 11564 -> 11983 bytes .../res/mipmap-xxhdpi/ic_shortcut_dfu.png | Bin 5903 -> 0 bytes .../res/mipmap-xxhdpi/ic_shortcut_uart.png | Bin 4876 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9564 -> 10762 bytes .../mipmap-xxxhdpi/ic_launcher_foreground.png | Bin 16696 -> 26469 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 16746 -> 18512 bytes .../res/mipmap-xxxhdpi/ic_shortcut_dfu.png | Bin 8109 -> 0 bytes .../res/mipmap-xxxhdpi/ic_shortcut_uart.png | Bin 6623 -> 0 bytes .../ble_app_hrs_dfu_all_in_one_sdk_v9_0.zip | Bin 124276 -> 0 bytes .../res/raw/ble_app_hrs_dfu_s110_v7_1_0.hex | 1080 ------------- .../ble_app_hrs_dfu_s110_v7_1_0_ext_init.dat | Bin 16 -> 0 bytes .../ble_app_hrs_dfu_s110_v8_0_0_sdk_v8_0.zip | Bin 20630 -> 0 bytes .../ble_app_hrs_dfu_s110_v8_0_0_sdk_v9_0.zip | Bin 22309 -> 0 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 16 -> 0 bytes app/src/main/res/raw/dfu_mac_3_1.sh | 205 --- app/src/main/res/raw/dfu_win_3_1.bat | 253 --- app/src/main/res/raw/notification.mp3 | Bin 0 -> 98077 bytes app/src/main/res/raw/readme.txt | 58 - app/src/main/res/values-hdpi/dimens.xml | 16 + app/src/main/res/values-land/dimens.xml | 26 +- app/src/main/res/values-land/strings_bpm.xml | 26 - app/src/main/res/values-land/strings_cgms.xml | 27 - 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 - app/src/main/res/values-ldpi/dimens.xml | 16 + app/src/main/res/values-sw600dp/dimens.xml | 35 +- .../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 | 28 +- app/src/main/res/values-v21/dimens.xml | 22 +- app/src/main/res/values-v21/styles.xml | 21 - .../res/values-v21/styles_icon_button.xml | 43 +- app/src/main/res/values-xhdpi/dimens.xml | 16 + app/src/main/res/values-xxhdpi/dimens.xml | 16 + app/src/main/res/values-xxxhdpi/dimens.xml | 16 + app/src/main/res/values/attrs.xml | 22 +- app/src/main/res/values/color.xml | 64 +- app/src/main/res/values/dimens.xml | 39 +- .../res/values/ic_launcher_background.xml | 4 + app/src/main/res/values/strings.xml | 104 +- app/src/main/res/values/strings_bpm.xml | 48 - app/src/main/res/values/strings_cgms.xml | 36 - app/src/main/res/values/strings_csc.xml | 175 --- app/src/main/res/values/strings_dfu.xml | 131 -- app/src/main/res/values/strings_gls.xml | 184 --- app/src/main/res/values/strings_hrs.xml | 47 - app/src/main/res/values/strings_hts.xml | 54 - app/src/main/res/values/strings_proximity.xml | 49 - app/src/main/res/values/strings_rsc.xml | 72 - app/src/main/res/values/strings_template.xml | 49 +- app/src/main/res/values/strings_uart.xml | 76 - app/src/main/res/values/styles.xml | 63 +- .../main/res/values/styles_icon_button.xml | 43 +- app/src/main/res/xml-v23/settings_dfu.xml | 58 - app/src/main/res/xml-v25/shortcuts.xml | 58 +- app/src/main/res/xml/file_path.xml | 4 + app/src/main/res/xml/settings_csc.xml | 41 - app/src/main/res/xml/settings_dfu.xml | 58 - app/src/main/res/xml/settings_hts.xml | 34 - app/src/main/res/xml/settings_rsc.xml | 34 - app/src/main/res/xml/settings_template.xml | 22 +- build.gradle | 21 +- common/.gitignore | 2 - common/build.gradle | 31 - common/proguard-rules.pro | 17 - common/src/main/AndroidManifest.xml | 26 - .../nrftoolbox/utility/DebugLogger.java | 72 - .../nrftoolbox/wearable/common/Constants.java | 67 - common/src/main/res/values/strings.xml | 34 - gradle/wrapper/gradle-wrapper.properties | 4 +- settings.gradle | 13 +- wear/.gitignore | 2 - wear/build.gradle | 57 - wear/proguard-rules.pro | 17 - wear/src/main/AndroidManifest.xml | 83 - .../android/nrftoolbox/DeviceItemLayout.java | 121 -- .../android/nrftoolbox/DevicesAdapter.java | 217 --- .../android/nrftoolbox/ScannerActivity.java | 197 --- .../android/nrftoolbox/ble/BleManager.java | 1035 ------------- .../nrftoolbox/ble/BleManagerCallbacks.java | 113 -- .../android/nrftoolbox/ble/BleProfile.java | 184 --- .../android/nrftoolbox/ble/BleProfileApi.java | 443 ------ .../nrftoolbox/ble/BleProfileProvider.java | 36 - .../nrftoolbox/ble/BleProfileService.java | 388 ----- .../nrftoolbox/uart/UARTCommandsActivity.java | 277 ---- .../nrftoolbox/uart/UARTCommandsAdapter.java | 101 -- .../uart/UARTConfigurationItemLayout.java | 125 -- .../uart/UARTConfigurationsActivity.java | 234 --- .../uart/UARTConfigurationsAdapter.java | 88 -- .../android/nrftoolbox/uart/UARTProfile.java | 143 -- .../nrftoolbox/uart/domain/Command.java | 161 -- .../uart/domain/UartConfiguration.java | 105 -- .../nrftoolbox/wearable/ActionReceiver.java | 78 - .../wearable/MainWearableListenerService.java | 87 -- wear/src/main/res/color/item_background.xml | 28 - .../main/res/drawable-hdpi/ic_bluetooth.png | Bin 333 -> 0 bytes .../res/drawable-hdpi/ic_full_bluetooth.png | Bin 597 -> 0 bytes .../main/res/drawable-xhdpi/ic_bluetooth.png | Bin 340 -> 0 bytes .../res/drawable-xhdpi/ic_configurations.png | Bin 93 -> 0 bytes .../res/drawable-xhdpi/ic_full_bluetooth.png | Bin 1556 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_uart_1.png | Bin 520 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_uart_2.png | Bin 1259 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_uart_3.png | Bin 1386 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_uart_4.png | Bin 789 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_uart_5.png | Bin 1115 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_uart_6.png | Bin 1510 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_uart_7.png | Bin 914 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_uart_8.png | Bin 1738 -> 0 bytes .../src/main/res/drawable-xhdpi/ic_uart_9.png | Bin 1521 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_about.png | Bin 2971 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_down.png | Bin 586 -> 0 bytes .../res/drawable-xhdpi/ic_uart_forward.png | Bin 1063 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_left.png | Bin 564 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_pause.png | Bin 434 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_play.png | Bin 848 -> 0 bytes .../res/drawable-xhdpi/ic_uart_rewind.png | Bin 1073 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_right.png | Bin 536 -> 0 bytes .../res/drawable-xhdpi/ic_uart_settings.png | Bin 2452 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_stop.png | Bin 357 -> 0 bytes .../main/res/drawable-xhdpi/ic_uart_up.png | Bin 614 -> 0 bytes wear/src/main/res/drawable/ic_uart_action.xml | 45 - wear/src/main/res/layout/action_item.xml | 47 - .../main/res/layout/activity_grid_pager.xml | 41 - wear/src/main/res/layout/activity_list.xml | 42 - .../res/layout/activity_list_with_header.xml | 53 - .../main/res/layout/configuration_item.xml | 51 - wear/src/main/res/layout/device_item.xml | 62 - wear/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2419 -> 0 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 4609 -> 0 bytes wear/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 1588 -> 0 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 2800 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 3328 -> 0 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 6462 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 5249 -> 0 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 10436 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 7246 -> 0 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 15052 -> 0 bytes wear/src/main/res/values/colors.xml | 32 - wear/src/main/res/values/dimens.xml | 27 - wear/src/main/res/values/strings.xml | 42 - 584 files changed, 9906 insertions(+), 39860 deletions(-) delete mode 100644 README.md create mode 100644 app/google-services.json delete mode 100644 app/src/androidTest/java/no/nordicsemi/android/nrftoolbox/ApplicationTest.java create mode 100644 app/src/main/assets/fa-solid-900.ttf create mode 100644 app/src/main/assets/labels.txt create mode 100644 app/src/main/assets/model.tflite create mode 100644 app/src/main/ic_launcher-playstore.png delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/AppHelpFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/FeaturesActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/SplashscreenActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/app/ExpandableListActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSRecord.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSRecordsAdapter.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMService.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuInitiatorActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuService.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/NotificationActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/adapter/FileBrowserAppsAdapter.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/UploadCancelFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/ZipInfoFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/AboutDfuPreference.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/ExpandableRecordAdapter.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseRecord.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/LineGraphView.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/settings/SettingsActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/settings/SettingsFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/AlertLevelParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/BloodPressureMeasurementParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/BodySensorLocationParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CGMMeasurementParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CGMSpecificOpsControlPointParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CSCMeasurementParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/DateTimeParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/GlucoseMeasurementContextParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/GlucoseMeasurementParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/HeartRateMeasurementParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/IntermediateCuffPressureParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/RSCMeasurementParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/RecordAccessControlPointParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureMeasurementParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureTypeParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemplateParser.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/IDeviceLogger.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/DeviceAdapter.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/LinkLossFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/settings/SettingsActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/settings/SettingsFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ExtendedBluetoothDevice.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/template/Readme.txt delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateService.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/template/callback/TemplateCharacteristicCallback.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/template/settings/SettingsActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/template/settings/SettingsFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTButtonAdapter.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsAdapter.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTControlFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTInterface.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLocalLogContentProvider.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogAdapter.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTNewConfigurationDialogFragment.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/ConfigurationContract.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/DatabaseHelper.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/NameColumns.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/UndoColumns.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/Command.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/UartConfiguration.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/wearable/UARTConfigurationSynchronizer.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/FileHelper.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/ParserUtils.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/MainWearableListenerService.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ClosableSpinner.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/DividerItemDecoration.java delete mode 100644 app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ForegroundLinearLayout.java create mode 100644 app/src/main/java/no/spca/android/iisc/DebugLogger.java create mode 100644 app/src/main/java/no/spca/android/iisc/FeaturesActivity.java create mode 100644 app/src/main/java/no/spca/android/iisc/FontAwesome.java rename app/src/main/java/no/{nordicsemi/android/nrftoolbox/ToolboxApplication.java => spca/android/iisc/NotificationData.java} (56%) rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/PermissionRationaleFragment.java (52%) create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/About.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/AddTest.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/CreatePassword.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/CycleManager.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/CycleService.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/Datashow.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/FontAwesome.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/ForgetPassword.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/ForgetPasswordReset.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/GraphActivity.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/Interface/ItemClickListner.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/LoginScreen.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/MainActivity.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/Model/RegisterHelper.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/Model/Tests.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/NavigationTop.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/Register.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/SPCAManagerCallbacks.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/SpaceDecoration.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/TempDataShow.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/TemperatureManager.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/TemperatureService.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/TestViewHolder.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/VerifyOTP/VerifyOtp.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/VerifyOTP/VerifyOtpForgetPassword.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/callback/CycleCharacteristicCallback.java rename app/src/main/java/no/{nordicsemi/android/nrftoolbox/template/callback/TemplateDataCallback.java => spca/android/iisc/SPCA/callback/CycleDataCallback.java} (54%) create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/callback/TemperatureCharacteristicCallback.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/callback/TemperatureDataCallback.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/settings/SettingsActivity.java create mode 100644 app/src/main/java/no/spca/android/iisc/SPCA/settings/SettingsFragment.java create mode 100644 app/src/main/java/no/spca/android/iisc/SplashscreenActivity.java rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/adapter/AppAdapter.java (58%) create mode 100644 app/src/main/java/no/spca/android/iisc/app/ExpandableListActivity.java rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/battery/BatteryManager.java (80%) rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/battery/BatteryManagerCallbacks.java (82%) create mode 100644 app/src/main/java/no/spca/android/iisc/parser/CycleParser.java create mode 100644 app/src/main/java/no/spca/android/iisc/parser/TemperatureParser.java rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/profile/BleProfileActivity.java (51%) rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/profile/BleProfileExpandableListActivity.java (52%) rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/profile/BleProfileService.java (56%) rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/profile/BleProfileServiceReadyActivity.java (55%) rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/profile/LoggableBleManager.java (62%) rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/profile/multiconnect/BleMulticonnectProfileService.java (54%) rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java (54%) create mode 100644 app/src/main/java/no/spca/android/iisc/profile/multiconnect/IDeviceLogger.java rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/scanner/DeviceListAdapter.java (67%) create mode 100644 app/src/main/java/no/spca/android/iisc/scanner/ExtendedBluetoothDevice.java rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/scanner/ScannerFragment.java (60%) rename app/src/main/java/no/{nordicsemi/android/nrftoolbox => spca/android/iisc}/widget/ForegroundRelativeLayout.java (62%) create mode 100644 app/src/main/res/anim/button_animation.xml delete mode 100644 app/src/main/res/animator/click_animator.xml delete mode 100644 app/src/main/res/color/button_color.xml delete mode 100644 app/src/main/res/color/menu_text.xml delete mode 100644 app/src/main/res/drawable-hdpi/battery.png create mode 100644 app/src/main/res/drawable-hdpi/dst_logo.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_action_disconnect.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_bpm_feature.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_cgms_feature.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_csc_feature.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_dfu_feature.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_glucose_feature.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_help.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_hrs_feature.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_hts_feature.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_proximity_feature.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_rsc_feature.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_cgms.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_csc.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_hts.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_proximity.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_rsc.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_stat_notify_uart.png create mode 100644 app/src/main/res/drawable-hdpi/iisc_logo.png delete mode 100644 app/src/main/res/drawable-hdpi/proximity_lock_open.png delete mode 100644 app/src/main/res/drawable-hdpi/shadow_l.png delete mode 100644 app/src/main/res/drawable-hdpi/shadow_r.png create mode 100644 app/src/main/res/drawable-mdpi/dst_logo.png create mode 100644 app/src/main/res/drawable-mdpi/iisc_logo.png delete mode 100644 app/src/main/res/drawable-v21/ic_icon_button_background.xml delete mode 100644 app/src/main/res/drawable-v21/uart_button_activated.xml delete mode 100644 app/src/main/res/drawable-v21/uart_button_background.xml delete mode 100644 app/src/main/res/drawable-v21/uart_button_normal.xml delete mode 100644 app/src/main/res/drawable-xhdpi/app_drive.png delete mode 100644 app/src/main/res/drawable-xhdpi/app_file_manager.png delete mode 100644 app/src/main/res/drawable-xhdpi/app_google_play.png delete mode 100644 app/src/main/res/drawable-xhdpi/app_total_commander.png delete mode 100644 app/src/main/res/drawable-xhdpi/btn_default_focused_holo_light.9.png create mode 100644 app/src/main/res/drawable-xhdpi/dst_logo.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_action_disconnect.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_bpm_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_cgms_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_csc_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_dfu_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_glucose_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_help.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_hrs_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_hts_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_hts_feature_black.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_nrf_connect_feature_fg.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_proximity_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_rsc_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_cgms.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_csc.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_hts.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_proximity.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_rsc.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_stat_notify_uart.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_1.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_1_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_2.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_2_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_3.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_3_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_4.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_4_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_5.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_5_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_6.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_6_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_7.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_7_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_8.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_8_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_9.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_9_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_about.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_about_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_down.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_down_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_feature.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_forward.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_forward_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_left.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_left_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_pause.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_pause_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_play.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_play_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_rewind.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_rewind_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_right.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_right_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_settings.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_settings_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_stop.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_stop_small.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_up.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_uart_up_small.png create mode 100644 app/src/main/res/drawable-xhdpi/iisc_logo.png delete mode 100644 app/src/main/res/drawable-xhdpi/proximity_lock_open.png delete mode 100644 app/src/main/res/drawable-xhdpi/shadow_l.png delete mode 100644 app/src/main/res/drawable-xhdpi/shadow_r.png delete mode 100644 app/src/main/res/drawable-xhdpi/zip.png create mode 100644 app/src/main/res/drawable-xxhdpi/dst_logo.png create mode 100644 app/src/main/res/drawable-xxhdpi/gradient.xml delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_add_normal.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_add_pressed.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_clear_normal.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_clear_pressed.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_disconnect.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_download_normal.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_download_pressed.png create mode 100644 app/src/main/res/drawable-xxhdpi/iisc_logo.png create mode 100644 app/src/main/res/drawable-xxxhdpi/dst_logo.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_action_disconnect.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_battery_alert.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_battery_full.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_proximity_tag.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_stat_notify_proximity_find.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_stat_notify_proximity_silent.png create mode 100644 app/src/main/res/drawable-xxxhdpi/iisc_logo.png delete mode 100644 app/src/main/res/drawable/app_file_browser.xml create mode 100644 app/src/main/res/drawable/bg_circle.xml create mode 100644 app/src/main/res/drawable/buttonshape.xml delete mode 100644 app/src/main/res/drawable/ic_action_add.xml delete mode 100644 app/src/main/res/drawable/ic_action_download.xml delete mode 100644 app/src/main/res/drawable/ic_battery.xml delete mode 100644 app/src/main/res/drawable/ic_feature_small_bg.xml delete mode 100644 app/src/main/res/drawable/ic_feature_small_bg_n.xml delete mode 100644 app/src/main/res/drawable/ic_feature_small_bg_p.xml delete mode 100644 app/src/main/res/drawable/ic_nrf_connect_feature_small.xml delete mode 100644 app/src/main/res/drawable/nordic_logo.xml delete mode 100644 app/src/main/res/drawable/nordic_logo_horiz_white.xml delete mode 100644 app/src/main/res/drawable/start_edit_mode.xml delete mode 100644 app/src/main/res/drawable/stop_edit_mode.xml create mode 100644 app/src/main/res/drawable/text_back.xml delete mode 100644 app/src/main/res/drawable/uart_button.xml delete mode 100644 app/src/main/res/drawable/uart_button_background.xml delete mode 100644 app/src/main/res/drawable/uart_button_small.xml delete mode 100644 app/src/main/res/drawable/uart_dialog_button_background.xml create mode 100644 app/src/main/res/font/fontstyle.ttf delete mode 100644 app/src/main/res/layout-land/activity_feature_bpm.xml delete mode 100644 app/src/main/res/layout-land/activity_feature_cgms.xml delete mode 100644 app/src/main/res/layout-land/activity_feature_csc.xml delete mode 100644 app/src/main/res/layout-land/activity_feature_dfu.xml delete mode 100644 app/src/main/res/layout-land/activity_feature_gls.xml delete mode 100644 app/src/main/res/layout-land/activity_feature_hrs.xml delete mode 100644 app/src/main/res/layout-land/activity_feature_hts.xml delete mode 100644 app/src/main/res/layout-land/activity_feature_proximity.xml delete mode 100644 app/src/main/res/layout-land/activity_feature_rsc.xml delete mode 100644 app/src/main/res/layout-land/activity_feature_uart.xml delete mode 100644 app/src/main/res/layout-land/feature_uart_button.xml delete mode 100644 app/src/main/res/layout-land/fragment_feature_uart_control.xml delete mode 100644 app/src/main/res/layout-sw600dp-land/activity_feature_bpm.xml delete mode 100644 app/src/main/res/layout-sw600dp-land/activity_feature_csc.xml delete mode 100644 app/src/main/res/layout-sw600dp-land/activity_feature_dfu.xml delete mode 100644 app/src/main/res/layout-sw600dp-land/activity_feature_hrs.xml delete mode 100644 app/src/main/res/layout-sw600dp-land/feature_uart_button.xml delete mode 100644 app/src/main/res/layout-sw720dp-land/activity_feature_rsc.xml delete mode 100644 app/src/main/res/layout-v21/feature_icon.xml delete mode 100644 app/src/main/res/layout-v21/fragment_device_selection.xml create mode 100644 app/src/main/res/layout/activity_about.xml create mode 100644 app/src/main/res/layout/activity_create__password.xml delete mode 100644 app/src/main/res/layout/activity_feature_bpm.xml delete mode 100644 app/src/main/res/layout/activity_feature_cgms.xml delete mode 100644 app/src/main/res/layout/activity_feature_cgms_item.xml delete mode 100644 app/src/main/res/layout/activity_feature_csc.xml delete mode 100644 app/src/main/res/layout/activity_feature_dfu.xml delete mode 100644 app/src/main/res/layout/activity_feature_gls.xml delete mode 100644 app/src/main/res/layout/activity_feature_gls_item.xml delete mode 100644 app/src/main/res/layout/activity_feature_gls_subitem.xml delete mode 100644 app/src/main/res/layout/activity_feature_hrs.xml delete mode 100644 app/src/main/res/layout/activity_feature_hts.xml delete mode 100644 app/src/main/res/layout/activity_feature_proximity.xml delete mode 100644 app/src/main/res/layout/activity_feature_proximity_item.xml delete mode 100644 app/src/main/res/layout/activity_feature_rsc.xml delete mode 100644 app/src/main/res/layout/activity_feature_uart.xml create mode 100644 app/src/main/res/layout/activity_forget__password.xml create mode 100644 app/src/main/res/layout/activity_graph.xml create mode 100644 app/src/main/res/layout/activity_login__screen.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/activity_navigation__top.xml create mode 100644 app/src/main/res/layout/activity_protocol.xml create mode 100644 app/src/main/res/layout/activity_register.xml create mode 100644 app/src/main/res/layout/activity_verify__o_t_p.xml delete mode 100644 app/src/main/res/layout/app_file_browser.xml delete mode 100644 app/src/main/res/layout/app_file_browser_item.xml create mode 100644 app/src/main/res/layout/content_main.xml delete mode 100644 app/src/main/res/layout/drawer_plugin.xml delete mode 100644 app/src/main/res/layout/feature_uart_button.xml delete mode 100644 app/src/main/res/layout/feature_uart_dialog_edit.xml delete mode 100644 app/src/main/res/layout/feature_uart_dialog_edit_icon.xml delete mode 100644 app/src/main/res/layout/feature_uart_dialog_new_configuration.xml delete mode 100644 app/src/main/res/layout/feature_uart_dropdown_item.xml delete mode 100644 app/src/main/res/layout/feature_uart_dropdown_title.xml delete mode 100644 app/src/main/res/layout/fragment_feature_uart_control.xml delete mode 100644 app/src/main/res/layout/fragment_feature_uart_log.xml delete mode 100644 app/src/main/res/layout/fragment_zip_info.xml create mode 100644 app/src/main/res/layout/head.xml create mode 100644 app/src/main/res/layout/item.xml delete mode 100644 app/src/main/res/layout/log_item.xml delete mode 100644 app/src/main/res/layout/toolbar_w_spinner.xml delete mode 100644 app/src/main/res/menu-port/uart_menu.xml delete mode 100644 app/src/main/res/menu-port/uart_menu_config.xml delete mode 100644 app/src/main/res/menu/gls_more.xml delete mode 100644 app/src/main/res/menu/help.xml create mode 100644 app/src/main/res/menu/menu.xml create mode 100644 app/src/main/res/menu/searchmenu.xml delete mode 100644 app/src/main/res/menu/settings_and_about.xml delete mode 100644 app/src/main/res/menu/uart_menu.xml delete mode 100644 app/src/main/res/menu/uart_menu_config.xml delete mode 100644 app/src/main/res/menu/uart_menu_configurations.xml delete mode 100644 app/src/main/res/mipmap-hdpi/ic_shortcut_dfu.png delete mode 100644 app/src/main/res/mipmap-hdpi/ic_shortcut_uart.png delete mode 100644 app/src/main/res/mipmap-mdpi/ic_shortcut_dfu.png delete mode 100644 app/src/main/res/mipmap-mdpi/ic_shortcut_uart.png delete mode 100644 app/src/main/res/mipmap-xhdpi/ic_shortcut_dfu.png delete mode 100644 app/src/main/res/mipmap-xhdpi/ic_shortcut_uart.png delete mode 100644 app/src/main/res/mipmap-xxhdpi/ic_shortcut_dfu.png delete mode 100644 app/src/main/res/mipmap-xxhdpi/ic_shortcut_uart.png delete mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_shortcut_dfu.png delete mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_shortcut_uart.png delete mode 100644 app/src/main/res/raw/ble_app_hrs_dfu_all_in_one_sdk_v9_0.zip delete mode 100644 app/src/main/res/raw/ble_app_hrs_dfu_s110_v7_1_0.hex delete mode 100644 app/src/main/res/raw/ble_app_hrs_dfu_s110_v7_1_0_ext_init.dat delete mode 100644 app/src/main/res/raw/ble_app_hrs_dfu_s110_v8_0_0_sdk_v8_0.zip delete mode 100644 app/src/main/res/raw/ble_app_hrs_dfu_s110_v8_0_0_sdk_v9_0.zip delete mode 100644 app/src/main/res/raw/ble_app_hrs_s110_v6_0_0.hex delete mode 100644 app/src/main/res/raw/ble_app_hrs_s110_v7_0_0.hex delete mode 100644 app/src/main/res/raw/ble_app_rscs_s110_v6_0_0.hex delete mode 100644 app/src/main/res/raw/ble_app_rscs_s110_v7_0_0.hex delete mode 100644 app/src/main/res/raw/blinky_arm_s110_v7_0_0.hex delete mode 100644 app/src/main/res/raw/blinky_s110_v7_1_0.hex delete mode 100644 app/src/main/res/raw/blinky_s110_v7_1_0_ext_init.dat delete mode 100644 app/src/main/res/raw/dfu_mac_3_1.sh delete mode 100644 app/src/main/res/raw/dfu_win_3_1.bat create mode 100644 app/src/main/res/raw/notification.mp3 delete mode 100644 app/src/main/res/raw/readme.txt create mode 100644 app/src/main/res/values-hdpi/dimens.xml delete mode 100644 app/src/main/res/values-land/strings_bpm.xml delete mode 100644 app/src/main/res/values-land/strings_cgms.xml delete mode 100644 app/src/main/res/values-land/strings_csc.xml delete mode 100644 app/src/main/res/values-land/strings_dfu.xml delete mode 100644 app/src/main/res/values-land/strings_gls.xml delete mode 100644 app/src/main/res/values-land/strings_hrs.xml delete mode 100644 app/src/main/res/values-land/strings_hts.xml delete mode 100644 app/src/main/res/values-land/strings_proximity.xml delete mode 100644 app/src/main/res/values-land/strings_rsc.xml create mode 100644 app/src/main/res/values-ldpi/dimens.xml delete mode 100644 app/src/main/res/values-sw600dp/strings_bpm.xml delete mode 100644 app/src/main/res/values-sw600dp/strings_csc.xml delete mode 100644 app/src/main/res/values-sw600dp/strings_dfu.xml delete mode 100644 app/src/main/res/values-sw600dp/strings_gls.xml delete mode 100644 app/src/main/res/values-sw600dp/strings_hrs.xml delete mode 100644 app/src/main/res/values-sw600dp/strings_hts.xml delete mode 100644 app/src/main/res/values-sw600dp/strings_rsc.xml create mode 100644 app/src/main/res/values-xhdpi/dimens.xml create mode 100644 app/src/main/res/values-xxhdpi/dimens.xml create mode 100644 app/src/main/res/values-xxxhdpi/dimens.xml create mode 100644 app/src/main/res/values/ic_launcher_background.xml delete mode 100644 app/src/main/res/values/strings_bpm.xml delete mode 100644 app/src/main/res/values/strings_cgms.xml delete mode 100644 app/src/main/res/values/strings_csc.xml delete mode 100644 app/src/main/res/values/strings_dfu.xml delete mode 100644 app/src/main/res/values/strings_gls.xml delete mode 100644 app/src/main/res/values/strings_hrs.xml delete mode 100644 app/src/main/res/values/strings_hts.xml delete mode 100644 app/src/main/res/values/strings_proximity.xml delete mode 100644 app/src/main/res/values/strings_rsc.xml delete mode 100644 app/src/main/res/values/strings_uart.xml delete mode 100644 app/src/main/res/xml-v23/settings_dfu.xml create mode 100644 app/src/main/res/xml/file_path.xml delete mode 100644 app/src/main/res/xml/settings_csc.xml delete mode 100644 app/src/main/res/xml/settings_dfu.xml delete mode 100644 app/src/main/res/xml/settings_hts.xml delete mode 100644 app/src/main/res/xml/settings_rsc.xml delete mode 100644 common/.gitignore delete mode 100644 common/build.gradle delete mode 100644 common/proguard-rules.pro delete mode 100644 common/src/main/AndroidManifest.xml delete mode 100644 common/src/main/java/no/nordicsemi/android/nrftoolbox/utility/DebugLogger.java delete mode 100644 common/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/common/Constants.java delete mode 100644 common/src/main/res/values/strings.xml delete mode 100644 wear/.gitignore delete mode 100644 wear/build.gradle delete mode 100644 wear/proguard-rules.pro delete mode 100644 wear/src/main/AndroidManifest.xml delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/DeviceItemLayout.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/DevicesAdapter.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/ScannerActivity.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManager.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleManagerCallbacks.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfile.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileApi.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileProvider.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/ble/BleProfileService.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsActivity.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTCommandsAdapter.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationItemLayout.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsActivity.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsAdapter.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTProfile.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/Command.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/UartConfiguration.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/ActionReceiver.java delete mode 100644 wear/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/MainWearableListenerService.java delete mode 100644 wear/src/main/res/color/item_background.xml delete mode 100644 wear/src/main/res/drawable-hdpi/ic_bluetooth.png delete mode 100644 wear/src/main/res/drawable-hdpi/ic_full_bluetooth.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_bluetooth.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_configurations.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_full_bluetooth.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_1.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_2.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_3.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_4.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_5.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_6.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_7.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_8.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_9.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_about.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_down.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_forward.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_left.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_pause.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_play.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_rewind.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_right.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_settings.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_stop.png delete mode 100644 wear/src/main/res/drawable-xhdpi/ic_uart_up.png delete mode 100644 wear/src/main/res/drawable/ic_uart_action.xml delete mode 100644 wear/src/main/res/layout/action_item.xml delete mode 100644 wear/src/main/res/layout/activity_grid_pager.xml delete mode 100644 wear/src/main/res/layout/activity_list.xml delete mode 100644 wear/src/main/res/layout/activity_list_with_header.xml delete mode 100644 wear/src/main/res/layout/configuration_item.xml delete mode 100644 wear/src/main/res/layout/device_item.xml delete mode 100644 wear/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-hdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/mipmap-mdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-mdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-xhdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-xxhdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/mipmap-xxxhdpi/ic_launcher.png delete mode 100644 wear/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png delete mode 100644 wear/src/main/res/values/colors.xml delete mode 100644 wear/src/main/res/values/dimens.xml delete mode 100644 wear/src/main/res/values/strings.xml diff --git a/README.md b/README.md deleted file mode 100644 index 2eddce8..0000000 --- a/README.md +++ /dev/null @@ -1,134 +0,0 @@ -# nRF Toolbox - -The nRF Toolbox is a container app that stores your Nordic Semiconductor apps for Bluetooth Low Energy in one location. - -It contains applications demonstrating standard Bluetooth LE profiles: -* **Cycling Speed and Cadence**, -* **Running Speed and Cadence**, -* **Heart Rate Monitor**, -* **Blood Pressure Monitor**, -* **Health Thermometer Monitor**, -* **Glucose Monitor**, -* **Continuous Glucose Monitor**, -* **Proximity Monitor** - supports multiple connections. - -Since version 1.10.0 the *nRF Toolbox* also supports the **Nordic UART Service** which may be used for bidirectional text communication between devices. - -**Note:** To get a smaller version, with only the DFU profile, switch to the *only_dfu* branch (this branch is not maintained anymore, so you have to update it on your own). - -### How to import to Android Studio - -The production version of nRF Toolbox depends on [Android BLE Library](https://github.com/NordicSemiconductor/Android-BLE-Library/) version 1.2.0, which is available on jcenter. - -**Note:** It is recommended to use the *develop* branch of this project. The new version will soon replace the current one. It is using the BLE Library v2 which is now in alpha version. Its API and stability has been improved. - -You may also include the BLE Library as a module. Clone the library project to the same root folder. - -If you are having issue like [#40](https://github.com/NordicSemiconductor/Android-nRF-Toolbox/issues/40) or [#41](https://github.com/NordicSemiconductor/Android-nRF-Toolbox/issues/41), the correct folders structure should look like this: - -![Folders structure](resources/structure.png) - -If you prefer a different name for BLE library, update the [*settings.gradle*](https://github.com/NordicSemiconductor/Android-nRF-Toolbox/blob/master/settings.gradle) file. - -**Note:** The nRF Toolbox app on *develop* branch depends on [Android BLE Common Library](https://github.com/NordicSemiconductor/Android-BLE-Common-Library/), which depends on the BLE Library v2. - -*DFULibrary* folder is optional, as the library is downloaded from jcenter repository automatically. Clone it only when you want to modify the code (not recommended). - -If you get ["Missing Feature Watch" error](https://github.com/NordicSemiconductor/Android-nRF-Toolbox/issues/41#issuecomment-355291101), switch the configuration to 'app'. - -### BleManager and how to use it - -**Note:** This section applies only to BLE Library v.1.x. The API has changed in v.2.x of the library. - -The nRF Toolbox application is a reference design demonstrating how to use the BLE API on Android. The main class responsible for managing connection to a single device is called [BleManager](https://github.com/NordicSemiconductor/Android-BLE-Library/blob/master/ble/src/main/java/no/nordicsemi/android/ble/BleManager.java). Each of the profiles listed above is using this manager and overriding it to add some profile-related functionality. The BleManager sends events using the [BleManagerCallbacks](https://github.com/NordicSemiconductor/Android-BLE-Library/blob/master/ble/src/main/java/no/nordicsemi/android/ble/BleManagerCallbacks.java) interface, which should be implemented by your controller. A profile's BleManager should override the BleManager and implement required methods, that is: -* ```Deque initGatt(BluetoothGatt)``` - method that defines initialization queue -* ```boolean isRequiredServiceSupported(BluetoothGatt)``` - method that verifies if the connected device is supported by the profile -* ```void onDeviceDisconnected()``` - method that releases device's resources - -There are 4 different solutions how to use the manager shown in different profiles. The very basic approach is used by the BPM, HRM and GLS profiles. Each of those activities holds a static reference to the manager. Keeping the manager as a static object protects from disposing it when device orientation changes and the activities are being destroyed and recreated. However, this approach does not allow to keep the connections in background mode and therefore is not a solution that should be used in any final application. - -A better implementation may be found in CSC, RSC, HTM and CGM. The BleManager instance is maintained by the running service. The service is started in order to connect to a device and stopped when user decides to disconnect from it. When an activity is destroyed it unbinds from the service, but the service is still running, so the incoming data may continue to be handled. All device-related data are kept be the service and may be obtained by a new activity when it binds to it in order to be shown to the user. - -As a third, the Proximity profile allows to connect to multiple sensors at the same time. It uses a different service implementation but still the BleManager is used to manage each connection. If the [shouldAutoConnect()](hhttps://github.com/NordicSemiconductor/Android-BLE-Library/blob/master/ble/src/main/java/no/nordicsemi/android/ble/BleManager.java#L246) method returns true for a connection, the manager will try to reconnect automatically to the device if a link was lost. You will also be notified about a device that got away using ```onLinklossOccurred(BluetoothDevice)```. - -The BleMulticonnectProfileService implementation, used by Proximity profile, does not save addresses of connected devices. When the service is killed it will not be able to reconnect to them after it's restarted, so this feature has been disabled. Also, when user removes the nRF Toolbox app from Recents, the service will be killed and all devices will be disconnected automatically. To change this behaviour a service would have to either save the addresses and reconnect to devices after it has restarted (but then removing the app from Recents would cause disconnection and immediate reconnection as the service is then killed and moved to another process), or would have to be implemented in a way that is using another [process](https://developer.android.com/guide/topics/manifest/service-element.html#proc). Then, however, it is not possible to bind to such service and data must be exchanged using a [Messenger](https://developer.android.com/reference/android/app/Service.html#RemoteMessengerServiceSample). Such approach is not demonstrated in nRF Toolbox. - -At last, the BleManager can be accessed from a ViewModel (see [Architecture Components](https://developer.android.com/topic/libraries/architecture/index.html)). Check out the [Android nRF Blinky](https://github.com/NordicSemiconductor/Android-nRF-Blinky) app for sample code. - -### Nordic UART Service - -The UART profile allows for fast prototyping of devices. The service itself it very simple, having just 2 characteristics, one for sending data and one for receiving. The data may be any byte array but it is very often used with just text. Each UART configuration in the nRF Toolbox consists of 9 programmable buttons. Each of them, when pressed, will send the stored command to the device. You may export your configuration to XML and share between other devices. Swipe the screen to right to show the log with all events. - -Since nRF Toolbox version 1.16.0 the UART profile supports also Android Wear devices (watches). If you have an Android watch, the application will automatically be installed on it after you install or update the application on the phone. Before you start playing with the watch, please open the UART profile on the phone so it could share your configurations to all wearables. - -Android Wear 2.0 support has been added in nRF Toolbox version 2.2.2. Now, after installing the app on the phone, you will be notified on the watch to download the watch-APK onto the watch. The app on the watch is not standalone. UART configurations must be configured on the phone. - -The wearable application may work in 2 modes: as a remote control of the phone, or directly connected to a UART device. - -1. Connect your phone to the UART device. After few seconds you should get a notification on the watch that your device is now connected. Swipe it left to see Disconnect button (will send a message to the phone to terminate the connection with UART target) and Open button. Click the Open button to see a list of your UART configurations. Click one and see the list of active buttons. When pressed the button will send a message to the phone using Google Play Services and the phone will send the command to the target device. In this mode you may have more than one watch connected to the phone and use both as remote controls. - - ![Scenario 1](resources/scenario_1.png) - -2. Open the applications menu on Android Wear watch and click nRF Toolbox. The watch will now scan for all nearby Bluetooth Smart devices and show you them on a list. Select your UART device to connect to it. A list of your configurations will be shown, like in 1. As that was a direct connection from the watch to the UART target the phone, or any other watch will not be notified about it. - - ![Scenario 2](resources/scenario_2.png) - -### Device Firmware Update - -The **Device Firmware Update (DFU)** profile allows you to update the application, bootloader and/or the Soft Device image over-the-air (OTA). It is compatible with Nordic Semiconductor nRF5 devices that have the SoftDevice and DFU Bootloader flashed. From version 1.11.0 onward, the nRF Toolbox has allowed to send the init packet (required since SDK 7.0). More information about the init packet may be found here: [init packet handling](https://github.com/NordicSemiconductor/Android-nRF-Connect/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. -- **Secure DFU** is supported since nRF Toolbox 1.17.0. - -#### DFU Settings - -To open the DFU settings click the *Settings* button in the top toolbar when on DFU profile. - -**Packet receipt notification procedure** - This switch allows you to turn on and off the packet receipt notification procedure. During the DFU operation the phone sends 20-bytes size packets to the DFU target. It may be configured that once every N packets the phone stops sending and awaits for the Packet Receipt Notification from the device. This feature is required by Android to sync sending data with the remote device, as the callback `onCharacteristicWrite(...)` that follows calling method `gatt.writeCharacteristic(...)` is invoked when the packet is written to the outgoing queue, not when physically transmitted. With this procedure disabled it may happen that the outgoing buffer will be overloaded and the communication stops. The same error may happen when the N number is too big, about 300-400. The receipt notification ensures that the outgoing queue is empty and the DFU target received all packets successfully. - -*Note:* Android 6.0 and newer does not require this option to be enabled. The buffer overflow is now handled correctly and the upload speed is much higher with this option disabled. - -**Number of packets** - This field allows you to set the N number describe above. By default it is set to 12. Depending on the phone model, devices may send and receive different number of packets in each connection interval. Nexus 4, for instance, may send just 1 packet (and receive 3 notifications) while Nexus 5 or 6 send and receive up to 4 packets. By customizing this value you may check which value allows for the fastest transmission on your phone/tablet. - -**MBR size** - This value is used only to convert HEX files into BIN files. If your packet is already in the BIN format, this value is ignored. The data from addresses lower then this value are being skipped while converting HEX to BIN. This is to prevent from sending the MBR (Master Boot Record) part from the HEX file that contains the Soft Device. The compiled Soft Device contains data that starts at address 0x0000 and contains the MBR. It is followed by the jump to address 0x1000 (default MBR size) where the Soft Device firmware starts. Only the Soft Device part must be sent over DFU. - -**Keep bond information** - When upgrading the application on a bonded device the DFU bootloader may be configured to preserve some pages of the application's memory intact, so that the new application may read them. The new application must know the old data format in order to read them correctly. Our HRS DFU sample stores the Long Term Key (LTK) and the Service Attributes in two first pages. However, the DFU Bootloader, by default, clears the whole application's memory when the new application upload completes, and the bond information is lost. In order to configure the number of pages to be preserved set the **DFU_APP_DATA_RESERVED** value in the *dfu_types.h* file in the DFU bootloader code (line ~56). To preserve two pages the value should be set to 0x0800. When your DFU bootloader has been modified to keep the bond information after updating the application set the switch to ON. Otherwise the bond information will be removed from the phone. - -**External MCU DFU** - The DFU service from the library, when connected to a DFU target, will check whether it is in application or in DFU bootloader mode. For DFU implementations from SDK 7.0 or newer this is done by reading the value of DFU Version characteristic. If the returned value is equal to 0x0100 (major = 0, minor = 1) it means that we are in the application mode and jump to the bootloader mode is required. - -However, for DFU implementations from older SDKs, where there was no DFU Version characteristic, the service must guess. If this option is set to false (default) it will count number of device's services. If the count is equal to 3 (Generic Access, Generic Attribute, DFU Service) it will assume that it's in DFU mode. If greater than 3 - in app mode. - -This guessing may not be always correct. One situation may be when the nRF chip is used to flash update on an external MCU using DFU. The DFU procedure may be implemented in the application, which may (and usually does) have more services. In such case set the value of this property to true. - -### Dependencies - -nRF Toolbox depends on [Android BLE Library](https://github.com/NordicSemiconductor/Android-BLE-Library/) which has to be cloned into the same root folder as this app. If you prefer a different name, update the [*settings.gradle*](https://github.com/NordicSemiconductor/Android-BLE-Library/blob/master/settings.gradle) file. - -In order to compile the project the **DFU Library is required**. This project may be found here: https://github.com/NordicSemiconductor/Android-DFU-Library. -Since version 1.16.1 it is imported automatically from *jcenter* repository and no special configuration is needed. If you want to make some modifications in the DFU Library, please clone the DFU Library to the same root as nRF Toolbox is cloned and name the library's folder **DFULibrary**. Add the dfu module in Project Structure and edit *app/build.gradle* file and *settings.gradle* files as describe in them. - -The nRF Toolbox also uses the nRF Logger API library which may be found here: https://github.com/NordicSemiconductor/nRF-Logger-API. The library is included in dependencies in *build.gradle* file. 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 about the usage and permissions. - -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. -- Compatible with nRF5 devices running samples from the Nordic SDK and other devices implementing standard profiles. -- Development kits can be ordered from http://www.nordicsemi.com/eng/Buy-Online. -- The nRF51 or nRF52 SDKs and SoftDevices are available online at http://developer.nordicsemi.com. - -### Known problems -- Nexus 4 and Nexus 7 with Android 4.3 do not allow to unbind devices. -- Reconnection to bondable devices may not work on several tested phones. -- Nexus 4, 5 and 7 with Android 4.4 fails if reconnecting when Gatt Server is running. -- Reset of Bluetooth adapter may be required if other errors appear. - -### Known problems with DFU settings: -- Setting Package Receipt Notification to O (disabling) or less than ~400 may overflow the outgoing queue and hangs the Bluetooth adapter. Use values around 12 for better performance. diff --git a/app/build.gradle b/app/build.gradle index c3557e6..320161c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,28 +1,34 @@ apply plugin: 'com.android.application' +apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.google.firebase.crashlytics' + android { - compileSdkVersion 28 - buildToolsVersion "28.0.3" + compileSdkVersion 29 + buildToolsVersion "29.0.3" defaultConfig { - applicationId "no.nordicsemi.android.nrftoolbox" + applicationId "no.spca.android.iisc" minSdkVersion 18 - targetSdkVersion 28 - versionCode 69 - versionName "2.7.2" + targetSdkVersion 29 + versionCode 78 + versionName "2.9.0" resConfigs "en" + multiDexEnabled true + vectorDrawables.useSupportLibrary = true } buildTypes { debug { - minifyEnabled true - useProguard false + minifyEnabled false + shrinkResources false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } release { minifyEnabled true - useProguard true + shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } @@ -33,41 +39,70 @@ android { } dependencies { - implementation project(':common') implementation fileTree(dir: 'libs', include: ['*.jar']) - wearApp project(path: ':wear') + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' - // nRF Toolbox is using Play Service 10.2.0 in order to make the app working in China: - // https://developer.android.com/training/wearables/apps/creating-app-china.html - //noinspection GradleDependency implementation 'com.google.android.gms:play-services-wearable:10.2.0' - implementation 'androidx.appcompat:appcompat:1.1.0-alpha04' - implementation 'androidx.preference:preference:1.1.0-alpha04' - implementation 'com.google.android.material:material:1.1.0-alpha05' + implementation 'androidx.appcompat:appcompat:1.3.0-alpha01' + implementation 'androidx.preference:preference:1.1.1' + implementation 'de.hdodenhof:circleimageview:3.1.0' implementation 'no.nordicsemi.android:log:2.2.0' - implementation 'no.nordicsemi.android.support.v18:scanner:1.4.0' + implementation 'no.nordicsemi.android.support.v18:scanner:1.4.3' + implementation 'org.apache.poi:poi:4.0.0' + implementation 'org.apache.poi:poi-ooxml:4.0.0' + implementation 'com.android.support:multidex:1.0.1' + + implementation 'com.jjoe64:graphview:4.2.2' + + implementation 'no.nordicsemi.android:dfu:1.10.3' + + implementation 'androidx.appcompat:appcompat:1.1.0-alpha04' + + + implementation 'com.hbb20:ccp:2.4.0' + implementation 'androidx.preference:preference:1.1.0-alpha04' + implementation 'com.google.android.material:material:1.1.0-alpha05' + implementation 'com.google.android.material:material:1.1.0' + + implementation 'com.google.firebase:firebase-database:16.0.4' + + implementation 'androidx.appcompat:appcompat:1.1.0-alpha04' + + implementation 'com.google.firebase:firebase-auth:16.0.5' + + + implementation 'androidx.preference:preference:1.1.0-alpha04' + + implementation 'no.nordicsemi.android:log:2.2.0' + implementation 'com.chaos.view:pinview:1.4.3' + implementation "androidx.browser:browser:1.3.0" + + + implementation 'com.github.bumptech.glide:glide:4.11.0' + implementation 'com.firebaseui:firebase-ui-database:7.1.1' + + + implementation 'com.hbb20:ccp:2.4.0' + + implementation 'com.google.firebase:firebase-auth:20.0.1' + + implementation 'com.google.android.material:material:1.0.0' + + implementation 'com.github.PhilJay:MPAndroidChart:v2.0.9' + + implementation 'com.google.firebase:firebase-crashlytics:17.1.1' + + + + implementation 'com.google.firebase:firebase-storage:16.0.4' - // The DFU Library is imported automatically from jcenter: - implementation 'no.nordicsemi.android:dfu:1.9.0' - // if you desire to build the DFU Library, clone the - // https://github.com/NordicSemiconductor/Android-DFU-Library project into DFULibrary folder, - // add it as a module into the project structure and uncomment the following line - // (and also the according lines in the settings.gradle): - // implementation project(':dfu') - // Import the BLE Common Library. - // The BLE Common Library depends on BLE Library. It is enough to include the first one. implementation 'no.nordicsemi.android:ble-common:2.1.1' - // The BLE Common Library may be included from jcenter. If you want to modify the code, - // clone both projects from GitHub and replace the line above with the following - // (and also the according lines in the settings.gradle): - // implementation project(':ble-common') - + implementation('org.simpleframework:simple-xml:2.7.1') { exclude group: 'stax', module: 'stax-api' exclude group: 'xpp3', module: 'xpp3' } - implementation 'com.android.support:design:28.0.0' } \ No newline at end of file diff --git a/app/google-services.json b/app/google-services.json new file mode 100644 index 0000000..c74f56e --- /dev/null +++ b/app/google-services.json @@ -0,0 +1,48 @@ +{ + "project_info": { + "project_number": "373562439004", + "firebase_url": "https://spca-1133f-default-rtdb.firebaseio.com", + "project_id": "spca-1133f", + "storage_bucket": "spca-1133f.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:373562439004:android:10f9cf941182ebbdc8bd99", + "android_client_info": { + "package_name": "no.spca.android.iisc" + } + }, + "oauth_client": [ + { + "client_id": "373562439004-md3mf893e0m3mn45a9v3tdtlquqv09bg.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "no.spca.android.iisc", + "certificate_hash": "4dd609cfc14941b104eab9dd18d6a02dca970fb4" + } + }, + { + "client_id": "373562439004-hpejfuaulqq5kfes9n8s8uepcfio686q.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyCVnXHQZEvsXbuEPN9X_8dU_kZX3e_mUH4" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [ + { + "client_id": "373562439004-hpejfuaulqq5kfes9n8s8uepcfio686q.apps.googleusercontent.com", + "client_type": 3 + } + ] + } + } + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/app/src/androidTest/java/no/nordicsemi/android/nrftoolbox/ApplicationTest.java b/app/src/androidTest/java/no/nordicsemi/android/nrftoolbox/ApplicationTest.java deleted file mode 100644 index 5e6a0ca..0000000 --- a/app/src/androidTest/java/no/nordicsemi/android/nrftoolbox/ApplicationTest.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.Application; -import android.test.ApplicationTestCase; - -/** - * Testing 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 index 1ce41f7..db1f8fa 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,297 +1,126 @@ - - + - - - - - - - + + + + + + + + + + + + + + + - + - + + + - - - - + + + - - + - + + + - - + + - + - - - - - - + + - - - - - + - - - - - + + + + + - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + - - ---> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + \ No newline at end of file diff --git a/app/src/main/assets/fa-solid-900.ttf b/app/src/main/assets/fa-solid-900.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7c59512f3ca5c18cae924d6897512ff5734c32b8 GIT binary patch literal 203980 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

|)x3^jKapWz0B6g%no11O?0LpPnj{2^-|v zDN-mB-_QEQBoWZW@Xu=W8wLxq2jUCUSzV7rk<0syCr1Y(uvE@WU*kZ*<cakvf!f_JHb=^$J88 zvviYy7nu#eDzhunU)dQvd^otXQVj3Pl#LUm-km#pODBx-^Swuo^t!Gg&nLGYS7&2= zLqmPBS@rnVsPuy z-1VDXp8?Ip(MExyS;{a|o2i%e6ynmiYNk^(DcG4HoD(m#ti8nFc0S)(?)fwX+M*U!zic3_9)}z6(Utz$T-*UZu z^UVnEndi%8zQuA-5D*Qq4B115eTQ};Ch19x+eRG*jfnzbJi^d-h~(Ly1M3?A2c~Rj znOp9x=jQ=c=^4sa3onCes=!&WtKl$I;*UEB1j(nl&I?pG=@uz$o{i@UDN_F#pt#Q) z&p&UF#iaLdu~kCBU792>rPvn_i%&x)o}nBp95c>eDd$w z^a45v?KUdXf#%Kg-z`denROn#q*P{SW1`ksc|qn%6Qz{&>_iBO6!7;H1l;Rgb{{S6 zz@C^pKv7)p8wyVT zw3LnXMzD8@egL%s*(Jxj#ViuVMI;36Qh4qY=;?!zbO8i6_C{Hpr~TPnq~imo9=az4 z@bYtrD-t3X`NqxI@qxByk3*F*DsIt+oim zlR-A=hSMhG}iDgIU@_F&(T<)3x=s8eCzadY7YjXF}{d|6IG%FV87U+REp1=cq z!UH^hfLW_d^Th~a)l)S&faMtq{0~1I8c=YhlG>Qw30c8!ofiAHHX4e9%rUC%%ZNLY z`QV9#G0SPd8`+4*E2Uk%(f1tEmAS_0-3kIw`mH@;Yc3hfKJhAbCKfk?VJ8(W_RVF( zuB-wp8oi!|4)GA_nM(a2eJM&3W)dZdP(8BNGM_563!0We&R1oea+IZUvB=@M>XN!et7Yms^0%H-CnWv>$Y0x)um98E}D9%i2)t`)KW=9d1aGCXDA8 z_K0)vma_AUR>nFw#x9b3sCY0BnO4JvPLfA#UZ8j)Z-DFzq>y=Nj2$WWqI4+F=@f~+ zLEDJNurVgk>7pT$2*YSd!EL!8`<)ORI6ASsu(Y(WN{3}ONc?9CmOU{sA(mmwf`9K} zC*c>maI^k?2s~upz4xzsyXSM<@lN?`?_JGR{si>r_z$$gGBm5(p@BKpbvw5cTMeQV znBTxqaG3L2xDb{+=*ZlSC`)M6)&*#p)%2+{?6Bw=81FE@2>q2#iYq{6RFF6Z@S{8q zN4s93h?&De9G;mzJQzBu2d3@4BQuAu2IJ5>VFh9Da!NPv2~82kXaw{l$>w*`!@fi5 zs(CCJG)4^*0gAqUXgNLL|9Su9c)_wpRTT<=fI1o%VnlRZGc$7tZ=aqkr{7}_%^see zK5W!r*n$)XdN_?gctkv894aT@kV$qs2Nl@;Ek01q*A|spe_>oXfH#?VO<|r#~S^}%K=!~e5nV9Szms{rI5Du`D>+^-w5?B@83|ddl zEpX`zy16j-q!r|gr4%eJMLJbzuF&EXk6S_9PMJi&;RVX?bg4Vlq6j(C=W!CmrfPVlfh?K?7!qQ8!G87vT zD+x`fBU)FrhDDBdnD;#Zpks)JCKBh1laHz|gDwyN)7*Jl+*<$;kQ*<#dk+pn3^UvcJn>@twY=SNwtE35oCU6xye-HXXRHY<$ z`$65IiI_E_5Qy@{JP=kP+Zj-Md|)_92NE`yU`z|lGb4T$+%ZDaak_5TdY9wHtX@A& z*CRUv`y3-O6boQKpF@20Kx`;tIL&vx0U6KVaJYYvXJA{V5XwfjNtty2zCck6J`#w5 z#{_p73p^6kih)m`E-Om;G$upp6jzaVV-jA)TZzk+b`vdnotg~q=oxHrsA!1*py7tL zIYm@goE$$wqCSocLO4w$>?4Gbi5mPR$bt$zMsAm0vZ)fwJw=&fq}1E(vy83L#=c-y zPg*&6PFP7j8{F53ZZj-;3E;gKM{iM zEv-f3hb4|XfW7w`3EPr>_S&gef^Y!wP#n5mpM|KE!2&~!)OrlZYz@yn%rIuP^{B2y z2FM*44loigRK)aQaW#<7Xdsqxga}#3f#+s{_zp}aV@^0fN3%A!x9=nIdD>13K|NX4 z?NO?|HlJwzsziADpoYvb+tmK)j)OIDv8kGXxa)5&0aG* zbwGgvts4R7f>jVI*yc`o2-dpr6RGPLvWc{FSODi;-9M=u)8N8_S6-XS_tz9>& z>2T~GR@MBtW>~RMJRXW6ZPj?*rwsSYA)+~1WmzNHj;$Y`E6&d425#d_Z5YJW)*zy# zIZPadW1tgH+-76ChA~~BIKAuU?y_w|tWcuOnU}$tkPi(lV#~S_PE!EN>!P%#`g@H2jq-#AKNi^-aJ zIJv&d9lAf-BcO<0{4UYJcVl%E$qmQ?f?FyXX2{My3H-}^1}*@Bu=uaArwSc=tuK>6 zpfUj1LVwDJrTO;byTq0D+>bjqqaM%nrLjTM`R=~s+oursRm!%RU!XjhsFAY@!O3N} zq^sHV9wD(FdIVbshO@Bvs`XExhjLQIaYwh*$b`3nYqWtMlN# zEm2CUA+^xM&p`rl6ngYX&D-J=w8iDlI;Lywd;Qx6)R0hUSdyhgZ$XXHljxq?zXsN9 zx$6Md?S}q=KG--JvfVzOl*_JaP)w{@gr-qJNC~$Wla=+8GgRbmG++C`@pX%NV%KZs z2z2(ZuRG6k)0gQ>QtKNuLzlqPN80cWeIb6BqN<};jO;OM9C4*Jd&B`t$N)OY6(qDl ztEOY=!~WGo*ydoArl>Ms87f9Yygh=EPGF1SrX7c;X%7aYJSE%ld@>p|@B&oPhm;JKK6MBb0Nw#u+Xezu;#RTWsEdcOTaunT<-ZJ}MMJ&SI9Z;>)A&54Z9CYjmJZ3sg57+XF~7q@HqJPqt0sOb7GQs01KtG?B6tKw zSnf|qe3(E04w&*{H4-oBwMYEeH0QKXn!uyk<9(H&Wjdt&Be&&QuYryeul9QF#|5?i zoZFB#-lg1R5~9c^czBk81C|!S1iYQ`>u2POp}h{B%i|KSdaJ?fTONI*cxzo=Eaoyv za?mOH>qlsyj*Bq2qv5UA)NmIv$h7 z8q2}%JX#+jxx-NXXqe^skllg)eJ9$QMQb5!Lo6vQYXATj<;pF_xK_Vn8;>9mP|CK) z#%w#~IHT*XnjhJ$r584P)cxVkO`3~!kA+IKpHA^o5to*!@z&@PRqmP8cv4Y_?l8nt z-*#6&l2?))OS6kld{{$B30~00=Eqi9KEP4}u}I|$=OEPJF=Cw_=TyQYsEomibb0ufz1;{JzWATm}Ei!XFlwoF1z zqfTzA2$Z*c8s>=7FmaZQNXT`#OJf>u6>~=Ip}n^M%54I8YI&tW!Ql#5q*0{TMlTxs zrfq#5p--tDI6T`f%D{uozm(ZkuGIFHWn~cjj!d+IBlU%3$I=f`2mMeYc!4B`Fau-T zrZ!M-?}#bNf~e%1d9j9Ul*#hv9Oo?Zy_|IpSixzyK1=z4 z(m;EMyIuhruH8bAZkx2w<9Bec-cj!88FZ1JDK|kez=>A(8vbb{9!37pX|O`=@+#Lf z*SH22_lW2LXmN%wm-*gm$HQD~th8$mFm%C>4)C*XpV*#|W0sW&umTIPI2{xYB{72> zh}y~V$)2ar35YiloD7!yuyjEi=o-NP`T9-d5+L8X$~;tv_Yu8D!aII#1TSM$Bhd^- zz|}bbs6iv@sS;}AY^KPSh->9#+NI)!0+1H)2E>D_EZ`BNy@L&sWBb5|{c6S`MdNZ-W_CP$- zV=W&zC%(|XtvG{9O|uPKb8kF*?f_(Wp6$f>vcd5o&UGK@1`;;)w;5$**-;pYEAW73wF3=vK5 z@^dpU)1KqP-x{tYDrY!?JDV$j+%GqZ=M^t`+(*88X+!aGjx5UVV_-hF2@ zdgpE~de_d}(NQip8{1BtKw>LNXAs>;ZJB*Ztr-J~*JHCY#dzw< z)3W7(k&yw>)!W~X@U9!j>K6}^r1^soougsm%;m;u0i*TbPwu!NmajBSJXYsUY{N)l zXqX0)W5pcMFPJWu`?zu&Uc~pkZ~qVM*N;p6q368}C@W2X0NNm~!jVKX9E4jIm=dL$ zc42x}d>fWX$Xfz+?L|ZzTFUptV>x5vK`aH6fp^5C_eEnWqSXiCFdMw3XLvrI>xtKN zgdysQ_toe)j_r;z=g=02X9g+}xDIqZB0!N}Bl!pe1E75{j)Q)N`Fq(U;`Do!&emb) ziw|2dOUtU+@PAE*9zv;L=1~(#L;h$PVcTz{!njC_1_I_kmP))XoQOXaEX1_H$lszS z9r^SRaq`(^v+;>IUz2(cc;|E4hfZ^DlwU`L>PbJyA`=5qqE zG9Y^{k&*Pe)dqsiTmI|LRIR~5grc+3AJ%Lh4Z9F`mgS10sqFZBq02B%^S=v=n(u5d z5zr;6zdqe>Fb=v`|Ob(iWxKNms_01FS>`!rv zE~cD@t~q^&^>Asx*c-(1;&wfkiY#zL;!A-Zv-``jflxU5S-C*vVs&i^K`%cn79q7E zjtx6f`m{48Mhj1poKqsnTXd%AF8Oh#NK84c#(Io23vRevlu|+?J3U=Hp=&Tpp?JN@ zeIhVxL-lRzy{b8BDt%ETp2OuVbPH)=UuCMpVb~N6tL9a<5Q`u+hc*3YM6mu$*M^tT1(Y7-a3;{yw$KV*PV9!A+qByf%KfgVw{yan8_HV(i}FX z#dYrRg20HLTrae0KVoZsSU8pM*l&hHX37d?M)Y7h82nk!oKxWl;mwt!N_z78p!FOf z(*xH92yieCVj8AMer3SdGE@raMVikJxd{Ojrk^bSaM%U3r0 zh5LJS$EDZ2{(vlbNn`AJGLzR1aLtwba6LM3#~91WuQiSLnOAK0BE<1`j6-Q`8pjRe zy%5i$X)WH7B*w5w?BFo4cCmNZAyWLvfg-(GqaC+o1>fUzi<}V*%52e+Z~6LZRP1T@ zKaYK3as(hq=_l(6);IxHVd*e0yG$jKk{xPxVri~ep8P>A`T^u zx#sdN)iP>g8F{e9R}|IoH$R1HNH=M&C=Sdj$vj#Rj&+|cmmiX??Ci}H=W0~=+6(vbW)wgHodVC|x7H2(Ao4b1ujt%=Uq zgQ@lxL0u6s)xrm^sru>mD=v9&+n$HwOObYwYz*4Y)DlgTe?8va@Aq^Ho^P>OTpTYn z*9zl{U_V!vkyqw1RttQVkBBRIk(tSGo{UfP7_jpDJB0pSKHe`4@f*Nzvt9F~*#td< z1%|Mgv;sLGqC^59P>Cv=^2i6!GTb7dBQ%P}R`wfFJ37h=%$|&l5=c1B4@R?Uh6N3~ z?=&(=pRw?_3x+S5G49+AXBZhGHn=2PwN zI8{W_NyR#vIt-5yLs$zTY0nV6DJ-l(5Feq#IOxCdiDyzbr-WrKn_AU6X_?x!e4wjK zsy@5COmYp%-|%(p7cZ|kcnVKDfWc>dQ_|IBdFv#G-Xi`F(^O*i*Ke4gzhV9cmQBB{ zqkJY06Wr#by3-$o59E@*hNtFlxRHg}U+*Z3Pi7oIP1rqMuppmr?>ngx+m9i4+uBeL%MnjcBF^UI2*q5>TT)%NJDxL8R^Qn?2$jIe|X)8%%#)&-T`P z@Z&`9H3HdRlt@I;1GeJ$#;=N{VSwiMlhVQOhdEk0cGb9#_r;gkzJzSOv)CD38ic6h zXeimxRZ>Y#Z5VZRGmzH;ZUGP%`zdZg0_N7_xQ>`wBzgtK%L^za-mEB^@{pmuMf_}+ zW~aNg|C_oufphFC??iR3?yh|=sZ=VdRFY~hb*WUU>Q!C6+P#(CZM)re+lAXpd!>zy zZMIO@25i;_3^*hq1=(x}Nn;>@fl%PEC1J*c69QpL%}hcFGjU8pfG}7+|L;5ZN~-E^ z1M}wh-tTpn?sD$c)w$<<=i8S-bug0|%)D4vO!(#9C=^xn&#OIYzcvH4z8&0Rfc-JH z3H3jDji>SDr{3dFBW>VOu^HdW3_fMXb$snRL&F>#ps131@%wm}x$Sd^TPym$NkENNzM`Xpd>eG-R(I0sdbjz6cyy z!+J&@?-Zwg183m`sunAHsxd{PrrQ#O8ylqvD08|Gtm-6e>}>RN8z}mkjDYU>i<;vT z+bHNn$*b`1LmbR35(KGvVKz0@e4B+NVt^L}6RCg~-?ii8rVW3`QpvP5yWHDrBGsZ1 zj~mG5xT*QU4>oOcNVC1(OMLpVW4iAW6u8ueyyAV~fiUXEz(@~AKG?ifarw-fW{{x= z<#O*vy<6RC6pt2hZkU<*jA`iLZiu(^KqgpjuYa=ANxPV1g?1$q-C1>RY*hy<$kph! z!+nESr+eLPchB9u+rGr!dPD4>uCce@GknZm=P}tLTm0n}J`s2EQ-6a` z-u$aH9p;;9Sai@asdtFMX3&JyV-XcdJP1~SbVPD479t%1O~TesHG$>IB)tS=xUF!% z!X@V>_pRMgl)B^TEm+g==tlZA;HeaRD=Lj|gnP(K09(+j4R60Glt_fOjr+r4e=?Wq zP42#aH!dCKA-bKnsL$II7MC=AwpTGNzjn!uqV?+o3j?2~?+~S?Jy!4U-*i#$Xa;^; zks!)30bh-Cqcqqn2MGf;W zqK5gC@D<+fx!ZF;cngGdkWm+O0h;fM#9P}GVBj33;4*Lk#7t<}pj0BbiBkp0=sRSD zFT){3!HvB15Xes9KjdfIAa{2#38`cQ*nI}UQaGu>eGR56=wOi47wR1f8xh5PVM~t@ z4ub3Sjb^Ud0Tb4k8QM5(?>3V`#f%3AhI~;}n)e&2#Q3OfXj-CVCqr>NY$a_Y5)r4? z-EAR4r2B5G`vK#S$Ljb z@_!1S?2#k6{uG8An3@!wz-_-2IEqhO))f%3O!EpD3%>%Fq(@ZSOFQ#dgTmi1@f?!A zuCOe6j`@hHLVkOM1Tn5D4!(ct)t^Yl*@<&D3|9HQx279bm21EXZaQIe# z_@a{GwX7a95Ws~0B(Np=ibP@>O?JvSs9s}wZ7XG5s~zA2^Clr8spz0TqDTDxFg89q z@&RIcVqX229euMuro`0nvlI9_z7p{jZBr2uyBbOQkA;Fe@I!{zKH+_t-DBWKUanpz z4_;gLN6s|<_u%Q6{DKh41iVmc|7{3(MU2md~Z1LsyjD_LY+(Xp^+=!`Ov_^Y^EnR zQjVs5aep)&)S}<;Wqe0QH=1#TE1(+H4alYYL&dxCgOS)1LpS#HbS~|+ulQ7@hVYtf zAfAr;WBznBvjsx9#LdrxZY@E&$-}3NXx0@Z@qtkS&(uJcKX4lf!Xt=90ES7`C}mE4 zBkB+mTdPUSpv&QEB!v)3XSz-YMSN)!odR8L6XGKQ3v~zIp7Eo^h_(J4du=Um_4}iddi<(r!wMX^G^xbnoAA6PtMPfwdruEi z7O58rTk-h|K5@)!Qc_8N#IW$J24YP31es5f*fgR{Wl&}tFVWEx692IiGYR3;@hx!o z?RP^SA5v6syE}tYE{6uVRDAeks<2u!>M`IA;1tmrMM?D%KX&FiJtY*#Q4|h+uGy zhNzZwr4*1U6c3~xwq;Bdzf?w?F z{y-1)ehXz=H}`gJ@jf&Motl*W9Swx*-=s_-^CrSqNYcVf7%T|AO=R~@Pw$=n@Dp>v z>AY7>3?)==emdwVB{tyF^xoFDclH*9VTb~PidBMHmV+q9m_6s#j~Nh-oIyBh>n|{V zf_2l9(`TnM-XzaAO024GixYXdR7tl{o|Y3UM+W0ywCB|VRqf}Q-A0wh&`Wj;nW=f( z)j6Qqc!9Z-bLzsVOmInQNgX&q9tNzN=T`t_N)r%@ITnlSrV^*`;`jNGVw+Ez5KIRW zCZHCHNTW2(VLYLAN>p1<13-S>HKTHN6|Jo!*o zpz4WNNB+A~Vmlads>Pfai+@q7B6hc49sCOf?zB!$7IZ&wgQZ&HI|SU{5kPZ56+Q!= z=nIr^zZCr^@=yJzXjh*@$asl9ukT9ZoL5L79(3Ic5Kf?qH{73mr}N?ScU=@FQR9KS z@i=wk@o2UC1%}`mbK(BOYos&I|DW{vX6p0J|NrVU=SLp?Kkl;uZ8vNQuEhE)!9;0h z*DnJQSFw7B^yxVmJ~y*Kl= z!Q0_;j^z)_PNdGcN4CiC%Hxapp8t-ge?Z002l4w8y%{^=9Za?U6DjP)f+Ek-&2pDTOl;KOtX4;}!+Z~$U52wCjd@4H}kH@p{7{ga?mb>Cu z9N6nqAa@QuUI9Juf!1B(xsvpflqIu1Jq5Z@;aEI!sUXokg)<7+BaX35a=Z>b4(@`; z4mOf<)=VHWonrsNb>c$;JO%7XI1@hoVx;3<3cgg+gK&$OxMIuPr9!D{C}^!~eaHt^ zheGnn2X@0N6-jkUW6{FsO!lIiMh3k&)xC4OzQF5mIF(9YmKqyNUG~SCiqbgx=+-Tl zDas{t+sAa&%2Bnxq2W12sh38D_krW{xAiK>3J~u(IMG)h%SUh8JASZ7@y61ss`TDA zf4q-%MLegg&}&M5?i@Z2mI=%v99f9ax|+$;l!j|9x5Y&;Xj~n;p=XhzLe{}St@|m9 z**J4|*wFWg4_jdy7Udr%%MGtWW*;#L#QYlT)T@SM9c#qGS0@W_Y$V^sC3JI@I!h-z z{eSQOISOK-0X~gYG(Xb0n609o0sS`QZ0EPv=HPm@=dEr(z$7?6`{4g&gdH3h9CrLy zIxiu`GrR%Z;Jj&66#A9UY25k!uvyfj`p5`27uvUSFL+sxVr&+9u$Hks=tpw=s;=L7 zfxREskUd=27cYE3<0+skTM=Kx+WG^)09U)7#2S(bP88(wcQ61}5SV``_1OeWiIeJ` zk`!({iOgF|p=46Q#(p=D*ZbN11_$tfQsDfAZ=;QsBGNkTpqd1g2%wT7AqdF8J|Plr z9k~~H9b!LqOngH3dc#Jrfb!dV2&FAz+v)17k9?L`-&b=HTESXem@YG7~ofy#X_3a90f_ zRw~8t%@Ceo#7tbm)2LTaaO$f2JimX<^R&A2JUrutp2sN%wXfkbHq^+B)?W_to)LF#nBRC6>XFaEXdHR?*onP^?s&EShDL2< z!+d#X)mnFh*fhRp*0QuK?%Flzj{nPYzLD|5Txm@+!Dbj^{wKg|102sOEg>@$Vv3PQ zhoIA-cv5tl5RHsFX|HmXE>4r8kp0_m3#St zm-+{AjK2YEu$P^WKxeLdR5eZYQE9ru-2WVTaUaCYZvckn0buJWYk~>Jl5x)V>iVW~ z$J!d0g!tiOzT87(@_#7jd(3Ek*?)wxN*qBUE0Uj%`2YAZ48>y5UbKUY7`exc_y_#6 zLn}kG=v6GR5{R|?@gug0_EJ9z?l3Ui;l1Uc@cdO6=eIo;F?+;W31%DQPjVNoFpRFA zwSR0#{`gm5*o>9i2?i7=;;wp076hSQqD-S3hWk{eIFf6f&W#i^eIvPGvYZJQ zCPS7!gka=M8D+OdTK~*euqC0XXH-p?n`bwdxaE*K)C;1Y>m5>)#oS1&FH@c@q!Y^Q zP$*K)^uhN$Y;zCuPROOfs+3MV?_Qd{6@_A0EyIKzjGUiAxpRw zLJdUNN%u5Etb+eqB9R`QSpfs2G*9psfv1Lu5 zV)5qS-}7%>(d5-}`#m;3gK&;)im3_9da;T7aN7{;>KLmqwOLO>jaRP0q`s9C!7{)0z2JtY( zc^2VvXdpY!FsOb5-l#!LPy21fzq-%+)Mbaia0&m$C6A_VJ6_t`^7aGihe zl1Gy_BF@(5zXvN9InvJlo#)>$*FeFPkj4>%0j)CS;bRk6^p|6`T@Exbfsz|H=5UI$ zoIo}|qWPW!pglGIKA=QWd&1NO!hyxtb>IHz`iGH>fbV|}-v`MrVU-Yj#@yi+!Ct2| zu@O(ukWmyr+4>rS#P}JS-;V~_Bbozxk5#+01+r^(LwV4w7s}bcmP5%LB+}kmVn4Q$(9@y_M() z9I8Oa=@>No{Ou=yiF>-g>(~pHum-69x+5dG3vv^Bhb4*GbTzNA4qy-*+S3+`7NGsb zTKf}rYul@TRL38vH}U^*u^7*idti2&y~eJGPfQ#Nf1Yowy&7f5WEQ54&DTtRO}yM4 z-XFCOM6w%})=Y>yho8k9evY0EN16^Ol4-Lup^2|w@G-mFztuhVCj18xPk1()zx-J|Za!Uc?Asb%BH6nmf`Bvip&a#o-q{bH>q`H6XRp z1JTtaWyu2&o9FG+mFIMx#?+OQbChGFi+^;5V_FYbdLfu5%;}2JZZ(*m+HEm8GR@sj!%Y0xCxyRZ(2&w{+Jv&7ksOcy+sm+bb zHPBEpeG|R=>aEk8kIal*Ge355qNi_Y_Km3UvYq{Rx1)5+Ek56Ow85ENeczGIlNX0H z@BB4mgW=hs=*>nP6N1e0ak_`c?zYcwY^28p?LVW0HD2uq9%s|9h`qi(Dn=F3W>pdH^Wi7( z7-w8QNAfDF*vl15N*GEH1w4aJQX7#KN$~2^;^tQ!#q!j zU7bH+4RrL-1J=zuSyMAoJE-ahW~->MJUg^Z@)oSodFLbJ7iew-!7SO<36l}jNF^CZ zCb`**8xf-HxP&(n%tWu!z@K0V;I#kCe*CR9{kF*Z7t35JW|5=%%b;Wi4qWP3S{;gTh{T9GUo=r3 z-V9SR15;5$&<&X)Ow!)-kRVahxLNA$Ej7Q-qbN?{uvuEhc;K%gyzDh$tLD+w?i$jq zGrgtdQtw$0`%+(rC#=F+NwCH>0$wA&1o;4iS%Q19>^lf(ialNQilFt9g6A=-XMm}J z7ll6*TX@+!V``5U0~HXzttn9X`JexY--_D-@uI%S=AcnEV<%%b>@a*=ufTy>HG&VT z0S$gJ;)`}5?YCOb4wj~TkyBBvM~y8n(a^F!+p+hPpM*P??U8#S4~cFI{|A1tUH^Or zeX1??ZP2IR^W?!Bvs9c@K^{n&fakbcaX2^gj6XZQuzxC7E&38F++-8EiJ5_{|BNY= zN9{mpL0IYG`LVIf(#XBsKUMCF1vGIq6tEvP5WGTbJbd=k;yJ)Lb%D!W*qERnn9_9GK3qt zFI6LDKqncW8(Z-BvyWG-XlrNGs)#(4ZSaV)ECt?`-{4N~;4MT<#OA7Y)Vn2JwC=D{ z`|SuVBTb)>*Owo^_u!6DXve{O$w(N8=~-0c^Pzw{FMa6`T-R(dghG+N z*sDXhu6$Rj0ce~tsZHPoFXj^l{TTA=4B`zP)?y2&H7$8!cZgC9RB%?1swK3{)R#mP z8E#HzY@Fw} z+&;-V$4;iNzdqjSz;PdZ8-20?$p&)1er|c~@lFT0;Z|xu-U8yb3)~{{r1ZbaW0j2o zbEDiNXGyH+2HEJT)+2BTbm)k*h@M-@0yrZ4sR3JP*dyAxamo{Rs6|;#=)^a zpV)n!Iz4c3MA`N3iT7?htcQ#)$U#V#|X{)ZvJJ(nJAw=&X@ z+CL{z{wMfKg)zY~zI?{P3NVi2cjS89gm{s=Jg@M)1JJ?-a`0DeYbG-ZuJ0mC9tiq! zxy*Q~2u49NUEsaDSWj5~q;3Uar4`~k<#Reo5&0Z~6#{OY_`M5#|Kb5*8FM|R*#ka; zc5@ILQFk6JTsXWG4%5NM@gW;UirKom)39;rX?+GCnAy_aUz;Q(d@pWVkvA-r0>fwuc`?uVNoBWD$!{*T)k+HGJ@s62>xCdw6 zr5qIko=RaY^n*XGU^Pslrw!=Nw!uGb4_7Kb44>qykje1`DrVdYAD_G62kXj&%^ieul)$zwbVp2{?Qj!oIM_fNAo}Yo<}|d4ftC@D_zE(4p(^VTyfxG1vD^( z3>hA#w;jo>M$!S6MB#-OA=Pccyf4#MoI<_2i(6m67?tW!_1YXl9vRwo=35}CrKWxT z>zWpbRh_HYRUN;+CD6?hRh1lX~&NheeISi zYq1!LNGSeC4&B*W>50$vCdt`51m6Nf4pQu-8M#A*Tav2_7hCDRk#N!$v$+n5n~omb#1?r ztY)C~y+G44AZ(-H#sY7Tg8V$)^=iwOaVCHH#TQ?mKSQltS&_G`Rm3C!?Jad)#Ob5d zNu_|N4uf)c@nKPJPLH&P49I`x(SMXLile5 z@BnLP3I@*#gsl`@)M5r%bk47H7=^Oam z*q7BcxWV+LvZyGb>)B)T|pPh7ma?MqTFM+=Z*+h!KOtYSOto9mD71`Y}W582Teh!pN0Dq(CAOcil zf+z<4UowRqoK~=&W*V{uM~l!pKvlsOXzZbP&I~5MJzj?e|D(ZJ(&&qudy|?k6+pm9 ztjXs%$P*A!@CEkY>8+2IgW2N^*!1s@A(SNEXCx<6W*}v&$@l?z9w$6S$O`h70nc>L zX2{FrHCUlYZU7v>4aFhw*Z9g;8rc1ml_kNUTyE$NQX%m={EYH?=sied1S(NNB)At| zIEb(Y4gm;|4-O!leGw@@Ge!n1@_DM@0*MnT;Xx6zP+z$BwKH|qxE3+Po6~*0mt=*7 z;z&Ct{K>xe+WzkkcvXGV<){>>4tzgg|KsgyXlQUGkccQsDt}5fMDk)dc0EMOxk98b z=@;7r_J>C`zwqDQK!EP(6BgS~L>E8d(F&1*;%VXin=}p_>jqz<6>!}BBn_3yV71AZ zis(rS-6@ms;rJH8#j@c>-HPX`cMkm3?6xPiP4@h&?i=nKyi$+ob=|nB*k>igRvxrR z^YKaCvu*M<4=1C287(__6T;qc-<8F_O9p*u4GCdy7*1qH$M#$r-!wQW-V)h)Z5?Xr;I0QSjwb7(iEr45 z)o?L%qsKhgd2aDgK|02~q>aFez)E+Lx&i30R)F+K#Js@qdd-F_PRux(4)@&MyY1o~ znb_Kda6LflV5GaZf5VPO($DCkbB>3(MQ+7HEN~_n@8pdu{E$}NqewJH`%jqWqt5x> zKo-^=Y78mvH%lb@DiU^+Fnk)s7vj6>-hJ_a@}$`a*TT6KrZ zIp;jHh;%DTlWeMstySUK%~n^LlH-o9V@kl%LQWRpDQ8wPWmchpDf~X)c`0x2=sHF} znf@|QVF7Qzg;rEk;Cq3G&!q>gc)-30u^VP)QmbtvgIAyEPl7!Dh$I*LGcP8^=9=;&wG-lm>ZMg0A@VG)(m^$!&;PXR7IT*H zIrBw?!(!k#*ddU;f}o%T#Q_>yx$M?kKXB_UV@GBd7sbkf-`jZ2J@;I*@%LJ9u8+*# zeDmxG&+V$R2k+Gf`~w|aiLzp_CZ5!`j;KerJ;ZoUrQGZ>8boIVsv&w)8SM>M`UW=- zJYeXgD4!T_DuF&~X#JD|m5P^cM?{}LYWN?i9PdqR_>>)b=LBwBotWP`R){Ayy!8~l z-l_48$CH+S82&A7eoy)yAYTer!rHNB(~i3WQfstm$ws$En>-L^82Der-ff*cRqS|( zvF~^y^f1)_EmvLXq^LrFNIygTr|b{OBz45)A0R*e^Y?5$`f}0JjI(xQUEUIaYd~-t zBesv%zr_c-mN0iTct5wCJU5)}+*fNo+O?wP8h?UYTJL2W$jPoP<0i=A^uDC$se$9( z0crcHj%Kv%$P`FA0_U^W#{ji`~ary8rX8|(~9no>E1J9ztH{;GJ6*7Nhr zys8<|?%~+T=Xw!0uiNo-KT7Epy~#ij@$bFJ2a=0jbyX~>13Z@ ziNpqv&1P@~kttTtC(`kro|EBlxb-wPa@~EB>mw!r;gGva6q*k|h6WfTPW1^+uFU)# zm{{c1D0df0OvT6RrYUbG0SJGsi zN*ULWXTPrdmDb1E9q$9ns%eP$iTH_x5XdzCF(i(xM~0C+XwTTJsg30tQ0DLyC0kz? zgM0AE$JpP`k;NHyqP~*c&=;75oUT?+ zQ&;n}Iqb!cdB4cp!%pGGMZ&X@P(KXd0GWlP9L@m1X@@Xa4*erdDfeFF+dbJ` zRBUA~d5nfm9>*2!%^-C_`^&%1z2KYzmjv^?|fs-{{4bQJT zLJ}UtmAQ7Q=%>R14fn6qtrDab2Yy$HwcVuAtcRI_=Cu)&hls!5V9kCjDSXg$6x zmX=qTkC*5a;JoCbQ{dF@!zTX8zJ6QT3EUv-d{-FGs88HutS~Sju=r4TB`5DDF&{!{ zV}`vu=9hue|L4~XWAdIO=79dxVXLSa&*;XaSY}q0Htz*q0Hd0F#?Xq^;d>^H#u03c zuR%@V;>{(%c!B)mV)cT9x&hHL^8|3Z#7MlCHDo#?R?Ab_c&a6RpK0Fbe1M?ac5D~` zmPy!bVs6|Ibaz#{1shCP7cB_^D?vX42vl<6vj($l)Ot)9- zX-U^lquR|P_w5U7z{r)EmcTa^WgVb3vKCE!5V-?w^djdqd0u0 z52y-Ua>AXbZ*h)1Am|Q+49WJj2PIlKPTvo~5 zH|mvQLKf7jLPxZO&!eXKG-EosZ9NCN36aGU&yK}|*9Ti;%rJ?odAD@^*dntQq^_e6 zz1q6JD$_W8HGbPE=9y&4qmTNpKSl2=eHjUkeV8?}w;hB=r`uDj=4InNrVj4}#gu$Y zz?pX)w9%4>vpufJd%JE;bsWEH3V^+8n*GBQ*bVmgVav!tMs|qBGs4W|=+b6vj`F=u z3J+oRUa=u(nz{0PJXYFjnp=IX9|Eh8*KaeP1(p%>(YXTMF_s?LK93v5o|WPfd?9{* z_R|Pq{4;3(pmm5fVDEI?4am?$&bv@)x;krE-J##cbyb=J=M$kB_6yp0D?Pu|QQjh~iDc^|lAl}6X9&!*AkZ3IUbk@h9LUJ-e zT--Ip z?oeZoIL_}Bv#sl|G~z+y%JC^4jj66Zy>@M)_kj4r!ll{guQY;jE31b}mM_n}7w za!1NbgZWEyKg1LbXxg*84n2bBOP>W=H>Az0u$9^qbI<`V0Y{rcHs3%2eL#&D1m zVR+$nF?8tmitPOx{rT48rukDMad?`zBJaPG@<4QSkCbJ3>O5Q%r9xnJmrETgoE?Fi z8Z#3}k0_w#L=NgD+Ga9$zW2_|^$%Wi&4br0qy7Ra%?>CC_VJ1(+`>1CW~Mw|J9Our zhicYw?w=YOF2e|EL*|Dvg@D@x@FxSJppeg@7bPgIoDt+%F5 zAwTx4>U%Vg1kNJ=s85|$f`p_f-ftE9?PchosnR-}oj5KAxB>V9ByOuhVU|4N>$LA+ zD&r)R+%j9+z8~a7F(O%g?k;v{f-M4O2e}o?u;#^TUKD*xY)H;seEB`NwDym1)PJ1) zBx-Pc2@o|1UVFMh>5I7!(6W`gJ&XG}fgl`nnwHpA9-?2@RPUH?PT9D|srcrL7H@gi z+|!xt&+S;vR;NejPOtGMzO?@G%lB?1{D_YSy#5lR7ogp45Nt_q1yG3PULg7T{25r< z;%$NWo8@vQKRYCvL$i6ZGl=C(Igg^CsA~zlgk2ujNpOk`*z=Tr6h>V=p6+ zl|EB1iw$PVs4fr5iMrLn0fuL{=VV6@3HulpKRZ`5D+xfNoO@^kGKIGVIW&~PvBX`+0)R`&UVLhyBu^!9t88%wuTm80P z;Z~u>dTiaVn(B`UiOCAD`P}F>0NZW0-5ks1Ilc84#9$^-&|_ZG&*5n{3hqPf2vWF$#S5|$18)tVJp)a zz-WWvaA8^G57r}jBc|A6r%vUsnLn`I_TM^zGS;V)k;^h_Le0JE;ABRsSJUB58%j{5 z?wZ}#T%NyX)>QWzVP!BJx#Z-QhGp+Ms%=I_d&U~*3fo?{dzPRbA)5lG26V$wtGUWj z&P>gdg{hfR>M-EGJDP0$20=n&GC#5$iYZFme~`}aNx@gF=RP}Uy$l{Oi-uLsq=Nns zelB=1gjK*V_>Aosizvze&|K0;K!`wYTh0nHp#4&v5V6}+-b`vs!sknFPW5_wZr6h% z`-?mF#h3K#MIe0A?@wy+YtE=R9MK1d{w6neC58S%jh)uQ#8zp-s1AVfZw~bW76* zEn^101PZReDQEqq=X~oXCJde8ETj$h3MHbeNRci=-eAl}7qK?Z zz4|z!hV1s7#sXfYGpn6>C3yr84&Q7E#&}&;ME^pl5_=bB4{KrV@W+1fB(5|nW2bce z)L7-!7n(c?XM`sQNQVO+7NnYxPlXT-&<2~dSx-u4DcHQ-Vor_`0Jl(<7=}q;F3`LB z^jGIHmhqq;UY|GHAPUFSpcb&rvgu7`#9J~k`)0U*`X4l`%p6KEcyYlFXhHSZ-yRqk zg{XuC@~;m>{+95=Be&^V!1C3o)WUDZ0)HC`yq+!_r$z@3*i?m~=Ck0$f7>GgM)%-} zKchT=HB<650f!PDQidVC5Pe|2!8-tZP*4uDSz83JWk#V6LrYLd`8<*-8C+<>o28t2 z_$FV*SkMjMLjU%W%_Cxr4hyMIfZ+-i!qJ=Pvhc9#q8W%~%A0ZhjlPUNQ5}p`UQSsB zW=nLMO%;w3>-B3zf{2o?-J(d8<4_h#}s1rMew`T7)MD^4q*IaU{DvZ0cTelr0-2AAnEa6rt zR2BVE+ZfzF7TkH;{mRm%cieI5l5+oTI}=A}JT+%LrQIw8eK1zHTW!FN-i^8T)olvW zc2L4txCvnhA%n0lqfw+WXHgU2p&J8umq~>LPH;m>q#tt8gwvAJz#viOg2p3K6>vT8 z4r)GlI3~?rW!N^7J8WSgAj%s+u?uft6g6OCHQl%D(`!+~h>Qlj@CFNb1=1AQJCbnc z%JuaQ27F;QnTLIWVs9>IJpT{FO0U+F_GyBmDBQo+DSsL|mtC=m>+|XT$4wM!hzGBZ zhc@g@+#=crlhMN)z%F*&bN~;jA=WQZ}L`sBTY74@XGWBj?=l2S=z3^tzj{(10EZ2H?=_ zR$r+M7}LZO5JR(}T$COI8v;>gPb8B9pZ=lrfLDp6gUG)GyNaTOe51aj8<&i5-&j7@ z6S$da;&Q4-KuP1%R$1*34O~JmBo$1T1S{1{IUP*-p<>r8%^zu8qzvp&<|JeNaY~9r z{Eq;s1fByA`U&xQ=*morwg(q1xn4;+E8Ynd_9ZYO4<+JwKu|&J%g7b`(nD7TqdP6H z_>`eoyP|>rKzegc8Pn~7Tl;N&EMg=E4o$0tV+Hm8qc?{ASpbEZ)U(JI5epT2doAxp zem$Ag{TF4Msqz(@^e9}zTshH$@uzqsvH+832I(tN^FxXrB;?4;}gowtmo?_#U$}^#0@H7{O{!4>LG2;eP8rZt>;ohnY(zMOdL9m=XJC zp1#zxkj>&;c(93OJ|r9b<;#19_Hql;*j47~L(qwkH>QK90W6>)C3x)_aI*3?k3Ybo z&G84|S$+3q;nC3W)F!d`z;P%B5itJ1@#f`A)|Sc4NG{^gZ5k7|z8gKWNSa=P!g|MU z*j}X211F?ix^5 z3>sdHK0qEIGG&zEmx1<~GE^-bXVKt6`LK;i68=csj+eY5q}#soXN;((jlXH!PTR#h zWE{Te85j(5Dm}i3uP9ZIc`oDFcI( zaf5Ha$XZw@-Qua^4?OVX13SJT12Uz)^+|qzG(T|sn)xQ?8cuQ~GyW;tAd-^Dh0@Kn zNz3w+#9EdGtJ@)~X*#fHqXfI48>Bb2L4lXyf%Mk&0k45_gj3K6e8cdG{lWuhmF-IF zUQ-DurZ^URn6cX4Cy}sBiC-N)j+z6S_mhTC*@!}4zt%c6F~4p6HpQGUm21S#KnylQ z`hwI2$gvAYP{aNA(+E|O9L<(i5vwo-0~IWMX}2c-P2 zGFcev=@}|a#$Z%Uo_)rb*=~O#CZM=JQCBv%t$P z_B_Lb6hOaP9o1ym9?fe<2BkaM zOuf{9MdJxghd03!jVt^wUGsh^g4(q*HT>A<*Md|rE9FQl&a1gmy07;inA&_KR!FW? zf7-e~o;@Vr%8kywd2-8<&ArvKzXnsW-8dxm>4}d3p;O==`35^7S zNGh<-fOg58YQQXdY7(yvG7m{cVlgSgLM#W-Bc2n*?c5Bs$W%)v_-TmRmJy6DRC^{$ zIV_fG*a^sM+!5?Zw5P2z%nAV$3>k@YE8o${xS8&h1TW&qn7$G~y zNaGL!v0xQ4txHV{3C_k(npT%h$ABhkl>7+5q|-8;hHTunxRaH>g6Iba5H^8X2kA@c zWr^A1;-ef3`m|lP{kFZ?er~AP`aM7dcMK6v(NXU4DhG$o`|TOq-fxG;_V+mbQp$U| zvrd2R$GAvOt9w9eNjFa%0C78raK0<0Zx!o*+L-%%@|3I#16c4CogDpcRk-uT z9e4UnRD@J>SoRgLUzp8jxh7n(xIgQ?Qd0e)zY?_C<_ONd5v{HON>{t z$QHEOv$JcK0sWm7j6kMZHKl`_=;pJRqfa+SPd*5F0?+f19n&;XD=e*G+0rlI(rN>QnA z;{8FI^aiXel!!y@nnn^9n$|tjH>`|~Zs;?5`ie1{rLi6U>`j5#axC!M+Wu*Yh^O~! zH-4$s*H;?~_eOo_Ono@F=p^P;F$SOEH5$bj^uy*1jiH;`fprfvDTDGlxEKwtap%Ek zRb9Cw8qE$4M0~#bLi8@5&sW%_E`EzgCf^vd>@LiN1UurxMs%<_Sxy3JBsW_(c#E@z`o3zp_2a%; zzvyqh-{py1?%^f*nSKn+eBh7rb0z(|1h}_acByWev)quWGO|R zKbF5L0~~ck-uYOTDJT!u^KwburW~wGK&l^9KKsz@>_eCj{0Qte_lsqRZeHhkEk%m| z-=Li?zD*HcV@-hp@rr%kp^`y~GlX-x+H8={+DwgUX|xrXiTs2z=MW;U|gY@_!?4qk&yypO*%SK+_Sdch#-)TnB005mr%ry)gP&3rB>0% z)f@^OCOv$WbR$NsqJ#+_t{Rr1zXdMEHi~d9iOIr5>K^CpL0?|v8Dj064r*cqHU|z1 z@#WKdTOW*P`fRLzJC}(CHs5%9uY*9v6<)Qf=z2dMF={G>$)O6)a&Sl{t~?x*o{m^epxMymx%&dCc?kv93Wipz6vc9HN#<`V_1?uKd9P`{H~J>id@%YF z)4Vx?iVrstcOjmRv@W^Cw;LIqn2_gtOENcwcry%ZP4~0Nu{q79C7>GC{d@=d$oIiM zIsg^4Q>7d{I?yfLAP|p7zU5%h0j!YjQ%NNkj7I`*I-~)+9(aWjG7r5e5Qzuhg8ED#ihZhu;@1lze(Lk1oq%L=s|Dx+y-41Yz_E9 zAb!XQWCbY#*8mtu3Dv#=BEdliT-^~;1Ix@*LsB+Fewc>Qsb)YOO&l-ku|W=CGkXlH zaI4HNj@9&Tzt=Rq{sGfcOjEJUYyBZLrCL_ehM$w_D(3H>AUsWxpNdW-K>A(TpZYZpEeNf4sit5y8|n(! znA+45sGfkkkF+t8O;2cKfFe3TUn9y<7f**5QC4Ize5y;ODi2%BvD;4>7HiH?$2b1TpruW(FmKfKl`@3yC&%tI+d zQjVKX0h%LDk|0}4bqb*lDy|+uBTGCkZ4vqwI2?($zV}Y-TAtj=jpe;tK(PlDE^U`l4vr){aU)$*Atnhmf>x_o>40t^1Xwip69KBlvWyz=9oY1 z=!ZG?A^Wb7E(7yT3G!S#N>T(#6EY{y(QD=p-T5dBiHD{3P^RR$Y5to0ore}#EbP*y zf0}tv>16<@AsdY23@Kot8pRR<8X+vAlh8-<6sby_a9ssD`^5uWhE-qEuZ{_XIaSK? z_(d-Z_4&o!lZ8t9Vh-gJ$ha3?*nUIwln>To-+d?LZVM{NhAdG^K##eX!?gfYoi!B# z1#!8GHvK^SF)Lh+0=v*SY#fy3lF@J}ET2iHp#}98f_VNC3XQl|+uK^&t9d~%hO+8j zU$1^?6i3lZ^^AWn%-DIl6&r+VBFgb|pQEa55M1q1@X~J$C5g@?LvID{AGK}p@eryV zK0fT}aiEGS9wQ9AZFePV27iT$J8UwMy%U2DRfOB#nNUi#q{nBRVRqXUDDimtJ`}ZV zFAr-n82sbVQ0R~4?nB)67T)q;QYan%WQ*`PRbM6^j&4YPf-ilj^JP5a2i*1+-oB)3 zD_bOA4!(bxX*)&NPm)ZB_atmX^TYaYS3$qN`|fMF?P7_RZ)=6NH3n6dpktE8%dKo7 z;F0%-#8`X&!the3+25zk;^4ocgaEP(00-l4nWRxF)?E8C>9V8_Y%9@ z*23X8VX%<6ORBI=FP@5LzaL7s&d`r9pz;jkBZ**_ntk!shs9^rc(_%NO}G1^-hXD; zAsE3sdJwE97T6Q_967>K_O(ZlOlR(}iLN0$-5Iu(&LN%+13hrJ2EWV!oRCab1HV`c zDkQpspf))730%0K_<_TZc&1_(9=Oh|yyLpwJ-aq0=gEy-sHlkW5xsBNC`^o9dx>~Q z<)*nYv$7%6Z>st{d9VwwKk0j-e)otzFg{iw$43RS^QzJW9-Z|x@yjgmfm>za5Ij%? z-p$a7f$);qm)+dtB}TExh>G4!wao$Ivm1wVx%XT*L-B#f?o}cYt9N&{h#D*TVmTj= z6`|Kb@~)>dOC?m){%<7}l@#jK%asB4ekmbS4y>@2yg6 zDYN1D{>>$|uT1OeT5bekUVQX%wzXB#d$Gr`Opg7Luhmf?3)0AzG?egG1s0E4~w(EcBLO>}#!-GjKIE2dSJuJc}xaRATTqm%E_$vRLomm5Rr8=Ep*6_wN%2s7ZwKOsB^$vQy z^An}&4rSclF&KuZtwF8{Mnhq>GCaJgadBhQ@Nh*9hoT7L#x-3J5ALvAPpZXYX)u>4 zp^EIxV5wMCkxZ+U$USD7yC-*S8LL#rw(OYPZJHk|mjd)ess*M({*S!JpUL>&6M?ow z#lujJOwj_Ra_fh~fj}wI*PAK@0>iOh=HV&t`19g5;sFoR@iHTBXs+r8lSo665>Uam zz6zJ1plfi%8& zj7E^rdHQ-J*f4BOD1KBc6BDUa>zQCLLP7$8GoRytxl^<31x5P8s*X z%Rd+BQFpF(N6nFc!3un?$uQH0$pVssOxPFG--GP*^8Mv!?o9Wj# zHano&eBgK>_UTvlPZwKf;pms+D@k&Fqc!E^jfudX1*sM*oVi@m&NI_JV@wg4v1@bz z#m8aF0GuVo-|RkdV)rGx@hA7+nZ&<%AwDYh`;*b2F`C1dNGi7oqp3{<$c+JA5&Vlf_nUOeEyFYDGsr9`V3 zQ7n$iQQYo;Z0oDhsHnMse9VE^x2^@`Zum`-zXWG0>^zNea!^#xf!|b0OavUDJrf83 zdV7OAJHY#c4#fI-&f1+lpBob39DEsEt2 znxV9I;)IsYrL`i_*ySbux3aj{tHam5_uQ>xQ+YjTYu$4hUWvp=nLNE;8s#AMv)Zq- zPt{;!B>SgBD`0_i^#ra;9)2Q-CV{Ja5_xfrgz|E7N^x8`{2zgA>n72^YjyL)A`xl0$+SRAMv6wz)4|EEHl-z|DE7pg zOu@P{nVI!32aT8NwFmu#nJU!Ot@+*tsnTjnZXF_0FG?*_Qt&5+hBWp zig*u&cw*p7`5wQh{~njiyI?n4|0sKQ-tM$kxC@=}TLLd+!QV_~T-f9BY-mR`0}myM zl1f&BBh+w;GhiTGlQA8@)(lKeJHt(ZmWYCQl;>9vmjYGLBF!Q;CZgF+nXM&LR1wzp zG)2(kkK9F{$6Qn1EWr48@^m+CULB^ejHA3g$y=&6L%yKYf3i`pVy%))yboIc6UbJ3 zjyw^=Y-3%5kB}-b4v+*F;iLgr8|}ip1&jck6`&4_HC|M{T=y{sK)y5vKv|?kNv|0T zoQ7+k5e<%8hL$yuoyBjM!3g>vO`oUnIXM)|2;rkY3PMICpMZf^3LnHpBa?_fY=wF> zI1?j+z^nQU&4;_pu*gKu)10SE&Yv7E#?PNbE!QuRM@|WOb=_r6jxg|hX)6dROAD?4 zT7jHkfHIsr#qxFgK16T#lfzaZ9k6Q+I=O$}S7|3wmtqYE?CBnyJqO!!J`lSFc)<$n z;Nx>!c;3$b(L^U z5deD$Ki(vLGvIhhyat*Eii7k-Ng|qoPaEqRA?QJ}k$Ds$CQYT5SVAp*3&LutwA;2@ z&)OL~i4dtM_M*hi-;($IHCk{PS8)Y+*pVleSe_Up-S#>+j+!@t)XRy~fZ>2JcSs6EXvgYZszO zacet`;3?ZqlFR5w+HM3t432_wT+8)V>ZtF?o&+RC zD-?^*EzU@pKpOZ+**-bN=gb9?9w493W2BXU475#@lBWPdrwWs;?;|QCH4thx7n{wK z?(qs%CGKCv9#c_mJ;#diFifpYp1aBW=}W1jc%%h(TFEA?jV5RU=@in`g5s)m6_naE|@vMwa({j_aFt;eL_E zru991>-E00QMti@B3r+)f0Fmr{u_0#sT${;S8zY(f#~ZB+aHR^H0Eg}42B*8Wb*c8 z*yylAbWZtJu_H;Of~g{}MGg>NvtNF%!qJ1XNFU*R#C6_8f7&0}5BQppt^po?Gz=_xke>MkhRzMKe(dOlo}X`0pX6|~hr;O<)ASX# zix5vjI_~YT6wxm_`8zQfSm#*b=mT=k04WpOEfF#7f9zlAD)oV;q%AH2ytDwj!bwhb z5jNi+1h)aKycAqU@O(|OOUTFsJ=rSAE*KU;J;O|yLrpuTU7$#C70lw))f*>pW%#8g92 z%7aDMg=foD>)!|O zd}Y3t9lZ0w)G773ac+P@=wYHi8IqjaP56meg7QMY>#tg09~8c+ zEr;%0$>(28`@vUo@YG6w5315Dx-S$=hrLLm5rTa8BjB^UG4>ha>fqJ`oe5&v8|CTM-Z3zyUDuLoS5{Tcf9I`l07 zTX_lmM7`FgaH!=V6Q}?bxO)-0hJi)KT%aS$)YKIJ%Z|pLUx`J1mst_ zEl`F6J)nWN&M`W|m#|sr9G>YMq8}uaN|=-NHe#MLo{s|NQb>eNe>hNxO~hK(W~M0} z1K4nKlyJ$Vb52T5L?^5-XSDv@$pzoe5r2Vm(q-ef5dQ|&zKdk9JMZ)b*(p=Tr^m;~ z--{3ZyG4Tdrxc~nN$)-}fTTOf*Aj7eoKhz;AXD%-Ipy{2xV%kk-zL9Qa5C-uUwqo5 z=;lA;vlE|>;Un(kh4pr??sZet|G(E6%Ci4U3{(yM?1EjY$8rE`hWL^WRqH;&L^^39 zC7YP4Kmmm`oN|!^lyQ^=0yXx-ss*fvmsXZ&sRv^2Rl4(^ ztiWMj5Hfc}_;A3Qu-F2=U|G#3+(c+8E_QAKe@HrCinqX;XL}Co?nydw^|@Vod#aY+ zQ0~=L@0>TF&6y#&_(SF#+?nQ(sQ#(Yw*A{eV$mDWUjo0TEWD#y^ph>iQnPS-dWjzJ zE+#UW1eP3+-)F=Q{I&u9`Xb0nEG{MEK+)U_H}W?~LBRC44Rnf^!d|~T~ogBm4TEV2wWWU&!-1A`&3^LL^kaY z=7S)4DDNgl2Ks(|+8!J5Tbr#I^7C5EV@Ui)*;LNaauk>s0Gg+0Q8)FO_^Pxil98Vh za0001&`=ZUskQS8Nq?D#@MFkhg+xIhi3_tyRU<3Md+rwU|@LsxDDU5o!ZG)5MY2nsyZSOdth+k1KWCx zqASZ~FD3{-pr+ri_zYDSxW#AqG%tNC$a*9xA2b0!1C$L3V@Xg;WNC{cHM-6jt4E<7 zi?yW#Njqe?^Ri*FD33ifmME-9drBG#8p_%%Bg~N<-atwO?SS28 z1*1cdf$O5X;@BUg zFqP1q*kOdtGIWTo=D1&}R22XC<*IFB4TJ`8ZjO(e6=lB&p+uo6eqzIX5c0L29Bwp* z#qP`prNe(~H4uvipWBe=8_o~+C30G{n8=MNeZw2xo!BruoEtHy^=A^W5io0Q8X<6ZV!gh*1Qig8#@aQk0I& zbQR##0GC^vq5BBN^m1hagb&;fg>J$162QiH;Z6?KWo30L=cTx>|ION)z{ho#_riM5 zzRk>;IWuQA&8E>TTC8m(jcm#Gc!}+JRczzffh0pPu}MgxB!ndmL=CyYP*TG3C4m;I z3xzKfC9&$~YF zv;H463?4(9g_Wu|euW7r?%S zto=s6rKfbO-w@%LEvTX{x_~c>U;)H37?FVukk$kv>L!eY3)iZI3xsA(G#TZ8m>i0s5DU3W&3iV_wvm>@6*n&mKJw7HEA1pK1A za7U7p+Kl|W8Yi9$ZUQlePm*L%?j@W zHqSHb7df3@WnTtn!6f7F692if3==nvgA_fdZrUNMm35BV_Ta`n;_rp4GO?J|Ki2Hp}-|3#w5q!<- z+jSrd|Lb1!`3g1;YwepX0xdH&vZv0)8Qcx6Lf}v5!?1)ch3mCZ%3{a~IU1Q4wFf@? zKxfsnWNhUM=M_Gt9^u=iyZI?(ATkz>@CVEY9>mk$7Un#DdIE`h1}5gX7O``lFTvOM zj3q<~hKk-7hRlaMM=ceqes`Ix{i z5lb8(sc-`JFuDK=DZr@x6J1}pTGuUER3%jqD|JZZ^@=FqNR$C`fAxZ{7f1U?Oi@<_ zW)2)Hm0Z9ZNs^whL#1N_CJ@``L35;k(@EKp3obk%WM*ZdO=v(_e++wNe;=)#}Pum$+9j;1Q~`4-%@d7 z9CxZqC#mMn9VEH@tmq=RW)0C^(XiCB7p_=P0VPDqkH(exAnP@01MgrLxf{?uq~ zgYp(*i%1r$Bf9<>MAy%K(6plL_NZlkaCPDM@r8PM(20|^ATt`8j_miN?O*#rE1$PM z_*!-WAOIJIy^7U_2>ZmP}mCtFYqH+dHk>k8-NeCf38gK-&&y zL)cdHb;pmt&V(k6-+)c0C*slb9sFHEVPAq>!uLVtQRQHpv2u8SJl(iQn9v1XEQY|= z8t8pkM|B3B>Q%MjL&Nzdg#m?o4?7>@6Q{wqpWxd+7_MDa#WN~GWSaSrgN9k`?>+H* ze40GWw{PcL&d2^P{LG&6vp^#oz!l32exVU}1Mc~f;y$Z5<@hDVtq!yOGy6M#aYnZFs9=P+;qI$HS>#0+O%LV%pbiC?1unbB~4 ztV=adO-?5g$>*_80l~PpYd{OI>*>*6vnmXpYa0H(M;cjAdw$6eQeg5?j7@MmVeJPh zqmYBV1oYoN-#Y5OYJKa$3r%1myoTSmLH;RWhCvG*$Uhj<+aU9R+XN6QR5#Ty;YcWX zD5HJTJmvNPTitVsbS~SNC-pp@Q=_ul-!DU;F{GS-1hS{Sgey6}-Vf_>MC-l4_kD3^ zn|~E-y29l3dnM%~T<`hr?t}hIBd=|yUS->OXvObkq_M9s)VoM+@GPgQ1LZK^D+&NfGnW)Hq-a(Zg-EQBsu z-CIhEB2ba^aD2A~!evdDCmMpVt30szbU_RCE7JeVXU*C67Q{m(Z;ZZfXlv2=r6j^G zr7idM4?xC83d=<7m97Vk;hq`{oqUDW91p1xDfFZ_!8sWu-5-PhL<7j$SQjuJRSYf~ zT1v3PF)HZ{u~8I!jgUwV8BQ2~1Z)d2f)-JbFrr^Xt`l(lV;{YSVk4#(uvs8K$bA#r zj&5=`H*c3@UD8GMXD9AW)H1J>5j(F7>eZRliF@a6WP5U(SH_Ar)69ESL^w;oXNAbC z==bL0*h+qr8xoAYq8h?mCQ6&TKD?h88)#fRH~I09BgE<{DICF~L|JBN$tOK`Q1=?*s4i1)XBK3&OItCHL9nKpm#@k} zO*4`E8f*U!Q`6dVSpLXm%Gr6p8egPJEXLKgEVH9tad=sf=ZrG9B)KI5E^vHK@yI3O z`DZA{Y7*$3WVhssK+k;0m6Wi#DhaksId*PRKVw;KHQs801N#nqJG+gIhCdIYz6bTc zN&O;jq7t{LwD+m{Ihs(^lGuU%GH4%8<0!8ltRp>^_MkI+vjBN&Qgk}zJ%|HE5Y97u zX$iFj#@NR6Kg*~+FXb|_?5wnSvwdn~{-1Na8U0c+&C4Nya`}BG_F3RVXddr`^wLL} ztvy{Y$Wd>pyhggx0PbCMyZ!8q;u%(41$N5Da#Lx2HzPh|S)X^LdtN6H4Od&O$2L~v z;^FDLI9#Anz`4c^^N{i^RiQh(&7;12$~<>{dgf-rAxvSeM#Nyjl>G%eIMnB3I{JcW2@j5 z$nMz74q;?oY_Gu}rKW{gK{?p@Oxr-1fb^Izl`2_2S8dqv=JNpTz{xx|CjFRRdYG?z zb8bCH6wh1r6mBWSs@aO~vNn7~L{BMGvxQcYdO>(`z z%uH7kq^G+a(apoheRhhH1@ZcjfvoI71(7)SmrC5iZ1anW1_Qp%}maD3dRywa|7dtj;U;5AWUmzMp9c{xFf0=S6d;h=B00 z5vo65KM;5rP@E0D6i`}D$v6?YIAa&@jTKI7K@)jzF8;)$xsdy~3{3fg;TyekbdkRUn~{)ILRw z(f_<$%h#7l4`jDe_dmZ9D%=*u*ymw`-UQD5MZk=GYac~{CAgjhdJ%x|Kw>6^2Zkjb z0%HJCy)HJU)O^8)3h z#*mlFRlJ5ABgzw8gNN57;mG%6I207*Si}^djTza-EGEI$ZV4tENT%UMkFWF}4iJ3CLY(RaWyz$^|OkrWufYF1oYc|JhJt~`eip7+$VW1;TLo!GaDA{q@$`4fQ ziIWSP86y6f5n_7}yu7e&cH$4i#$C6^68g(-HQH=p_|O4K*O*`%d-o-ate7}-P&Xyp z*mL#JLI!HC^4PWo(Yv9!dHbZch26T}5NBsJ6wx;3HaCyJN5P0k1^M3oQD9H&wWJY+ zrdrlcXmRL?qW!L|vxUt^Q?M9EjKt0R_A@(2pqIdCg{;|PZTQ=ByB3@rNgAnwZG|QW ztyw_q3Ky)r=mxfT;>E3cz4hXWZA;aYdR$1Sg}8BTb?MDcBmy2>6`$M0qu`QGYLNY*X2S^bs#xKoMgN)>q~j; zFjrZAoNuFl{8mVJi-2VwUicjF@of76+8zEWz8d`fF_-^PEIMB-p5-^A4QP#6FAtTb zD{FSY?UL^d=kFC4gfS=sf8$%pj^<>Z&_hh#ns@30A`9u0(?eXi@}RtA)k=R2< zL@XCg5>N5x>1au0qa(h4@ar>Pv#`g3@)d3dj_L`R^(>@DM@DrO zXzz%ju|!*dt;S5)*>JL`t2qbhP2x7*;!0v#0@wx;Rw@yQsv*%?27q{!N%$ zXkfrtxqd_K2jV|`wk21wk=#@(hyto3h%l(ac8g4t5Of8YQ6)t&WYf%9RzyqfEv9wN zV3BC7VC!ZG)HI5glf@fzLL#I{4xo!AHq$O9!u)d7?vX{dbxmNmS)_r**w zVc@q4d#fQ!#~{|Dx>E%Bdcnv-EQWKacv_2?gwPVMD4H6g zO(H6^0)E?}IYmi3Y)Fcri&f*EW05G{%%n|V#GzK_Z@xLDNHBs}o9BAWC-Py4}w1YZK*CNdk)K%B)Xc${qf z4d@Y_hknSLmg zjelqPi{7r)oeFNPUqnASUlfc2$yZSYs;W5YuCOG-C_*j?{_uYR|IjD+wtY&)z#D&j zTrq&7>6aIL87mN(>2aUjwnYvm=87f+h@4=w_U1cV_=KZT#RbP(N>|wECT7Qxuy?XF;53oFRT-C>Ab_Y28XHQg4-U zw6V(Gh}zg!X>bF;3Jv-S3Bl1x=qn5<&~R)vc233jw*j*NHWjxvz3#eB4%>S)AudJj za0;#q;mpf6_Dsjc{hOwPRJ3hUYB$@3&rYnEh0~NCp*vdl)O*j_C&_VRuZ0f z3-Gf6avc1AFlUMTQxz~Hn7CYtISanSg}mTRTonndpc7YItfjm^#sxGv7iLNGk8Tpk z6N;3e_yZZ3W$ywpHtq0mE*$OrH*bF^AC9v7OR1swYo6GP3d4E%~A7}GL~ zU(ezK6yvJQPyE$DIw{Ab~MYvuYS6_%K+uO_leiUhtkDp0a>!T z`}G$phL9BEOrAD`XYhsVWL0APM0?=HgDTTTZ%tzPj`VNn$0E?S_pbM2(zAP@_DPrb zCgs!sKX=iHob^sanjtGmaJSdBH_D=j;0{$T6eNu)NTMT`Bj5=ldp7oLt$U%o{)CJe z6n~7`@S97Qu|!6rf+CgE@Fkavl2q*c@1FktVsKX8csCyhUqSrkr$J+q(9P}XJ3)R0 z2q1f(C-^yc+} zAROZzXfQ?IcbAo7LhCf@sXV0MByeK}8djMOn zf&u8QBm`gt+g|GVuWq3%Ok8pv6Yxlb^JU=Awh0&?r}pW?inkVH0a1qaeW!k{XQ772 zIpPJRYBrRN8Zl-j;2RZ&%n9`4Prvodk=JG8@v-b6U#hW|3}(mT@$Bo4oVm7VDSsCb zKFOEKjHW`{b#S(ts%mgUyr^#T@HIgkb>+&Xg-iEyR69wI-c_jK`S6Er5b8dU1_F@( zN|ku{vJLQbKng(vi4ul%j}l&eg_^LJKSxvS=u%2h$PIMTTX(&_Rly??RthjiIrBSqr0+&f!yo~YFmsXj z*yWEKU7v%?Ux&~`5@q*&jW%)aE!x1*;F3Mh{C>sD@NnYSuCQ5s?#q7sKN7xB{5QpX z_;vO@UV=I|{K$_h9$#Fi|Lp#Dx2BgXIO}`v%RQC8{4NFN1uwq*9W)l#<6Q_lwbk3x z9Quc2lTu%GGk75&AAwAmw|+yw!X5TgUr=Yyu28vc59xC)TfvS^XTJJp?|?1@irRZm z%(W4yj6D&>S`In5gTPDxN{KB$!}=b3*%DcZmS6;L&w0Bq^YrK3CP)3W2W4F^1yn&O z6<3XN+YcXJJq7hnl1w=RpEXdC_2Dwz4rvFh$n(_m%ty2@REgQEYVD= zL00P;oG)jlf$k129N@~y-Mh-^p^ubpccjs7gaoz{5hB0!!7tk*c5%tJ`~+X62ScfN~Qau zjd$Y<{Appri=^><>7L;Oj1Mz`-0nJG)#R!SedC7B^7?V3d$B?A9WdZ-yp0 z24fDj#bSpo8VV{P8M=G;70tp`sCy22Us{R0n?;OLQf^N9eSycu8T%|HrLXh+^qs#O zOx=0vvE}R7pYT-nc0NJ5>_3%@zw%Treh*_O$gUU7JFjG>pNzgg$WH%GCHo+ns^sUh zPmk9yT>XUh?wi~GDOJRbFlaydGXP(&q~NJM3swm2vZnVf_5#TJhj{V0G$UBiJXB?Rqg8X~wUATK4L zp~Fnbeu(p{8_JkO347%*cXnojl<{0;g-sH7!@v>`g3faa|AH=hx%F2F1qjJZF7Ag?r6u}>n5rF)Z zq4dB84(?=Q^F7k4W#Xs;h{dE=X#oP5*D+lC;dc->G2^tymqH>}T=uVOG@2khlWy8tZC^mH>G~C_3v<-f*-P>r~ylQY4_ zahjw^yI`DNtmg!kf|x<^V3?2%uZvl)nscss4UzcHKO;-0dQH>sNVP{e`uVTce6MW-`&3tz2=ga+47pnn%=%fsEH-N0RUVcdD;0Zh&l#>iRB;l7 zW4(}e^BTXLv+G*J{7|eEUq9p;wOHv@UePy}{TI+fUAD|u)I&kDak)}PyYkhgnyB9n z3V2b!5~Aq%7220(Ey+#1#E7$QM{N>9QZ${IRgAk)k*Q~ga zqTG*8=Kh{?t_srz6&01w4AZf1T%{>>bSAN|3WTpN|0sgW7=4x}Si0daEc#}$j|Y^yQy8(P%1 zquOtb76`U^Fi#bXYzm%1pH{%D*=Yx_45gC%J}2Ao`hOsfWl>kfi>=z@KE>I zC#HJ|1gIKAsy9qTL5V$GEG}(0QAOlY;CK3E$l946JYp;{T(i(%PRW@C<;PM$F4x2= z2h1;9q6yqtp)HFRp6x3z?T~360w*W$A}h! z05wJR16dnM1GpeNJ40cD9nda>T(n^l%~s~>{HR5zDp~9^zT4(h5z%k;xgwXX`3Cnp zp^M^#3HzQbW1B&tAzM4MO;G;^ytbiotu?}|1_p{^vyo$1fof!9_y%#V)K#$b&iY&| zs9(AIzYa~VGG)10>)sV$T)rE z_)AK1uFX@EqK;&e zjn|UI=x#@vc;aUvB0&v7cWr04o!0g1;1oBo4X7G|Dr_6=jNLhgPi+c+@y^aSZ#8Yf zVSn%4bNUUVbeAG;`=ir%?&(!mH$PsMwR=5e#9WQ-ol4C zd8Z=a0)sgD?)c|8tu+4&2sQM6X)?kStx~OdnB-o{m0T#K)ikmH=82HDLl;lqG}507 z)vF_&HQ*q0!{Ptg480VYa7;nl)&HBCDFPs9HEZVblW;{nOs+HJI|h32My~&ZF4h+! z*UN*|!fR8sF71)`4BYR?vkx%H81}t|+HnZ}8+E{n?K}H!B)8omAqeGvy<}u$ER{}< zcK$kSKM+|j+pWix7)+$X;Pg#uOezWD(JAISVK6zD%-%o<@>6Dim22rA5qr~UgN60|1jrUen2Cg&fDsz3nt^l#(;GQx!WSbE56GQ| zSW$*w-_!;%3Gg4>DWJjE=|5B)1c2_b?LboUJVO4uYw~{w(U;6ectYnYK=coVE~(AY@LRu=9t!68HWvy6X5 zzJUCe8}1x!w-54Gz0m#v|DAZ-;?5t2qIbYC2C<~{4@(X1kG`edIZqU+{^#xXGyV=1 zuxEdU0lN(R=B+s3ixzxU!|-B*=BC=j?8Op_xl_duu0k5eZXP~iB$Ve7Wre6WKr?I; zggaCNJZ^Yspl<9ck0jIbp@)o+W6L+G>F^c=a>cYzvwus~2@N0EpKucJfD%m8oi(o7 z%7}f3VH?3aDJh@spWFHdJsna4a%cC>V&y1BwOG z=g>PTq5Cj4vmb_&%SL4f>3Y4~xp8Ey83hk94eQzhY4Cme1-e8W6$gWCB%By`9tM{+ zGwo~>NNXu0g_zhZt3U$*N?EN8)UujLx!TUttie(YA~v!7)utZNfByNf(_}ibtNxi4 z>-?VaX5$OyEzSc*J9_TJ=A)lB&P4az<=ley=K=rdgkq7szw>(nCa@C{*-ivBMJC(r zXZx0xR@&{ArAPQanx60@Fur%N-^2<%N+X9dHBk$Xi8IqY{kEG##FvPqO;vK4fbtq+ zNtn}=NG*5ld&hFMh@#oG?YsL&lF5<&-P>!OpE{XLDFZzHz3G8W8amEMWqy15nrqVA z=PSTtjtpjNb91%qU_`znmrOf%Y*p2*cQ_drWB7kR`%UnL|2Jeg%D0N4N{BNUtu$yc z4zNe$6?-mzlI&X*Wnf!B9QO9*XVb+!)rQ?4id7RswSA?;So)xDtA+otcE#ZNvTY!f ztUGE%pDt|9q^5J50ng)(XCkGoS<~ag{8*zXpXHRPeg_bUt^ps0hz8E{!TRU<5nq&T zwh_$qK<^&NGMD%t`_HdI>TQLbf8hjatv=_4x6aiI9(>`u`FUV+fD#?z+q-+V4E+b9 z;UV3I=IU!iLGY4i`#6{(i*owa;M=?TmfjO&`tjDZRn+y%kOYR2T@lz0qQ~L}>n$mF zFm6eLrZtuz2}l5F6oGI^g(Zxsx%w^(aP+%3vm`Xf#b^ON&wlQNBDWxF zF|4Vte?4%R<6`=jNXU8n4!y4LNFTi`Z8qGS9SL4F)$p0OMO+Dh@NVR7XTnu6@n9_W z;9IY;rR15;7p&R45aH<2npKW-QHFkIo=~PdY6)WAwPpn?I|sW!TL49+#|DEFnA>O* zv{Wq^9gq^rGmJxP*?f)nRQOz1fk@_O*70c1Pk71?R^+LqIN$BVbMX`3LWGj7o#oqS z7Wo?&7dOyI&)2=XDh9sg!73B1h~6^jd57=fcJ|lvf#i#eo+tS;d>wuhA0yO0wBFJ9 zSVc?-X(m0NQo?9}#-s`1B7kQpm$pG2DcvZa%|`on>0~I3{uDh1?I|w_2^` zR*T9BIhMz^pM@pzI3h!kT>xx0C<6sF`!s_n6&62q7JlWfAXmdl`tu1i8RdA!Nbci_ zgZ1A=km~kxs=nK_7weO!9akH0POD1n&TP_{Fw!|Ymo_HY6GXD@E!FBP_}><Jqok>2|->Awr+2-b);Yt8ikz6K)76rJ00;a6U2T_s#$9H34N;csAYxB9z zWu7&x`72m^ZUM#ouhg)D1_Gl9FS#Bu7ko<&89pv|mKcedvd3`$0`*-^8DSe8&#QvL zM%J%j-wqq8)#t2lQ4cA9Ph-JrRvJs~_QvDy$RWLrF(EwrvuA%tcmwEL3L3bLITNsa z0VqX;I<7L^l!+nQnEc=~SRpnk_Uvehb^g1ak!CSYrTzC4$*{iFH8Ld~p zzUl0Sc}aTd9>3w|@{a_94o4awuNt`O`W)*O71JL(dPru7Qy+R@NCohUKZBpkLvnfB zCdHKDM<<4iO=uVP?7t#*^=s^_JieDZ#L?PHFsPK-bbzn41H>7UQ5u*CT#!MFjgto$ z)&cg}NF}dma2$;qs-+79lG~4AE82-DTt+n|kF|YjpjbW)CQ%RN3^p+|FvZ&2ChNP7 zZ5}|j8AJV*P%IYu6(bZf2R0wuRiD~A(9m?JC5dua0|_siT7$PI;SYWht8xtb5XgfL z&(jJoMKww8c_jBW@h=Xe5}MBU5?Nopno0F;C;~Sbo|u%>7$bMs>Ix~=BH8>Q&mUijyu5A4%)v2y+XeCJU-2FPE!o5hvK<)+1R=%YOF99L@9N0-`g*andVuZMqx?#(st_#xHPWpDRh#)%3&S1h*IAEH+T zYqZSQ=s}WmxL&M@(B63pRe|hH@cu|YKwgr*hywtaT&mMf<8?4PFMtc(DtJ(Ee$c)31T7J?BWI#rB!-#ZB{dy0Z#aT@QC&1DXXI z_8-swKKmldIY2gSF93+t^d!n*Eu$aIQOrxuk7HY-i@~Wzfdo2sV=e7!s%8z2?65I1 zAjIt$8MJW5P1jPxgX#3(a3P$uod~QN4&MPt6Wgwq3*#drdndLSnr3X7*gG;ZUMQ=Q zNd|he5>jLqjtx5W8*%JppZ@F*(58QmvZ|oBbDAK45f@uI+q4tssQbbVo&s1S_bjYd%(tMe*O1_rv%a{7*P<3UWnrRkeT{ zCDB~tBNG;l12faci4#mp#DaaJ^8<^yNF7>!G#+PGsBAoh@DNq$yr2IZ;0yD1oYtKL z`}K0jV)3|+E+uRYABzXk)fMs-`J|qQYqTk1~*2B&w-aOXWvh$GgGKC1mdo7DG%WFdr1}`qxBT zGzJq|ezZTyq7)z}04B^pU{kVxG_NHFjqVMhBv?Ow2U4L(HuG=rYzbsbqP|Zd7NxI` z_ck)kb7le^>s2C&JQH4ZX%O>s(E7H)0?aLLQ$p&V`^-qpI>#0?WJxmbyGk|`Wj8y= z^Y8wXr2QD_*vkrwnBRsWO4E>g>D%xPRtG5Z?#G%m)1%CA2!$9!1@PlTZPA;kIsxDyHzfjin~y zCAEJll8qVF;#6j8Din==6xivC6e-D2M&JegF*~Uvh)!Ufmq#a}z9f^O2Wf@e009Fk zOx5!iMQ^WHB7@h~I#9hQnFU!Drq~)4jD%Jcj}zZzz6FpJ_e+C*q7Hehjtl|(hYZ;3 za8naRuzgUeb6h0ry;rOE$6L%FC+hEq@ z`U}!+z{m;YVIIRtI%T@E1}_xOg8{jS!vH|00j`t(KPf%%e?h>eQYAeNR^hxzuzytm z=1~FxbT=Y#Tm-DRN?w9e6xZHj$wFB+1w>>VM#Lp>Vx}ZjIRu9hW=SK8x)s*|q+2vo z752T51X>VAbWpqy0w?!V06K*V3C!}aAjq<%<#Z!floczYYLRHv{-tO*5r)5$Xak(@ zwQ9)Fu$*Aww?LGj3lviTunqqLV<2((%+5QPVSQ8Y%J=W zDvpHJ!FP{GElGrx*G3YhWGKIjN~kFbMV*%ASad9J0XKL=RV>7p%8bb+Ne?3%=S<#; zIj02#QmSyg281wjY%>H&4W(yQH6fP-XJqV%mO@auf~5k{2XrUdcgSzTldsB{iNx=L zXW+w-rlF_w^|l__rtFLuoLEKHb-(I7t95n3lwe?fe~n}&UUqs0bkq* zmJXsJ9$l`2_qimiC^&yFttibn&in+DU;?)J5r_rYV2CL$fSD9n*P0AP1P`=ITY(fA zh4j=wuEz6@!VsFRAn#~Ag!EDcNXX!F2zjLQ_mZk^vG9i7$b-c+d7eyTKw#=xjVM1@ zF*B^ax-=$=WBD}CN=ja($V%Fe2sI&UzET^`6n(D}Z;G~M6CRfOt+ILy_*;BkAe>2R zlNxb*zS%7>(UCq8f-d+8PnoloL#;OnWMd5&w`<HIr!*)HBf;)v!Pku)5&j$m}OR`*v{aLJ%trUycc)PIC z)-*ZGUsLiMr%W(cp)J-iZ@FEq2?g)^DW&G?Yl87R?>pc& z9pH9zD~l^)ukYC{mbHbW;tUQFMh=n}dON0f0YUUSmgBxmRabu$4zu>jUsIcp&J{e~0YlEpkrDTrJC2zsoyKSNSo@2fp*!Px7`uNizVGpB5S< zfW*{=wv1xs$%=-Rg^qEVRP7j=(D`ee*=&+B*k65dnL;))2s#s= zctT|Gk`#m!^}@pVVX1T#0}P5}BGIgx8!92j9c`$VhH`2M=Ok0G*i~C1k+EjT)+P%l zw?OwrZ(3TScZ4Li)#J9BAEnaKR+0sCj&>P+i@JKcZ06n>PJx+)gBM7ktCePFo0Oi>3yYC6FL?Goi z^ib!AA!m;n!Mqm5H_gpasa9w+w>c7?>a0$%e{~IWBt4jBMJ$UkQGD8PLgSVYvu*_B z7E4d?uH%~tHN9iIw(WXj#J0C3W9c*>U#pzPV(f!UU2jd!YkNuql#>j$MCG{dpu1&X z$drfkok#M+4Y#> zk3=ikoHLv+`|St4wF3VS6^ICxb=ead3@lh<0tP$al!5`^E!Yk2ta5<;yXhvLHe#Bf z+-eS+i`2=y%UAjJ2Vxb&j_aR7^5%c`FW@T8E%IAne~a^?e4T^#tO&5pbLVDT5Y`z5w-I?k9>XNhWD(uKE3Dp9Z?G-zNe3T)LLjr}l0ULxCsG7paMh)Z)~-$!@Ehp<=eO$nT~r{V94b zMbCBjBHgRh?kapqKf`m=D9|*`g0CXW4=f*$w-CoqVf$pB_H^0=-$hvHWCT)&!Q`nE zaVQWeXaIuJj62(OE93zY7Kk>Gz8mY{EUBIl;R(44?sw21kmN-gE4(B*>;8#WjInU` zdTCEJlu^a{GdP&Bi)rMT5ZUQdzbqg(oZT<5*eGo8zhT)5f`g8|c*l`h z_($Xtzjn^MAUehV?6Ez@*y{(xzk$@@Kg6P=UmG#wc0Rc&HD#8IY;bq=6N#F!S&@Jn zASd8=H)6m>FFF7p*42no0ETPm$)SBEb4PpV6N$W-{)l%$j%F3-LS(eopB%0qQDhS_ zgd$uy0Fl&d2PN;JZRBx?7()?yY1{=N6v`85O&SPD2{r)}z;8&v1&6!01PZ#~mn}my zjGL`!!O{1;Xpf$+wE73>k7p5V**WJOe0qD6+}pA~D;1B1q-vs)RYo^&9@VFcRb#S1 z|B760kK;mhjo*E`XNxi6>EmfGk_W~^eZSiG?Y{4V8V7{l^A9QWxEe6s9xuby34BAV zDcxEjzY9*8X*E^A-*6@k>gGV>Qmy%ZU&uodyk`~;Y24(9ybeM0xJhm~i9l2j+6al~ zKoBT^^Z)RRJu_T1T${*Lcey*=T?co$QJO_IkXN11odxIEe#*h{VB;D#L8}NffcW7q z+LGb<=mBKTJC=cwg-4(3hWmNft#Hqj=eqBCzG#h$d+~mIAfF!?$nztR`*z4lorQ}; zyVY5vl?*iC7b)Z=A7A7nW*V=DL(L^`lH}*#9^RX{jmpyt%yzT-1mlg^NiN%Mh@80M zuuC**fzdpW;k-_r5_Z05r?8uEr+Alw_26B4+XQv#dk%fW(-ACqeZm{hl*e}N90UG= z|I1IdkP-|ndJZkR3Vp#UZw+#I?XP40K*s@t1L@ubtZNy}qJ2CnpsTvSm_6W_WmtGH zKcE7D%+P=+vA!5V|3ps6@XaEo?>({DJGhnq94!o;Hf_JA>B6iM%|w-1LD!;|sO^D1 z=yROEv@BxvBEY8v^L&10#^zT4KgOeL^eDqRfz(CXui5sm0pcx@Fl`J*T^*DF!KWys zXcuU0MlAU%*Cnpgf$lu+PF~{pIX{Z!7_p&A0@-F9U$h-Iibl9i7LQGp{V(5NxoR|% zj{yyCm0x(AENfnGJvoHue{%Ww=&QgUbD4}zUdU=U zF13rd)m_=qmfdVmtH2fO&E(X%08J9_;0bDi?(Ppee@D5UuDc|6(R639Dsi&I;z6&gLGXx`?^Sq$sYYG_j(ynOFc9c)QuBSI1&I+jNG~*PkG9e27B_= z$C2^kf>AXr!&op{&9TlsIcG8FtT?$vC#QdE`3LGN{a-^=>$0T=c#w6O2*``9Ji zZEwoGF2!CK4|{dWn6en!QEqi;i)4nY%WeqBIempVHFG@VP}A6^q_>9}Vs&{+xg0VgP1fkJuiS;!)gldj69b;-Zm`2 zPzL1$Hwf3r50EtA{*;-aypXrdHFg}-5T2P+HnUVR2PD4el%hkFg+&Zuo*WFzR`m$r zcl=Ar#w%6VHoGqDLVg?@X)LtPrefijJj^!l zV>=(bA)Q8RBnv~0oi|Xz4I8-F8hrW%#Cn2%kVMH;WhidFE0L7E0Z9AJ1)wFS)3c+( zokt8Kwm5~jCr?k{``xYU&@ZLR-C0RtHSl=gu97{wKB~qVU0mzAh)?)(8QCMR1toY1 zXu%zz2CoI0z#B;}^LfH@4O|#^E`{GAc0C4f2IgkfOYlsl7i6!aHM;?Epc~PFU6092 zz(VbZbP$_YqeI9FDsG0Z7F+KGomAa`F{U>uDze^T%fH~VAE}0+Mzuj8Jpx!XESux= zKnlx4w=_QvpkT?BUNn6ce47l{6v<2a?4BpW#yN!Z{x1&p zOeg--<3;|Iph*z-HTv&Tqul0WtF5c6^i^zFi@Sz;98l|tZecjT)BOhdiumnz@i)33@{Ao|&U)F7jo&?KC@n+5 zH(K;{T749wh1_13l%adQdn@U~|Lxh&ay}vsFJD68Ba1Vfw?OZaAjcwS!5ae%&u!T1N(NtivRi_MryUloA8z!9(>znvH@^?tz~01 zA)1FIr$P@gr0$0O$M>IoDX7nDx>N`DY4}ZoKWgCr-kiV<$k*ir|345b*I6sYjrp zM&YumuPnFQ%PWigh2B0ty~IIEu*Cy-aN~9f9|yO2p4;X=C& zXfb#I^27D(>aCSty?gf?QxKH4voV2O7NMr`U5wbzMg8WvkI&t#i&~O#)kZ%`! zk2Rqi(>w*NT`y7rtMfQe<*`JQL50kFO?3c29QvGZcwRe>e-RN7XWdk5YAvZIRmvq^ zW6y+S>!t&GIP`LuOf+TpZbgHY{OOeKtCGfI}(XG2kS;nq;-)&(^hI{Vss zTARu>8o4PgUAJb3hY`9+YqX8AJAw7{0o01TVxTuc%o1Fb&@~MT{~(PTRQSZ>`@dNG zsJ;{~K-J_MiX160XSy*tm2iTG$Snaq?L9}$gvsCJaa`2z6wgJ!TxF*=+)3Ojq)HE6 zqo{}OFVyFeRCRpFJwbVuL}qMJm7&ceLKeOTFy_aHRdqPd;CYa@&}x7|>^aL1vO;A> z6NcauV*s*Qm!%W#&^VLl+xt#R*IqU6#F3uR7`k}@E>OUwOlS6v$eJownwxg(J7RDM z!23!%D4AXYJ}OJFB9e%#A+hU*3-r<04t1ttg_;#vMd-ucYzlyv$f3CP=AmdN1Mh(i zvSGgOakTU0B*SQ2Epa)zByz1~B2Ep)@#oeXdx1?70yuHg#86Ow;2(nPA&^f_0cHyh z@i6Z-(Rt`ewKhGFP-_^IWbK1IN*j<@GW)54gH#jj3*JE=Q`jdr3Y@zIhE&h+OrtXzbfn0GAUJ6| zWfbfzoI%8dyyv1s!<{E1CR~Kz8^DSJP{tG0$;oO0*?aN1B3>DD>A6fX8j0nds2eXx zWgTB&5fKGP21umaU6Q0b_~#{@5@Bh+9P@ODzmFKG)jqP} zZsPc{u$EH(u}W2iP{?gZD)Jwpc|BUiO{k!>ID&{sVoS4ogiyNXEMyccTx2^1VN(D; z)pH~ayPcmTlbxTqKL{7Yqv0@%h0T99T;re3@UkKS2@?MvQKUAUb%eHZURi`|3jRH! zw6TMK?B!~5a#2+mCzI+CS-wq@j(!K3s%8aY77n=I8L%apxeSsEeuPc<5i&S}b4x~u zLL2SE%okN~hddaC*P3^f5x6QyeD+@u*Jh$EZtr_#-|Nr{6lRNRf~+NHxoaHv8W&(| zq|wH8T{BP^gVupxodaOc%@ zwRC6{_hkzCG(3Rk=P|3(`9cP%14a)HRMVgUFUV@4kdj-@$w>B|Wv|QMy}dTL)li1x zB^EZ2Vnak|aerQqk(?3J^Zju4g$B12A6ASVsq|ILMO8P9`gnbhI~yNFBGgEukZ(kw zQk|KBx-!zp7a9?yOC5~Qx_fY&M0o{XQH)2cRm&L|aI9)I8Yh~&&M!paEdo0t&w3Xa zkGz2gmSM*KM{9iv%{b34@{a&A0&@L!s9661Z-TEud)jVcN$wE;=0z0JMF2OPmdpz6 zR7~kQLHOJX{pb0(VX5c0VB`C2kRC09a&1ObDe%FzfM65mpT~ZK@>6l(h6aaR^6MQF zD3W9ydlJS2a?7LWsd9pHWMQ{NkAMmNmEn;hYy#wI*D9`t95p#QBn$x8AVx`3S2_iPMq;-QcK&HtUODy;}#;&)= z&-fz0n3uecZ!UBFg0QReuH4D1Ml@~Ys*^O5DE~n#1#Z&LQZznB8DiE%&5ee^EEZX- zL*wm#_7`@|jm#Lv%*foX!UB(KYtfypeThL8$>ghvecrJb@YX^qt3)YQEcQ>pyi9V` zvs{jN3Tx8Yz6U`UJUs-K5za2V-f+RZ10}}zA%7lPZTxJAG%ooyx&jwb4o83h1}sK2 zj0l?m-u5^G%SDN#T|{)i(Ub;W7-809GUzuRn`JKp9)b(sd2B^ZJvu*M$<`bL$kXL< z=-=}QfE#jS2WEzM3`R{jPnvdVvPce7C0(*5^qp2~+EhGR^XMk@N`%8M!p%pP%Plx4@9g@T8dXi2!MZMGy1*ejTm{y|TIx&&3 ztbkS+)il?k1h#^cv@;f5@acYUPfZS|qvw%^qJW`8>ALibGouBZZvnZpcMiR$uXZ(k#zmDed2cboI=sZ0g6sT-i)2p$Igq zasqzEx@>4FxH(ai<%pWeg=G=x4nhgsX-6#N$BqsNl{EPrICe$TDz-!W>54EAoh~Ip zNP!R!(@zwEWx0$RfhJgFHHf*vALbX?I|8hyFm$$rg4vCzm61j)k(^a$RJWO!ZHlCa zNctHV*!gRB{BrVJr>b{1s_z`Rs-6ViJP+SHv+Iocfipu7-L-e%Wq0WVY`fMtJUTvf zCRpQ_5tFC^e-=^p0eZxY4Av6aGpl~~$S!HxjuC>jACo=DgxdfbvefBwZd-yP=z`rw zC$#Me{h(fV?t-|i$b7oy2z^hKMB@z`XnT2Ixs zSP0J#owQ0mT<)LbcHHhvCI^z`_}-{(P~M57 zz*jKBurzpsYND|XF$09HK!OWzG1=ocAoO|hI{Z2B60H}_SxTr&DX5s3amK5kkR;o7 zue0xAYTB?MpHtE)cCTyOlJtq{IF>{lhY!II-$<+M9-H-HiK}fl##zE_C)NBlxzu@6 zR@997Kr(ZP`g}3;7B$&66KverUR$PBa*<9S$|N5!GjP2z&Zlyy5MS?oyXqt|M4!M+ zy1ZpI0$NG(ZDXp@OineXAO!lBUlTHA5fI|Jy){AzS@-}A)1yfOG-xtNpgi< zyV|={L00At&msAC=V8wt>&XQS<0*}NdN&fy2-IX-d58Kd2=pb;hY_SL8QzY7}c2$qR z`YJgUiDf*)ktwUlvL$JN5 zo(B9mYkB9kkzL?EcJ0Ty77r`db5-TnM+$>SMDfUAVFvednUR+l`tMcl4{HO*C>G6MyRw2QBq$m< z%T+L-tBt#HX%k&~WB!JrsDpen``jJpSJo(qR|r#J7j`<&oWIbjUh7>&;ka)E&-0x1 z+L5$z_#|m8F*itk#}^&2guGnDNQ)%dBVBEvn%HnbVc;o*J8w+H`+t+~MsH!eOt5HvxdqIH zen_Hy+-I9NDCREok=UI8lf~UmD7Poo3eD*2VX0Ogs0d@nA)1ej-2$WW*eFsRg;e3% z`|i6|P~WGDQWGf~BthK0n;0V&YD%JdZ~*E324cE`6q+zK+cLsA@B8ihfN*R{vj=h4 z;2?6m9GsObW?rQzS5g0K)c@>hlr`5^1PbyH*86eDnXt_OKMW1Zjf`kcUM@s;5TXY7 zy$CBO)fxc-A--9KPPI`>Hp@`DvPWm&oqX#Y9Fym6O}OUF#>1WUcyVTFW@c$FIriyz zyk3t#oE&?k9$!7>4Biln-7x5!>h7^p^W@2sEL@!{mCl#$$4@Z7mVpaEGI5O}GkB4r z7?jNtXnr}0<0N#72|87UriacEcansD5ex!Pz>el8dJEB%2RUFR-h)`t>ar@_r7l;o z`~NIk?M?Y)zHKeX_c@LrinTP0kI3@pZZ;yFhuXQC zELBt2vwI`P&Gz>SNQ6`ugt{zr_kaQ$_=5=G@1pQJpgfr57jm3igb{PnfZBb~<9on$ zMW=xih!sLcBni*t!qrt&2hxgy6$fFZrGqm9 zb2{(g9$9}KbMA9uoxcW}`xitpmqVJ5g`8qpN^Ze|Z}-L%>~8+dT5NFCiR~}T5B!*d35XF z1(p3bj74B@IJ2DJ?jfe~70566e)XG_=KIvmL_Ke2i<>M9u)3g~X40}YZ8&1DF)h1u z-nPtB+(oE;xtsh)y!jr;JroU4S(kdi@zF9F=dcbQJ@vU*isAPlO8$X+5@-m`t}iYv zE!O9b@e{rX^j+|NPUbemHZH9!%`JYKAL5&wFKvM@CH&vrq)GHWtJJdRN!9%=MN2B9 zHHqAhAxxts_yVOs9h|&a#~|sL)$GT@82&o zYYDFF#Gt};z3o@e^Fii(sR}7_0`=pFM1c&DygZMpZ~)Y<86HH2G~YfTD7SA|`T z0#j81)Wui0nBOHV$;H`~i@X9qx^uk9WvJp8M0M|8jAv21=_V+?MRm`f?$N(_-07?M zE7%+ti@$q`!(hIeDLNsVumHHt{IVwI^CE-tQm%V+TJbt-DZb9(h)Mbkf;(L?EwF*Jmr(U3m#qt5qV0apyr7rtTp_lI;x z56#W-pZ%RruB-&>SRY%#Olx|UWkzZ*kH8W40u2|Jb4VBi<*#zqpH6KPdEgt}({r;vXJrEe0wH=q5Ps$12DDNRlO>i#$iGFbpK%8sR1|1H+B7 zP6^lPG_e#MeR65yz)WlAz(gGw>2-EkM)rap;%vtiLrbz-k{W9*FH_vw^72^nsS6jL zN_PGul3k)wFL~Q+r0BZc{@ls=FXRmHqP%!B!k#ltif}Y-k~WDrghds)I?A#Eo(wzQ zWe{a>4jAn0+QRU7>6!Z6V2;hzv!kI{CR6=}qDnKzqZOQS;9CU0u_$1yeFdC(@EqN=JPYjFvwvc>qGp*=4|d1;;Vuo?59HV_;) z#-&YHVG->qvQmMoK9L+^$*_!I73s0n!$l00Alb@$2I45prNZ{yAfjYYkLe2AIW{mG zwquzp>l}?FBKko+B<7B3+OeD%(oYV_F?r}DPUWLWo?Lp-&i+Yc7&7KHE0n9S(DgmwboE;x4!%Wq*#S1l5l7TY_fl(N_Sl&2#*1wYU^z`qP{o27LJqb zpuH#vs`wbv5#pvVz*R=L=N8Dk7t*IspZ@;mTuqw8`S$_>V(hzu;_if=Uvyo(H~SV?(S@4?iFLlA2-i}^>7C#HbxCudI)9$`_wRxJevRjS1jXSx za<66uR1P(w?uGji)g9FaQJrBQkfbktNs>NLEIuh|#m6=K8BO}4tvz03N0GVmRjB3B&0T_$uHDalXn%Wa(av1{&+s!I1m8C?fOe$+c_T zGncwMmQVdWjB&aDPlsR&wFrwxZA*bAQs`2Uh4GkhTpkLWCB?Y>0g%VUfXy zME|CON?@kbYD&%}Q|wO~LSbJf&+@qfk`C1)x>TNuCA9%JR!&={8>w%fdNcdg#??_h zoj+MJhQh9CrOPpQKug9Z2PHjHKXGI`Fy4GyVjpOtjkz`fj&-rG-M7@Y-1kV|yZYYO z_hGa$Q9>FH;A9X^&5|HP7>B$ONvk&H18;f*2IWkyFHkg18xDT~>22^l1&pFfeCb5v z(_F0a)H>cdydGLQK6$VBz8VC%XdIVk;L79eI4*`Po%v-55ljfZSSHX8M+_@0iX`t9 z31X*If$gNwI!^asq*+e!&^BCoEA4cfvzan9pEaNzgcL0`u7*RsU_$~4vVqAx> z-uO6w+X?~$i1o7K*e=IOpY(Gz6bgq?l(7+b8=nLG%vsYstAqr2-FO;enhDG6yR6^R zfS{u`q_8rW5@q%2a5xmgp`?tAsmA-1u+%`N0>$*c_BBpQd-P3)uUft?>kVxPx;E?WAp64x$lp zqG$KjnwDtRWB}?Xuvf@r3QwwrvaI&BjR^}Z<*K{`^ARgQh#aa4%r>GNz__DyVQ4Wg zFsSLRxV!~O)J8Bs&|v;^q?Zg{A$OHee0-N17ag;{3C%10a{u77eLx&RoFTeO`<5ioerKkSx4|zZHBnqhF%s${30B{j7puz9&9(_ezO~J?bhwyuTqs9G z?+|)D@Eve)9Cw5}j^hrpem~!5W>sv5Bk#SxKYocd`^+=Xl&5`rF`_euV!-aV*|24P z%aP(!0LEd{3wy^-O@oZC+iQkl7RTI&kN=pEit`V2I{30D9C=_faohGMfC8c~0R~WM z3m}XF>jmfn$raSajd7CwU8iJz-l~S=#>jPDFYf9{npGI>;vY6j<6pyljZxQGt>{HF z$_8UqnrN1cbabIzLluH;xHn4eY_zd2{I3SaCb%NEp_uOp*kCn7W;W|O>AD@z^kLUK zTpw_K-1P<5cQ9(bkX(Zpu6KU1pwxNkH$kFRoYXqkp(i4GMg>T)7f)?z@z~;wXR@kL z0C!IXaqpV(%eBvksM`9<-}^y&w5r*;ukEgYmHr)8p0p_?!(_m3hSy!B_8}s zEHX?Z8TDJbUiS3+?O%rU$2wK`pR_AlJnFjc-DRJ@%Kqs&=PE24PhziM;17G|T!Rd? z;t?2Unb!F-a&aQCVbH5rcs$L1Z*ZlAjChV zh&kuXaEZHwG!K;Q4iEtZTpF zQ>o#_6s&yl=Rg3o8czLpQ*8R3hyiPTF@+Yxsb$q7m{Ky0ClpTbLaMRfbvfczBJwCn z%V7rvkw4J3@+&9K2Z)(8tu{WeCDTfuM&@%wXpyoPLUob^V=?tA))dOaBlUgdu;-J~ z4a;TjHHP5~%aZQRwT8ieL4Cm5==OQyQPxGf`f8I^XsKvfsH@&IZcqZnvU~b7ULWID z@GH6jV@lmEM{DZb+^e^hLN+~RCJy8N~J?t0hofDR@C1)}vyw^5T^wE60hXiew_$Reogsnc}an@H@X-=}uo*t(H$nqLo8gg|K8d^KQ; zEsMAabef9h4vH5*4mqY`-B1s$d}>Kct1vW-X<5OqX-Il?kN z9IZtjgGdm#WY{q8EK9hEk^gzG-JSfUz($(s zZ89cUNA3HmAFoLaPq{5?9Cj++-BqoSk|WkST^MTUgWVtUGe(fxT!qk5@`C>Y|FIV| zaDwzqq}GKF3EvF!a#)rt!7b>H5?r^T`(PtM^_6L1sUJdRiS5ub`M}o6##h6{K(gOk z-k8_=x!3!1%L4)!{`u8bM)i+f`U%EAY?yOb|A=qAZln zl7i_hH(qxqz4FUdu<^OVL~z*%l#twQRW)7~sjo6C5*z69pJ`RucYjY!#g3|)9ZgBA*(z@uzAPO{%B1MAbPA3PB8-FE{cuJ0UjoY2s}Y#8}SVlpImb?NfXP;_R*DPI_zVJ9#ULf zTpS)@%Oj5?e4a9}Q-_wdWwkZeSDZvduwnd%Nfd}9PPP=EP_Z!%(HuII1XOgTV)N>f zCgCjT4j76Nl*d9QQxvRIc(icrHwb%`?H1+pgpzNNk5CeY#0`U$BvCwk;MK$Qdxkm# zgc|Y9RCjAebxZE>&_e;3#3m!YO$ulP1IWm7!aqUj#}GoLXHJP1?>nr1AQ=D}Xha~T zrcQo1ca0mhN?LGr*uSN6kZ4d^3|N<5tb-~g`6nQ!W&l=YVC=CLu-i27AWe1m|KNUT zJ=x)k^4_2RE}NtO<(2 zv=c9Lgw+OkSH%e{D;W4;s!<|~a>Wr7%B0wr>OkahC!vIO>ABvm?l$Bq^RrQIy1;oyF5FLu7_@7{D}Id_h^0 z)S9bUE*T$cIqL#s>D)O4e5>+`u}|W?^(9$01T=PZDZJE%foil!hNC0{Bndzbz`FX3 zlF`xNfV1vMfJv+bL)u=XO7v+T{U{vR{4fZ7`OD9%xjzL{jVqc`I`_J7b9?v$ies=< zB^ucHO5AbXb-1?@EdQQ8=hfUF+FVD1<+{zGq$d#YycR=V`bXo6Tt!ZderRkp23gcV zLg{(<(WgIPnNg3$FQuPt>~qinSY~k({gn3PUg(h`;4)tfZlFXuQPKy%FbqPyW^*z1 zWUo}h-{c#ERSpr*D#{1RRc{cVqtJ;8ol0wt_rlT=fnY$2*-H@15o!2(5)S4ep&gzU z;PsHZytV@L7`ODGuJf`ei9Xo9CPWuzch@#VTL$Xi&j&9bb}&UyH6M-|L4I#k2;Kt8U~g$Zf!JBZqe; z5ig3+hXfF7iL&ds9AXmY9#E_QdS74PzP>{$ZptLkLT`D+mWCsslpzq)5$-9hYyN=G zY&U%Yzov(c8ePW~0}HRz#2=`P-jVVRO;pQ(7B}6#VphdEpO|Z%&f(d8`?iwJQj~=w zzFwc%Yjx|-{IK)i=dV{JheK>VTY4Sg=uK zc*w_*>66$TaAgr#+zW)nV%J?B7;dS!;n>dd zftwHTKk?#I{^021;cmEIyU0+}x8at-%K%)1U9}f)FzOH1vk&fWXg}N&`^tfSfl$Hy zCk*l9?hV^omn(MzMvp9BHn<^L8Bf-BjRYZsaPZ?I@T0xP3FkX}n~G5Z3Y3C40gzAx z($d0MiQ5B|P9#bqgk)!%eHHFhWQl4r%D|I3Ka0>jFJn?e*0!puZK0U$)AE#BiCBzk zJ(8^G``p7G#kgJMf<_C&LGoT@L59_1+mQp@+YBYX#Yr(i0W4vYgB5Di(+IKwo(p$^ z0R?Lc+yUK|^8o1j;SbRKhQ>`&-`obZBKN>yLmCNBz|DBndO1N7MO+=SqDX-rNEp&e zA@DNO@Rkz-DM9MHLNK$L_YzFkl6_5o%x{pnUND6?%rJV(7 zH^qwu+JL(m`=hc$yEGW6d}E|Pa$O|y#>zwWFpq}lsraW`ue+6iZ`MG=3dg8RdNM_0UboomS7a@eH5%}hB^$}71Rp2T>3#C1B8_yP(%~lz%b?* z-+E+d!1%+W0r+M>8TW%;bhM)eOigsjseXT1V{I1fgIx|*9>U+b&)*D)0EUGw$fCM zK@*8NfCANic9gr-+@PtVks*1;UwFc9tU^T3v##2%#)_eqja9*LRr^m6;IeIxfOCh4 zR7HYq;)=~apT@Oh4N?ib-w&a-DW%`tD16udWhXz@+N)~2x@xQ1f!bPzTHFYL?3Vq| zB-NK2ZIR7~IrH#9e|566+W)t1|FE0m01Wg$71yjAimbVX@^C6Hz}BT*VE#3b*lKX? z_2HZ;|4CXeYp)_n!4fHlDV*gwGhck1TgXCyrBwGeRr1As(NY<;{um>>gmWkS_lVHZ z6N*(;#e%&Qt)nO8Pxw|(=z_02g=OK=6~1?2UHGsITS15JK|~c7%+~E0CR!c7E^E#P zn%14ck7l*yIoANs99#Yi?U46dLJZRcWBiB3?7FiLtUF^bTX%YN-Px9B7`h|6PtUnI zsMZ|3JfB_p-!3qwL>rOa{V;gNBu42lV$a;{Izja5Gwz~lhIl^Ux8fTClfn61!0ezK z@xMu{3BvN5tNmhpFni`dR(q^TnEUf8-85mL;vjRHN>MS@f{_(D1W}`LjqLc#*&6?MHH6?nmj&4 z$PBo>2N=AQ5MfF)+BP7fh$RC@e%-VyRzzYIk?_FC!W$Qy!=qb7qlhK2_^hgnpJyXV zZnvb4Px#ER=|`YoiVY>jp_zJ<@^FkHuBfo;K|bOWm<(+Q9BD`exGvz-A48(dU;UDnY^r}W#@c||*ZJ1xvjf9=4&Qr*Twof}&&Y6+!k`Wjl}?^CRa z&1cwb3fMlJf;|Rb;wyG58tO@3@u$HudqN9^A(2!do6zt06@s`{sy0)(RhV>`$x{SZ%?8 z51-m`ts>b@FRRb?g_)l8$7Bsi`qVImD^m~XK7AT9&M2?6KXzoBF9=~J9x&9#SVonW zMqoeKVN-6qQ$^fIS=qu?bt3TaPoPX&T{KT&OcX7wc&UWzQb06ij-@(5-R)P2D?xM( zDw2ZIbCBX3FblvA^m1$s6$-i^+|;@t?5xi)OIE@0dn>qz(Pd4Q&{XyN-(^!EgJ*Iw9R+;Phavu&8>a6IQ< zU4OF*w@m;a>b1TBW*vR`Q8hW)qZ1FR!oxFHzep8!ZrpT*D%^Cay5D9|FmtM=jXk0t zc*&9bXanDU)g4~nof%cWv+!5fS%s@q`JP@#NiH2y<(KTAzgkapSE-ZxXj)b2-g@|~ zC>g_#A!As=+O7kgc!g^byA$$lwO-@EK3$xUk00_S_)#e2L-xPVrW#zHlEeT`t~Ed_ zVIgJI4?w6?+dTF3nHzVW*?D8}J~+Ho_?VmdD&YSTMTRh0RtDguJ^HLKAnkiuE5Zh1 z97g~e)R8NoU@+J4@Xi}=Y==3#EJuhP$qXK?fEA(72aCXp=(DWHFF`%CY$1DJt5wB!{*S36PS?Zl4rAb~smreu#TK?AIPo97#Jhs23@kN%5P8vEOaH(CsdF zyKicB8^9*&797YU0sn@F*{}{GB;vcrZ5(jBU*I;9ZugC?$~cX_^(^4%3n7!e#^E^> z5U2;TQ<4hEee4Afv=6xng%VIlaGG%}j`fZ8|2J)UkM4#{vaO+YrVal>tuX_^0cy*< zNl(=^Rmh-Jb#0}$!c$(mu33Hi|DsjdFf$R2-z{Z4iT}Jl4j`^Wn;kZ}nP3UGeRN0e zUDqxy|98!>A)&8%8uHHD)mo3kqXwQ;B{vO0`~`>(EC(nY5-_1Ai7_}hrRy3{GA#o( zOHk@`DvMkSa5?bzN?LnIl}AIwgs9c+HaoX1beisNILUf_ny0G#{)pxWq+O~>wEDG3 z%HP^N+T7}ADJ6z2ey`bA3!BPeZ-sYLZ|^4j3VO_mwG6Wyo7o;|*1MQk9xn zRZ&q@^0y~g^C|4t9y@AvBvDHOiMVF3esT^&Fboh{1WX38xIj6oGGbaZ^%ExREeWzy z4ng_K>{(ZL8{F5GnznmuvJM|8YcH;q_zhNswz5SeXL6iyY=0W|*kc1Dbsqf&g@cC= z4C!r^B)PGCrs=b&6t0cSp##Iors91HGASJZ%>(7)`w(LAehO0O7-Xl%lr18-Xfk{S z6D?q2U=zN&Ljq%OG{F`zu0xX5>tF5D12B9O?G54SfvB*gKhQSPlWYq_ z4P)Ctc{Ex+upI)KKwGkBq%Gi=7LN^-)p%M_FfQ(?9ZVTu4O=}mUsoh3JM0OTheG8+ zPw~SQhr5KfYeRYYhFzNII$RO{$J90iuL_#Uifcxbh=As2Rw__l9!OazYVPFdH5ExW zl1J#DIfh<}H`!F7a zBSBLVWCSiE4|Fo|#EOB)*{0hN|4ES|px)Ni5uJ{P@7cWDXKroXbF=dH#rxcTGZgB+ z^)c980GaCdq!G8pIC|VZ)sAkWfF*zD9pBcv)%0Jz`wwLA^9RB@p0Ho&!5+*1_xfYE z8lXedFV$$11JCNmj{>F`n=jWiL#7Om>d&&Gr%gya;bjBetz*Rtt}{+VGQLfb&kE|> z1e!yo*^xNyPM4xd46hnRQ)aLtqNLh}B8#dQK^81Ng^&E!2;mkwd;txhvgoFBC$l8h zE{*e_`7V;|(|19vsQ<;^#V`UONzOnQ{pY@Hm|D@{LSIHXSC)~hi*gaSf~(vJ&TI=T zeIb>{BC{dez+fZ7csEhzNv8rZ4D^x#trw�y28=T)$P<#~T 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≻$pE^>=T!W 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�Wb(T6QKgrUIG_{j)fGJ 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�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

a!y{(T)MVzf6jDC-i|-AF6Cy6GcIq~ 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�NI-o7c8xmLe2*jdtSh%963 zB)+BG=s`9p$J73ykQP@ApgmMXKOsZmyBi0qBM4M$o1mm4DU$<&DXX5Yu%(KGhU9WO znERS=olw-x!*IGz+I(OxbeUi)`o_} zm5l9z&)vLlrhs07+*K)E{aRWv1cPgt;I`7b$aNEY1hpE)(eSN(lEB-fA!x1M9n#Ki zf9}GXzu?`${a@FVBS&E`|5-q| zA^XPG%`B&JP7;BT2gj}o!tYxviyo27lHvkzy$ zkkjG6{wWiTDVG5eS>|&9YEMh&e>1 z!5#U+rg^rR!f@XfT9GKCVkxhlakSwVffDHF3}yEL&J{%hX0Dp)iVtZc6H??5ydyoN=`SXw7yWV=u?+R@Wvs)Z`a;})G2 z2@C+=R;_Ipmxb=V>djBQH%SS?x2p13{pojK^r7uPkcWnHlsnk6o#KwEUFPap8h#cj z5WXuI<&n?j^gn$hOWqv~#?Y{OBB($ zxE(01Hxxd=*@76vADblw?D0kz;Z~R0d!jK@cv02DFis>8<+eS;$SfvnD^jAc=bk)C zn-IvyquE;Y5db1c_lq-jTBXAi5dgF!(9!B9zNp+3v3G`6%|#z&lRvFEniQ=x1RJ^` zs1MSH>?XAO8x!~LSzjlsvN~rZk&`tc56wgGeC4iY*E))CFrdWN-4mqhf#QqPOze;d z)9*X345HkD&L|eHSU@f{a{Y+rVa(NihD@t;MQiKcX{U(I)^7+N>G7Y5tPPRVO4T}t zi#7946*rREp7tv3Mc~vDK?upQl$8#bkENl=T%CModR19|$?sV?&Ug zB|*W-N&_`{W79m!7qzZAU(dtB#vt~_m5uIM< zg911{M)e|S74zvmQLDc~y+paxpo)}X6*A0G=-x?Xla!Sa(BMVe>X_#4Kqe%AcWMmx zPCfXqXeZ7+l3#ZSOuctA4ph?dW8Rdkq2)EP^1;zptR?7~StE%X`|{4Y-`9@yEUBr% zWxuo?B?=V5e%kVVY2*D$!vQ^%l68iObgNR5Hd zqP0(kF+L;$UO5@y5K-c3{2g6n`{3y=*2J%>*yaHSDL@Ggw_-jr@vIYOSI2$bkAME75ArZ>h#U*?R9km-}*AJ=SB7P--4+Y z2OB0M@ciiaTfYm*6z*|Wx`WjdtzV|X+L zYuK|f_F1bxzuZz0=0kL)W-a;$*$1E%SHwo~y^e+}*?<7+? zy}3CgRihhb&Y7N+!lmEzbZc8i3akCQ{dw*y_O9 zG@+JO)w090`&~2=6z+?@xN)$YXqit$}bn5|6P>h7$J`5=m#VQIb5M=*|+e6@p? zePE=2+SLFSNIFB1m3M2bV>wk%gu}wbaNoVK%1EzQFI*JuTSWcr&?WHH$ZJU}YD01Z z)kX-Pvda$+#v$V~S5g}d&fE7p`+i^i^Tq71@lQX9wmvrK{TO&sqh`A#3#fdp8#{s- zUgPa~h@qdw;PRT|B{ROg!;7et?!==Ka^)D?8Tgs;K=_sa@d{a3^babBm^&=$KBIdG ze>Ym-5xoN1hG0wMc>5He);gY94>+Qu!e}*oFefJX1&h+bS8MG!{(V_zqgSJ$I)y;g z-h!VU*OIft!kU>$lkMM$BK2Hrs3Fe%7s)OPI%BF-&T?LO7vDii@Z5C`Q z*?G4M`3fWMl>tqK^&P@cs)4v(5RI6dF{$<|OE+)-wy5`hZ<4i*nyD+Zn4c{(%czX2 zKf~I51n0p;6j%3ePc9Oj-v5lR&58`>$Ny5%b+Jf81X%lAVFw7cJR-FZkm?fk3T*oB z=k%3OW7AbJCfj40+kr^Gf}5XXivxIRYiuJ!s!)k&ghYy<8t|*YoMK3%Ck?FFU~bhEe-MX4;Y{HS>8ajdtyS|HiUgp-F!C}rE=lycn@5Ro!n z`gD+ALUDN%{)nnE9JEDnS{*w?1;lPxLk|j`L_~MfF%w)Lc2^Y|1g*N2s`s9GL{y{1 z0Aoahop~{JB#J%{$I!JpTnZ)DwdXO~aa=W&CqYP9m!GIhZmBzo6>loRYejKFXrGyT zMwF@Rd#iL`2@ipR&56}I!S+Tvp2xN@v%U-mjvj$I5lIh;2=nv42NT#xkxJcoszZgS zhbE@U(tYHo+(dV_BtDqPPGCdthtapUoTu1r6sDUg-3E*8I|ai!xxKhn>w4(wD6w?gkERdFDBs|ruQ z7~Z-cqJT4}iPAs@w6VQC_767T`;ds^U4!2tw=Yk7TrI!xd{S*8qF{yl~q>Ja%;V;|WE59zsXMN-ay> zx3{Pk!RlMsrW1z}m_~Z#Lf7V5b967!-?*ZsLaTp#5`&!1trCe`pNYfL zsPm}lw&*hx4}%?i8!r@QVbeAuC+hlyleKGi=<^E=zh<6d%PojG*Zy zDxQ{rM3WatzVI!^DPVsDT-aajv52QTst<#8A|g02x(*`}e3HyUr-IUFGm+;ssJwgF zE+yS27f(iOj@)u=EOw+}9nUT9!s*N8Vp9#n%qDF`>a`R}OU<89eEo3_%f@0gbP_Wb zwpR>oH=RVb)|B^4TyS`fR(h?!s3CPH(cCCW-r_Nm|i?% z!&M}BIXE1FiNxV8Kf;=_U5}FFz>j?&cdp{pp7YgxIBIW!F5^uKS_RGV6h$Vz+_;V? z_p4jivkh4|XD)DzZ9iQT7=J2hnoK<@`u9f$Y;KLMG4SyJ+c(N^wetoC%T{aVP`7v? z7(Vqi;ss@NyNQP0O}w$q-5mDLa+pZ z_+}s>gW)+bshkI|q^f~5*%zp$Ap>i+fKAszC&UM<3Q=M~|ElB{bsL*ny^PK`oie0e zz8HJbsDhX+8#C#_1FIuc!L>pmsXT9(=9HXAl;eN505mKWs91y!>f{Y)r1%d0bJA?2 z#tM{C&n_ss@a)Y;H23bzJvruw-wP7@=;6`%_&(nPnqXR9}| zuv;7KHnL%OO*Rsu?JDY1*}vAiqghUuv6!f$kBvtw@-XQeBqmW8=Kz6K*q*=(wFbd! zm_nXWyIV#Fq|;K>Y7*^iD@GX~@b;tuX~&~bDKqA*YJKkT*XmIh-+hp?BgP1}FkOgB z+w8Z5;*@+qlsnkO>|>g`P#=8_H00UfsSG+@?`mjuo9)Ys(9e-1a5n60L6*NBqYpT9${%@8X(znUX`-lO-GW;@_SX^@eF(gKR1^?8Oy zbN}l{hl91VF!!JTAmLy`#hm_PwTC@O7i;z*Xu;j-Y&h!O6C0uahsJ7iCUvM0Gn)NI z=oZnQI)3tfvY^cfpJ#jz{tLIEa=3T~fe_8_)H!?hr)&4_o%Sd8kdCdUtB&nwU6;P2 z2BZvf7l9Y@sc+&niXBg-2eEwjAgElA>qBN(1A4_EAnse0QjPiv!4XW4ewn&8%HXA+o7SgdG`^29KY=%{3GWJxq)m+ zh|cZOifsH8q{6zyS~>+a(mT^i^Z3__UN!zvA0R?Ws&+7sX&$-B-|=WJSRK@OGb<|p zgJ;|S9cGJf`b5|(c0qgltHUR93g0F=8aa)`M1l?2g0oQlCec3^Wlh4-gl$soWa?`I zlda^Zh|J=KpCSl!G@#syO;Ki?e4$Vytrf=od&TX?WiN6&o+==sQw2?(T^P5^Y(04xmLbHyTZ^cAtYSz~S`q%&K!dOQg^F8`_Jb1rg=03`Zk~Npr9arz=sRo#4l2mjagH2!;Q2k#Qi@*li31eg#1}w z01dV}>kIqGaF1P~Ke;KVw7PMduiPzItE^?Nn{JtyKP;RwS1G#fJv4@QC0AwfT?^C8 zT|p;pKY=DGR18>v!N#XNE%inZ3~;3ub{T+SgE2Tw9Vtla+qF5fE`*iM{xzXfdK0|3 zm-qp%X~(8k(Pc9m!{(mW_@-pBRc>(li*ulLl_Dx2Yq8IlgIb>PI-?o3`&7-9G^-T^ zM{2P27&`bB9`R~7q-4nlmRR5YXZgTjot{p8-?9G;SVP|_uQjh(o5LF;2j5U9AI6Qm zcS5&cXWc4pu`5+{%lQYrhaIksB=5m8>Oi%bO6gd{cx}&GK=zUw{$^;mvw^@!Y*2C} z!mc1b+QNkat8{mjC!c@@=DWlvT2L>a@qoLTmnI?0o>U;V?6$g`tH98KKB9jey%$lJ zeE#l;_M5B=jZ0UzOd>s<*lbgM!j4V5ODk&>Mze^8fS|7jgXx`n4J_RoXuIjB8hI?& z(t!>Y?=L?)W7L!xm);{84{Wwp4u`-XE{P!awgs~z=A`ss%f$AMhP8{{L`kyiNxgHVj02r#>H+biW9!gaUxbsJtz6yc0eoOSVJ#yyWE|;>1Ig zEpFi@D_Aj3xd8&7MbwX zD2rM1ztcW^szztM8-v;#wB4DO#^u2DfA{+>t(#S{rhw<(k6$ zQs&9B<=pzz1;XzL-R!Kq!wn{1y3qYaxb<58kYDk=&QmEWcjx}O7t-U_7GM7UsI*P{ zn73p!l+4XY(HKAUO#Ap+k zQ%F8~vkD8O<7d7fYl_-6G3Y>Tt100c=QXV(Ytr|~7}Nwes`n6*vImv|j9(vodQ4$D zz{g)V!_mw=Q+jH8A*zqY7&K;tV}{IbaAv${RPZ`+Q+`vauFH;{TlN!iT}jPSVmyT}B4$im!?S zhpeAhh0L~z$+9~tq^yQ9q6n?O7DdV06Lv)<<>P5mggR5NyIPKC^O-7ryLX+KJqY=q zPd%#bX?WWBu0h-FLF8fl)dBJ=FK_(_A?$dT!?BHKF(Ywh#0dGeqP$g;&Flv5?v0eiDg8AW80&tUig4Q-Nfj}`&0%I44`ub0woFu0dbnID%z|~?$v1rz-Si%L z;H$cy#R?97Awq06CxKM}AOsW*6zZ@^AhQI&$l+LB@7H^iNg-zh*ANH}U2WzW$ ziLFWG6yGLm>x!Vmx)gJ}fal|p z#%ET6eIhbG-sCfbD^ibmBp&tdmfcFccuPfQH=>gpeXMG_XE- zvr%l>lOXu$_t8iF9$5H!+GEgIdgg`q>VAriL3`fyNchy!ieG%#7)D}wK2!zuw=)CJ z+zMgS0XFrhrA4tau{rQtA@;~tl_k$vLikcSgY86b=$**sDs@EBu53E=mm?j^s*~Y{ zmzmjlC(5HYP8EaF2DUdM?7(c`Z^N)m?pLPQVa&)`s#z`CTEYfdyTmHcM z=h=<#@*8Gp%6Xj@gXxfsQ?)^kvh*nwr3{=dtra>2MJDNVcp1f_BAK2cyUlneP5IHxS8Mk4al-|Arx{1-)0weX)ZvgtC zS=l`bBkrt7Dn^Afn9DGUAwFLb?dP*qt5kk9rXf&EQW`O5I7Iq z+t*uB{(AOrBqMqkY5Q|CtPf}Da*}eiLuT}@q5V;eKI8?-yu;*Ij- zm5uuu!O7yx!3y_hqS^|~`G%k(BOD|mmQ<-me$cxS78OD;qx1Ag*hR|8)&pJR2ea5m z*}sun#kXh+uOOha3zi42zM$T9z-x+Nrs@0?2e0kK_8vn3OF zHFpm|WR!n2pE`D}0~1kbH@K43>oF91F(Qv=$g!fJi#SHbyAnj!ra7q2+w+Bm zC1h)WijQMc$Wg4m6}2BQ2hpu6FX*q~W2zk(y|6M7G}wYgI485o$60cXm>>asZi~r< zy|bA+h^2T$+SJ=Y8AKB9Mb~o$ihW7UTF@cBY{b)_DsAt3{5#3B1ihWnQ9rR$=s_Xn zfGpA9o=t{mU08vhQa$wd>#N3}-r1PCy{EN4Gsd~UQw~ul2D59yQUd`ce#W#Fv9xz0 z>PMta-!b@fE(GQ$Em($Yu{?x2>3ND%S09bGkJN&+>y;D1fq0~}y`9Tqwzz6epB(+g z_CLFC^fu^p?~Iq$vmd#}ag~s;S7iY)ueY4wyqHYwkH<9u|9;_-vap;^%ncFH)4vn{p?v#hlSmZa>y8vci*Av}DkueDBb+ui$P0fhs+p%SOWypN;vZrp(=H;&43w(C_r=Q~JY070!EE{$v04 zk%G&U?;ubPrcDLcI}^|UVDbaI7ECl#IEzyP9$3!|H_Kdeh`X54uhusFb5fApyP@-7&Y} z%s^<;pVG!gxEnn0PGmI+wnK?%&_tf!X2#JGLH7>HR;Hq81Sn0nNK1xvvoo<$uQvq2 zCb~TyBZd}A83NEtgFd4d_%`BT&A|l{HWxCJ{DP&Tg+gSXWrfveB3p~jGy4)|8~vYm zm32keXo_b;G%c&qS7WG&2mfJWwa(&vx2wCSB=;B z*`8C{1x1J^Qsxr7_wL^l;JB}>+)df*-(?*8cbdk%6t`M*Po4?gINpAsRNcUC)HnkN zO7#r0|4SBRcAetx+a$jHVtCq{akdoAN_6n#Fb{PRl{>6q^$aSz8Rpeu!dORfc&E}i zr$h50QU7vRAFY!$#!wk9?-6&4ygh*jVK;-_+XRO=B-0niM|Gm{n53br_eSJ4CXufj@7{%%;ainAKhTkrb{tqsK zOm!lqCo>=QPX@}{!ot?noYT63WUZ#EEg$6y#XMHT8(LFdOZXC9%;*rI=;m?k>wPTc zXWTX&s_zpV3sF1o!Y%IoV-T6XT2*786Z+$#;*bV5l4&R%_-|I8xh%x1+O~Z|!I}NZ z3^z+#o?;%0<&9w46lp~cD#qx;XH9eT1Q~7=~B+<2l zV(k3GsIkRIKjP1G1yN71L?Q3Hd)?w|wp?ZYz`2Dm{=Cgys-h})yNSfqyf7d6E4%NE z=>9q&l_)$eDD9ME>wT`1;w|SyDwX0wjyO`n{pn`qEk7a8fm8d@bh}k$h#<(P z?Ue&}PmcgYPt*ZAe^iZ$*4;zTMT;^o~b z?c~pVsjY)%FQ83MDdpE&sLF_ODk;?diHbbFg{NE0c!nOD_bt8tF*W<*(t|?g&R_U| z{5(PblfabqGQ50fpL?eHfOx06g`sl?=$O86t>ss=;YNa9nivF-1HY2bnajfU{l~ei^~{>P-A#s9FfWK4k#ID%tK< z7_NKr5CJ(jN3oT28Fxz)3_iad7WNA{uY_dGraW9G*ca&cPx!n&`k0D%W^fv2>)p0K4g#%5z zgGa_39)u*l3?0vDUF@*oRy8vFk?#eQx)Q}d{!oQhZ|8stl{q&7|4I*X=wt1H0%-A) z<5hHXbqG&n-!BM$G3eca!NuhSVl<;y5g~@AL0t@0d?>OjmkiKq@r1ht?pP+DWDJx} zZ7l>RzwA2O+k4PQV`-_D&;jSp^`x5b@ z^Q)+>C%iGDk(>!F~MoOJSZZ$?Iv^{cFCOkP?q9!mio*863 zcN#y^6-_4TKt02Lk-Bj;e_w+aAQq?r%tOr61~To{XVzyTd9OQ+-0Wsp=@-iKmcwm& zsN!lEsh*qgowdaWH?n$+PBld=epiY9wNw#eA?z9Z{qbInV6Ilu{@Ap{oqhfXpMIr8 z$xdTJs>Sl~;Q`k=$8d=~3-4A>78#z}PajjQzK=XUQu!X<`bA%Q;$PoxNm5&cN9hti zjPW-QK9J9N13y(9r(yR>EyVMArVIaC+~wP5i9=eIwYqdFHT;1dbysQ<#{Tb9P1^t7 z*PVXb#`-zV%8M&9^~{|8hxx{6f$6B3rlj;&dQooyRKd-WpO&Qiu6K6}<>2py2OVKb z1#1=iR|IYYlF<^aSpx8eNe44TiF&EXsh-kHnBkf+fR-ImhInKCC;S?T(pwY13Q9@Hw`4QS<){d18S~0$6Bk)$-a=FSYt3( zz7!8f8Ne}yUBbkEG(nLbs$v3bJAO`~>%R?DA{iaVZ=Ce=L$i)-ZsK62JwP+~_Mj3T zn@Kn1qNKKMLobU!cSvL0Qo1VTpvbzC9EOwi2`UA)mCQ zk&)1-5qGbsk|v0p0#-Z{r=T&h?HJ})iLFQvd;`Q(B#63mhrmI^*>p-F$x%Stacq7F z?@Uy-No1QPvqgZFo42F70}WPDRHJ14fo?*HLlQB$YJ^XttD}yQV%j(QsSi`-cH6q z@-o~_8=?WYoH`i_dVyFxmBTT3%#jEiSE*s8uvC>!io!D(sOqB&;Ur8xlPQ7mLN<ihN~C0o0i7Ul+p>(q~e4#2#8^%#)rbVjZdHhg7AP2jg6FPKEjMwy2nXd!szP znP8N)Jl87WSkt#HAlJVN?IbyXo=^C#8GMZm7YOaQ^-$g)R$sx0b*6y|loT_#w{<&w)-bxw6tDfX& zwi{LHFzyT=ki!kkV^l6?j*^}2H9!a?GZQ-k8<-8z*2CE#dan-VzVG1b=C;U!Pim0) zmCM5A)f_Lm@u=nTc9pcELbj9tNS}&msfg;WQ=x2UCgojE_B>ihq+vWc@2-uwQ5tE# zFrEm-3-S(yun?Am*%|=PnjKX3c-&Q}iH;;oxOPp;I>JjoLe~K8+tvI^MbfHp?@g`m zSEn84cwMVh0(oEF_a$MD2xmSf+LpvUr!w@(8UiOgsd9iHG}=eQW4f`@X>Ht0Pag|O`S$%qVd>|K zkJjn)ZtqKTuj(upjp;)>s^sn4 zJ8#D%(+994u$SGcu=MX?c4`3C5P&`^IIeO`j7$GMRO&*1eH=~ZH=_2Bz(dLPV-ks` zwqt@M0crqTV~OcCG=LOL~Ju!t_i6`YkdZpt^`enq?U17)V`FYfk zw0gFrt)QwXX;E7N<5EAW4hO`={gq%Mo9zn)+jc8mF{Hm`ev!t7R~IeZ4jy(|TCNfL z^BD9Joi5Z_4mauL)@3D5_2gI$>U8Y(!m$3`kS5NF3k8LEBLS9iXpr2fIO-4EMzNFt z2O^+0sp7+o9eig#?@!2xG)4f~%A$L+B>x_P&`XfucYs0BxgwpX+{WQDWNg4|i(8Rd zTKOx@nkysL_#!4!^l1t}r(ioD)_in41I-``3`*nS08mV@NRdvXcsZTMb_S&$GBGzO zaYwYpk?hT6%23LAY#GcZ$}UJD<8Y(}nLztxoQNR@uc%cik%*iUQn;l!N(Z7Dk&L+h z?N$oq_?~t-)!QD#$6O%!=;0CmWk?2LDg{7)Hwc~2J+$29nuu*$Awb<0BT^zU z6k!tx=ExYtV^ODA$-*Rj5)>!qCXSu<~DhD-tox>MP~jI1R!>bXh$l-AP69MSw((q?E!7J2)LL(gJt62_+@ z^z~sKx5l6srfc?1ls}jxl+y`20}=n$F4?4245cJLAC{McS`?8A+TgUh9H$aXkYgo9 zBDVc5cr%45YU7wI(l8K9zTFut=D*LaXhS!)Dk9(Zv-gu&;i7=uW0VYj=Crd!?AAx3yDbWn6WgM{7Pa&U2y zb`1X-8q&B)H=YM?cMWaN1kWo8vzN)sG}Qgcr3hOuU;D5bw?uTW1brU9W$PDzTIVQ_#*s8%`$@OYE8{uAJZESQMuGAZoyM5cf5E=U>C7xd_u zaR`Rw8Ht}itj82gJO&emTYm7+bpPy)zwlcCT>_;fw4PgkpHkfzZ}U|Wl#$?Lhw!&R ztMb;_x+Emi<3k!MRpg5$X{D;vpz02?r_Rmk*{@x@@PF(}`x?5Np((;5cH!eUtz*fAg=$#OPRQv(B~IjiUsxe(?^6No{}!um0J3!77Sr z<^%Udn8>F~Eue%Ezt26|%@821hW|sR6d3!wHPLe~l$yP;tgwqizz0};LX&}`Aqh%$ z73l~XmmGN={DdlJ*b(ET8xMGUahRHj(mrw*RGsN@aW6K#Uf2s!OgNMujhOO`1Gkt_ z_UQ6LIYTU%eI*mgkxG+R;Ds3G26<7LS)=Y{$I7`z=`Jd8a2D9=t@)TZ8YHf;-Umbq z5B1YFy=WhgUN0I1({2ThFkR`sUfto1Dgy}H9q3UF-Za^O+|)C0Z-}E zy`7SDhb%24>Fk}#w1k3+qDVOjrc&(+LuGf3SYB0RAUaVS_kb2=$|gc~R`0l2PEyjI z&=9`3VFsCcP?O*dB?#gLu)2mv8N-?{M*3C?d_NF?#n(Hts4OZ~8Mi>?m<@;wEREI5 zSSG96S!e8Fn3!Ek6<;OCj!8?-a7BFBb4|gjP}xK@YDW)@zMs+zc6MIIHqREgY!R<#U|s1$j$NXKN^ z|FV$&Q-PZthL&$jk=gFSV-M>ox8d1n1*PXFE@BK2+X6~YMmDdBa@jIbOLiDbb(FmG zcQg1&(|XL=%G;N%MN&pjLxS43P#cR~X`bN_PD@_$)DmtP7N5gn!$;{T7y?ZR-_GKz zOmC|^!|piXU^P0C4>w1002^5@Od|Sk6V^(V+w|Tu2b0(X!1B>8`eF!1M?#CspX^Kx zdLM8X$;x2#c-@q332}*B@?9EGOSbXmUV#Bz(p@;rU@dW^#7s^JI*`Y`K0Gz^H5xAR ztr5_)O;`qDq7m{|<=V*2_)ZKaorDBQy4nZIK>Sf;XRw8~T&&Mmxk=LAGR`3rUvVVM zRWnwKCNwZ`0a#wlsxy#83CyrECba)VW{V}Cx{>oLt{rQ}*;hZWYKl+K5^T9khPRsY zl^+FQ7s#qQf13DCj9l#8@UNM7#Q;5n>&xXOxNS&_etusl5(#B88{~i$FLN!=iieJoWM!UP$Ja|X$J^LN%Ci$NHm`$P8*SG#;(%uE0gO!07 z&sZhrrR37#+6}|OxvtDw)ExD(8O|>b(}X5a^oekVr3mMy9{OVi&OrJQKX4yL8sWuhc=Pc+ zkPp6DL6Y-$M;KHy3nxL@+O9XV3lEQ>uo(@(#Y1efP#Jd>sW8SKbKrC7DIpmcTDKR< zX(C#f8yPyyX0z*-=mt14o;?2KoogH)8ddA0#MgLPOsTq-q~MCmJXJKMHSEi7xUk>C zS6++cw7dipy9MQCbxTrrWTiy!eRD^d(W-r7dM*-j=_uhx2@~VMV3F=_`nWQ96_sH3O85E)X1yDkpb7-~ z);D?zg1JT_vvmBdxc3i7`y;t%6G0EjOa1HH``-9x6@uwN8~jy~ZvKl;xY1U02yAwo zt1hajZUjN^dQXSfv3t{Kr3UcT|E!U3mxkA>U8x1S=&A8hVVZ$H`#9`j$bqDIODVE-Pab`>l| zdcZ4(KXA~I$9MGy#C<{_gSSVWN4N{D58n!?B0aGBki%1@!zS>f>SnR)c!# zo1;=3j1<*el;Herq#{EoNSiD^Y}d8D8sF$WixrFT|HbV^3t z!Xn@16xdbNZq;mrUW0Gfl5X)%_(6NUJ$zk;RFh0aezm2^&7l}fi^G5*H`=zCZUDS; zq_`K8*TkH+@Z}tay+!}~nc%!19Ya1J2~IgPf5QG!mTGP*XO~?x9g|3|J&mpLHjQPx zD%mlXM$F+^o_UPN$yPXMC!WkNue22mT&z2Klvz!9{$E-Nrx-X)Irz{*Y^-%iC>8CO zSq>%E$BiYF{*2M41@=iaIV>7Ase@&d1Z0}H%@NYG_!i=hic`{K@jC%&JfF(==WEoC zviaI*pKVLbn6CBJI4yw5?5Nh#baAl>NLzI`IPkvRmWxlokS?A(9IumbzNC%RL|NOf zZ>O{!IUx}>G&_k(?B`v>N9*+T@$=eNJVjJ?9<5hqz-XPRIt8kN%Lr{&P<}v>BCOPU z0Q(pEr^(hu2BH#g7F}tkXQr4^Eeh?(QWB(RH8>gzWApNsO95VFWYtGu*YPWeS_d9< z@(A!uNd%B`E*9ZRnr}=ga>WC{4vOix4$kb_X?Ute&2`J*MKU!I zPxVl6Ya3A_3r!A45|J-J7F{Q00s2=IIX(rt=9X~#n3(437yaicsGK{SSyM!Hma_=xXwbOPBA z(A^w_&9;+dbSBU^Ln%~TINs-2L0Y{3*=##FY`dx>q~@mFTg}}NBRAX3l$O4)Dnzzy zYGQt%?(M1t$;~7~hm(;;TApB0NzfeU=uZvc)lQH;8?LMjT~(5p43m;~V&s1Uq;c26 z_<>@j7QxV59Jy19VedcOxI#TG$=cFnv1A9zI5pj>in|D3WQ?FMyEP|x>s4Cz2l|pP zK_d#bTtbT#JOKgihWf3e5LdwA`Ah>RPQ{dE|KZD(34sJy-1Vua`v0iVMwqM#HWRL( z3=`j|We3#$@|wRwhF)u?bPWATzjhq=c$B%M4Y?Uc(>=Uu<#(c0bf1I74{!`cUH{M5{ zYB#q%SGVxAnhc;>uu`t6mO}~&#VTg?n7%=UoivL!Yf>Li;?XDXJlKkO$qq!2!uYyV z@U+A2YvIYSyAH|DJkgtp4Rf!rVyhF2yJ&17B2QCy(gdat@MBFytaQE9E=7JlYAcc% z%~BXfXO`cTP`oSO*5)YCHqtrP;C)FyPNo=3G8%6tYQhNVVw011MIs3RO$Wm$kimSm+$tw7H#;JFn#rubGJ zlvq`Ou(`$vx8NBP6N>p#y>$)C!`ZqsC=vz;At42tNNAlXUqk@;7!l1WGcpt(!H03k z5UyoBjg_FKV@{B3@1SMy1t2pqyoGF4ou!cfJWty3bcre$9o%ZnykqmkED<2Ep37J# z&@FlDV08dKD_ds=~8hjBtxs|T@~lb7qztkJe(jWl~}k&(=! zumTE$rA7;G`fG<$utI}AHtHlRi1$(ORa>2d4{x6SNpx~WSMU{39LoEl&yk212#Q|s z(x$Xaek)>Yj<92qIj_S#;)^y9=sHGc9_}T5D1)S7oCp) z%%H^wSc!ndo5GlL)`}mKVc7z8J+s9mZtT71`etl~q2_A%-r9YcYBOFqP#Q%ei-Z;o zXG&ct%RS+K{813+D&c8vI8@mp(p4w~PZMfX(2Lk|*cN4wL!DtFL@l(W*$y37W!nW? zF2IeeB_0lesc)5vuD_&Bv0`ZHFRA_e{Xb2oUm!DxW~hl$nO?nff3GcQB^i#v!ec*PMLno_ zF-aYI2|7+eCud!`|M;q^yNMha5_G43Hw(yVbP5fsq_#3VhO0Y*aaKvWbE>@2FXZdVok>9j^(n1H=%+4jKqp#@nw53NM)g5n`$9-x3pf6r zpmA-HquD09N3yY14s^HeeHe8&4`|ll^#NV5hRB~yb1lfJ7|)K%HCRXY^+HJi?2w6z z=&CHqzVQGI3HN?#M1TAZ!=XcK}?r7+g&k&0#{+C5KU4^&A{iWJi}7 zTjKqwGK3SI#*6FHq~=F{nTG&pbMI)1^VLm*dok*J!WVjw$M;a+;uPlD_cJ9Kg+>uY zB$>k^y3~!6dT2VA22K!^tgiYPg2}@CNBSYb?&gbc!BcqBfziooK|8>{73}MZKaI6p z6_>I_dWBz-L~WI5x)MN^T+ZtfM*l|kY-xV3l(?H(*86wj^z3AK`Qai|;#!E;)U;%6`~)Gsuhu zdK2rlK_mcB^x`pTvXT@iOj%lUKEDym28oU~zaLcsOV@~GNv6oCYTS+CFl~s>G?CL( z9+rcTl#!?%GC!NIYXRt9B^(hC+-4xe$ZUp6dq$Hi!Esd-2JS+W_F|kE9|K)13`byT zTHt=QzA3u)4%LDoaT9J~w1a#Qhp3Yg%9)JEI}Hn=s;K3Ul~&R2QU=uD1kL*0NBnq5 z-l{J~-*bXTp$zuaBO8fAE?kFl5*a|*=VUVnfiQV%bGLq`G}bicArnj0fD8pCd1R-) z;i0avArFLB1q38T(GCAN`tvRs(I3RbEPx)h5Xy|+E z*h|zOtM4r94hM(6LbQUFpN$7Yo71$*uU9h=G|wMva(q9l5WYbpi@j_dp6cvkYs z_ph3!D)ku|9S$t7_pp%?z1afd+ZVC$5v~&5_uttid7NCRhfAAQhM&nr)QDG2ycG6e z<~M)w87Df67zDhp7@ch}gntLJv#8Gh?udUD^c?6L9f!sAt{vdps?w5fZK7fGloW z4d><;bXmri=6<7LFjWK7 zOf5N3O(n#f~zkbH8G;oAkfWC{ytzb%EB&gVi%4ekc^0be)L=lvn zQFSC;kS-M(f*7_u3zMMoWAv{qbvpH_!0VtD$`uLIapdlKBkCN|m5ShFd6$LyT?k=6 zI_=J)(LN_S10KX616gGz*N}4GTSXHme2Fk&Sx3Op%70>$+QMsweLR*o7gKpdN<76G z@C*14m$L?fus9T~^_0Fl=9^iyS;^_6dvFXYxK!kGT?R5FK!!dxBAbm{;4_iG_7N8F zI43{efhAHNKM+-+4-H9J_%|w)#)a1H}xzJU{6ajt55Gj zj<$D07sRiX)2O-vm(>@Z!~B<5mSF!$yFUh6^_o`SU@15wrbD~M<0OV7TLas;6VNPb z87s!poSh6q#5Q0kKioYi-JfTdGkerQl!^u$I)IEHpeFM*uJ8e}KxxPT)IhO6;QNl< zm-Q%*Da+Q2QWvv=zhtS9*HwChOGExD9b1QC+ALQAtq%87AzTL@kqD)XxYb zXlY8rz}0p_h_bx{fA$Q#&57)6z+zL&9o6`XJ$44|IZCNKB*214h`*f?dwP-yv!D!} z4VU5fkH(NB9<>J;qc1yNEpf2l{{{0vXp&RN{k|fY!CHs!% z=aJmZNPtr}yW_$nb1!E?+YXxYh7gj}lF7b~JrFFHd&dwT#UXr#{M}uv0Kd~9L!}zz zhFZ9zd;oSodcQz(yb?hlT5FevMmC;SFG_j5K1t~rsKlxA-~YEY?+Z_IlYYZc09Bn@zU6nR{ePLC7vh4E$^}o&CR8ZJusYCKj*n|VziO6&(R`{UILUn!H zQP@%y;Y?|l3g5~)eu8XQjc2KYY?SkEQ^8ORIx-cb6v)231ETwsg{HiX4d5@OMvrx! zaILx=srY1ofxsg1X|ZAwjY|Kplk()*KCR_Yg( zN719i9=GGG&`xKP@F-c|3i(4wN?+tNd^r_Q3wK1JS+|_@5wijKrb#{!dG`8ft}YT7 zre#F`d?g8jV?ObVQ7l|)uCbsg#ct)ucAk6FIf3If3!WMK-zx{sE;phNe*Nf-_>1Si zP20nLgn(t6liU*&YCSfrT{~<4_dAfLBa{>;HyFr3@_yZa=8Oi{ewC`i;HQ0C+1@TW zaQN}NX!Q0&?;mYW+rJJ{7iNK%YYU2!KUf~L?Q%8B~>Qr}A=&}H@4kIuWh(vj6V!tO1unA@HpeEF|T`T5} z*JX1OAH4c`CV3Yr@5@ok6c>A}Fz|-0sZ)_kWI<6th$LqY1_sDFUN~Ueuo@0-Z8Gva zpeIaUv9-A)cxWo9?3W`}T)9T&PcKY0ZErR6a~Kjo8-9YVavDcD`4}L_Ymjw2E)A$Q zfgw8bv7EkuGW3(c)tET$@;AYTB=#OnERs*gB`fhXoKJ#~1r-%0%!7D?18gihdnlLW z-S8lDIp}9|k1H=(WU%cjO5Xgb4%|9c~ z;QbFE0Oeu>t(3A>evx*E9=VXf8ti})Sk})Zy*XsTy}#0os%OIXC$#*#=70>JUGj5A zxE>geYpp)Q!g*fuR*YOhArhma!4MLZ!IBA*mcvQE2$c)R;hOD^Hb1~MK}3)1pR|FO z6CQK&uQv<#k2#_253)Qn`*7oR-S~b3$G^{D=SoJCtQc;Y&k;zNiL(fQe>7H3{FPA#5%auFHdTRV#nDMy^D2uw z!hM+@2evoGgVRLM(1|>jgFLv!quUc$x&E|8T9Kv}P1)SG(Om?b>;zF6_=yGq5A6CJ zHexWG4Q}rTp#EqZnJU1Kr6H;si(Fg_CrK}tk_LX?v?6OaY&l+of52A-yJom4v~C@9Sc;f*23TFE8n zmeau5%A$=y!7a4Q{x=Dkc3)NP$54cIt7TA@~otf4;h>=)P^u z7DBa(0G;q@>&po^(@HraPXS}Dc5k2_`3V#M3|g9`A;@->}VPYiuh7XizXtB~nqLKoxNJSKD|E0ApAzLF^N ztQcEPd$^&G6oA5@QPgn)k+GcKL60ux;_1I6LeTb2R}0sG;!b)AWsLF0U#R__z+M$; zQX!v)QD~&}zKR`*3YjO*orcvFA`$*M-$p8EFj*S#rWq-IcRr0qf;y$C;QdZZpUG{5 zYdx{QR@U4`6&!2bpkwZIP&V&*M$z`aIG0d<3of-BG(+kvkq1{Ug|l@R1u)CnfST5=wHo{Z$hYZTTs2_KhvXo~{FNo7 z8B_}|y&!+R&O!arCDEcb!FZnZa+RL<0MDEC4;R@Z^hA96xXZBas&Hjwu1 z1zJU*#ReY?^<3E9>(0y$A_}-aY2fW+ya7!wm1%fQ|5{ty?LlU_!)3dA49(a7><6IL z#aF0TDh0ajDYU!&UwCt46xUCgbu|H2sWpw$&i%S3SrQ+eboKxKEyy0$@CM|PahHnj zl$lf1oM8GR(9gw?;Z$epQb$D`-(Xa%%)C4Ku)lX1f70|>r?W2zaTS`Lr>&6gKrffa zOvA-zekJRvz_iI}me(h5cMG;$5! zH$yBa!YpxvKV%bYo6^5M?3U|#kK5kRJ}eJ*bIuUg1B;nh;mF4;HTDjf`~3K4_=cH} zYiGyKu`kmD;;W8oPwhH$Vj?h=kGv5j?7X~Ydz{BCvrfpfGbQi=erPh1u|W?1E_%Y! z+xboIknBU{Sp>vI7e4>Jt5oE|-=E=FE>bTbocvA1oCASOQc1XhuLoS{Yi6x0P-56_ zinryct!pZMJN{j%{UH#iE`2dGdU)zlcZj|my|(#jR7iXPmp;UX5B?+N@NA}fYV94c zouA?l%WFIiijAy7uA4_Q&}3nVt738^K@f^n2CZ_+WOQaA!cuT29q4Je#8)$aA4>(L zXyh#3WXD|ueZYl6eQ*?nz%rnb*}S}(2OIlKMhaZGX4fmB6yloSM+uQ|0)Y#FC6g$4 z70;eu3v3K8cGDpEIB0zB#m@igVHPl$cuJ2!m$VO7!*O-F1v%P6=M;OT!w?&O|A z>RAnKiy)maxg^8ay7qVb!{4-B>LsVy9LH|qWrA2eT??DmDbe2c0#qPCw?V@XC^F?t zOvPps5dBzpF;@)Tfv&@n?RViUh!n-c1byWo><@(P#|8eUyhwhTfn7_!7)SC(^TlEX z4Mtw#p*SPTEp`IsPS;DuEF{lU6cgZ=gslYHHVnb->Oww>z?Uc*zz;6Z z+x-A_A8~qDuL)$GqdrXrF8gF3|I<1=r&RDZyy$hu$+dtIRbw$`^23Ex`KQAFXNqY4pcln>Wk;}&0h%SEyf2ZPg5 zm_j9pa(#5?0#wk^=tO27YVpX1GC7an;>{N4*?56W%4N(465J6Mq%&=QLX9fW(sUdP z1rZ@62n?bfW{qkK;Y7lTLYFKRe*Uy$zU^-u57f&`0v*9mJxn5j;L9&gD&s7Y!& zAEuKF9C#ykw8~MJ;l^g{_xm-tN_}diSI~)cF(vH*)5wu@(De^YE25m5DFd4=bYyR& zyB3W~DSDbPQUHr{44jIx-YD?X`dQdhKnXOx?2+A$S7deBXFj#tBDX2LIvQkTx~4t{ zsdtHHk9~>+kDkkX98xZGqh$NSar!~yIH=0}(H%O48ajU$UVZ%%mBz)PCC6j6jU&Qd z1+tO`-)2~xDJrYnepj=@7J>R;IcWA}H_EQ$yay`M8=*N6LyiW!!YA|Kjv?r+x#g~H z(lic3D!l}`6*0OOX8Mzki3IX^rBikTb&t4uc|2D9hArP}$Zcv>GQhLh0snra0NZZz zl2Xdn8BD5O>8qTgM$sAZ)4=SG0UKsb31n5RIQE$OroU>l9Cvappw3Z{xgaN}Dy+c` z6amL9xZ7*xIc4+HL)@JdxP1PLQdY@J_4D-9%U&yyo-O&^(HTW-)bzY(w~~nzv8lZ_ zn1CBXJqC3?d1@xAMb>*HN-pLFd^%T+ti#T=WWNMZ9@{aJHzIgsMnvU@1(!nKpv9Dg zCSQzy@jJ?&lgUINW;a?+kN(Df7EykQB2EmQ)BLo|kIC@z5J5%57tmCH!Zd~k8n5{#5#)>DnFzsFf>?%N7gG9;{b`~w zCEaV_(unHY%*B?_GeS;BQJ2yhzg5h1zXCk1<_UvuD2q-^?yJ6492oz%0%;)RkxsRT zj=&M=mwU2r!jwsUxtWbC38ITeXCl0(Sj$EV(goe%RbK6+2){2Nz}d}1qU>y#@ar|2D+F zKOR>rGvSWs_7HJ%-Bp8J#QoyX=g;9Y?0Y-Me3e3l3L0AN;dbbVkTHDYpc=}|pGVS` zOgKGNrq49C+Uuw%)NaBJ5x;U}9z?V91?LIu{o>fLq?}|+hR&p~jXt_M>Ur(71NJH&BD--&pkLPuglB{zdiA zw8gEWsN+fdg5GJ+2O^M`P*b#?MxvXntIcI4Wv^rbMUYCGwuszQ-}N2|rvsDP%fWqA zsVw?qHI5qmq`ql-X7G`%C0p-yd#(b{#~DMtRqC|`(rT>O~Iehdbqbe=0kbMqkJnC zUX>%;piBlE(Ff*5_AWUh+I-`l9MY3IY48-uiJg2H{!+}4qK;!>+hq%LhQQI$UbUeh ze<&_gSCuQtA(m_?F9DWE8b1ZK{5+D9q_tD%I zd4luo!G2>GolyG@ItzZp8aVG+@dUzhcP-S_pCG=5p@E7IKW^sUO<_Ex@?BUmVmk_S zmBqkhPN^IdgYryW2|}YvgPKGp7G;$=yb&@y$-+s-H_G(*Wi+4hv2Z zV+qU_MmW<5A3RD?lC&9i%nEY@8I|nqat40FYS?c%$NI0_BziJY_Q{ zT9X+U{T%pARAEh!LotweuRrbK1&8A#x(g1LS}`D#Ur9r}ii+g90^%6iqLg5t=`T=rmZ`J#BFNxonE_(0mf6if$si2$x3xbPd zwYu$(F4ifQC4^{gz4#_A`G&3G&Jo|uC#hd{4G|V%^pG{HnqUn2pGeaC1%2YxnL564B|ObDi~ zX5m=lVd>4T{l*>^m!3}pxWmF7O*q(4S55QsMj#s((}0gz(6v@GhO&={2uZh%&hQd+ z4UwzAa3^HX;YfRtN)#6nqO4D0`?J{!`Zad|KAPkgBWnup-w!3WPD+!47wS(^7@7)< z{}>a7Bd@-~Ikbo@uURPeX!_>YqMp#FI%ah|^;Q6>x~*NQ`OS^YUzTtetYYdWWO6~b zjNJ_}$;}Pl0ny2#Z^P%_9RMDMlbS(D1Es5p=}|lg%WLvv*fq8U!JFnvj@oWuYkYfA z0F)4QL1PlmG_vk&JE(-ri&&^cWoa(mqG$U4Bi#n-AR_2N_X7ry#0bFVi$YK8P_5xh zt@S|xYf~ncW?BOeHEiFf`4oEYooAo0ax}b+>EG9ZL~Skkrx(O=?3PV!UC(kT#|je? zRC0W}9M(0eLlF$C5k-fNAO(0VKW=J@ReG#ZCk*j^NQXAYF{!jV4kgtm z;6gj@XgiK`8A-~xTbmsicq4JNJ-2EO7e6Ev1Nma4R7XJA!qGf#7Hr)q#JSxAE5Y*< zT{>i4Lq7`t=!3Z0dh|eSH>ik>wAqVL6Em|_i^!5<^sW11P>sg9345`GOpzIjF+!Gj z`b?(LH_9om+*<+uEee0O4ODMR)wSqK?@Pv8m@59Av@HD1>ieGO*#GkfNsSOeqi+5F z`gNb~_mDOEU^60aKVGc`bMfd=(dZ%L*LJcS$XBY`>o-4j+bWUg3v3I)1x>d?W?vO{ z)@wgqeCvCJBrfv~AUcxBD>OfgOL6Cfb@mjD(7ObK*L@H(o?(`%AJL~7$oWSX4q!}JU85yD97&6jPvmMBCihVx)*fhch^oT8U}kDU!oiY0X6Yq!ruiCP1+?%4tX znuumgTdnbLcvM2d{&mXW+Qo#;k?pA__da#3Cz9Ux?@@j_pHrocSt^NafXf3>F1>LhtR5c8K{RkM;eWu1=U?+IuMKaokPOdI zrd7u7--)mg=i_Gb@%6t(W>l7!8A#jv&_ho9KgG-J*T;7fSQMRTbcHGpe%#)KArJlV zplF+4Ou}#UMjzmPtHeM`i^lE+Sdb2{lX;6G?}Ns&*Z2O@cw@_X!Tn6Ivu1y%i$xo2 zU!XolreT1&O&Vwp5ne$4|Z74OyVb(JWr6q6EL*ub;&_(~p$6?Me( znrNv{Y=~HMaLuAKpLJuv{Fyc+rU_Sq(=4%cn6(UpU<0YpLWPle((I1(JibX{zkN1M z?;6L_&69LN6}VK6aBd@<*}Q~xUnV1vKkWp*K&Dkxd23M`yXPc`dXMyP(|%p*od%1^ zkc%)^PXW&-T>R%a?+ksG)F+$z13X(}`qp~sh?rGt?{61`? zUC%6$kj^48o*L>n{5TljP)iqLU=R7gdN?Zupaq<*PB3!q8r?p74ul@b!iko(fSUt6 zga%vM+;ItC7u(!BTdS=X(YMaW@im?~@ibSajK%XmlG|1{&1k(S3u|iT{3M()!Z)Rm zc%OS|9bf~&)^$&q9fJyHqGr+5ebdG%&nqm44bJ; zfe^3$_}}lGOXSgc&%O)784G;V6A{SFG+!DSwczVjygdas;GhiQ3UW7zlcAGLwzIhQ z&y=VrKF`{y;qQ20JDmXl=q|_68^o}G7m-3dQ>(0wey6&MXj#s8Hc*muhLmbf-9rW+ z0@B;NsE6=xy-u-t$ybFEv%eAhcx_^!o;n3muZ`emjZ+BvI=yGPZo_H_t zoYqHz0c>0rF5n~kf>6>mkLl0P1~j*LR$Yi%W_?AogNZEXzucoSjX zW$+N5p3H7bo7I4M@Uo)4YqQJUn-z+BnPetA*?(JCD=uUlA|II6Br9-6s*$`_rgPd&`K8n83(iF)= zSqUvGSk7k_GGlHnHx27v4N_u+ z4^K7v=_7e7#xta@QFJ5-f5U$8NyoRW5wtSV$M%)*^a%Qu_sC}CN z)Y$K5t>yQ#1{=dXb%Zv$e80DRa(Xw0Y(pgA+ILMP`T+&V@0{G1r)_8 zxfz2IIuTdtCKMRck%iK8!e0`Z5fZfu01xTnk`;%b9zD={wh`1EDcDhCg{%aY8sFPy z^6D0wG80Sy+a^$w=Cy!OF7Y78w-) zTzzx|EG!VMPCTR()qp(zv43BNAM zQ0KCG)LvE-HMaydqEg;40vVbJq!YB~82vexS&LHY?Q~wJa;tAFE-_fKLMA(j=1UK5 zvC}0i8R&xpyUj^)QTbwLsl)}6ea%Q{IiyEn>-JU1S0p8QeWTHW@D?IYK*a3|=(7lI zz!`R{%*HEwS??+i%|H(rAn=$5CLXIK+xIhh zB+i8E7tXUrOfs?ju=>BrC)JHa28u>2-2%RJLWo)KAU^nxnd-`1tKV9ONqyjD>3#X1 zI0tTj>)^%Fm1|DOJ-g`tcUDR;KgVK9lNFC;Y6;o5h<6)%pU}dLY;C3vm`NV36V(ns z>n94Dp^rcyCB88psuV$&^!oQumCi`&xx$qn7mhw%MJ&|MAdp8OveMIXlR%AMV9WF< zeq|G%>8^sBD@cnz#Pi2{ayTzOeHnp1}d3VYBdr ztcpz8mTQn*RL$u=eR0-Jcs3=A97Tp>U+Q7;Ui03%^&6aSaJg*3;l@WJ>rqP>hAGiO zP$!?`z^wv-S#PI-uPc?Ab0%70j|u^n^hljL)pk6CkA~lYQDJ~MvFA54gErD8RS>M; z-HK?fn>P=>HTPl!NuOFNf@u5Ijteh!*Q2h$&;I6WKbnRFt|F>)cQ1(@gwTyxwL?ZW z9idQ@wh|sfkBvl8`=jfFj;%S~p$FkPVL(}aF4@vA3E6it+}m-%<>#wBJM-Cw8O)W> zAr&HJlYaI{Vhjl;B*7{4S_SV~PINd@BstiVz`VG(r#KYyOYoOjHK6c4XejB+lQz-d z=X()+;pQB#0WDNjQ4z>4MIQ@C4M~JmAD4gKkEUUYn<(JW)?{4)ysJ8;gxu7rWYlm| zOzK>&TNW(GcM};jS=d)!I(Zw4C4m8lBPNE8Dx}WqcNxXlV3`6UoBkDt(BxpLJyOI$ z%ZCZc^)Nb+_i(DUx(o-I$jkOJ84jlKot1RbnO|>X!pEZPLWlqd2BXV@3S*8CrGEoS zN-M0r^e4PLaZg>3 zYS6QEc^E??;~JWIppL;%z8_Z!z>3eCA$#RU*^HKM%}b1NY{*Ne_J|q8@4Hjm?j|@A z@oxgKB~U3(H(A7+HnT5WNT{LVx7i7TS~HeU@ocYHwjHRWw}fB{i)LT;NLsYZr94=D z^Awa>j&MODEN}2$1xZ4gX;?U=t-NV(n9gt>$T44|plug2TaAbd^J@PlxJa#kU z<+EfG(nfFzo5if&336>_y8?3@<$YDsjy74daAZe{R0g?Cj%p5A5yrdf6@;LjfE6ky z^Ah@goZ1~%JGjOfWTK1eiewu0*A%Gc`e;`Y|0ZN=k6C!#(2lqE>$L~FrVQ|(jNyZme z!^43;#}gQeqzo)$iuaTn8Dq6fjO1k2^5Irk2i}3%ssH;i+sqR5&rDhNqoM8vB^~i^ z54d3ecUvhRUWhe5w4)Ia7VH-Z{H+ywp?`*Y>ZvLAHVbj9%9*pYK<1zLIKOKHdtw2w z2OC6VFMcO{Ma2;DNcAat3MGw8@y( zk3x{BP>aW97*QXuJa#B`XS3;03X!I#XSzZC)cU{;t>i0-pElTrLG zC8LfL6Ob0!c6_7~Z%QlVlre8xjD`voNpy5+74WnmCQDLcS=W-<<6r z&-Y+c9u8YL9>KsLa0=CCG$EA}lTdUN0a|bLL8b6g8g6CeGSC2k#v!CxYkiuSnzW{g(TMyyrn!DA`Rip>)SH2fGf8w5AhAn3e;ln{7SjSWx;3{5Y^ zf{I|~pxl&TQ__Qe_AoO!u_P~|Sp1?76)B&}H&@Dj%3gkj$z)~2>V(CQ8IFNxqsQw8 zQiXj>^NhdR7u@54iKST<0fYw=3l9@jaTcG*R;#1=@6q4gnN=$ZRfxGu4`BdE@z>mi z2$`%L6Q!41vfr3pGJ)y}(V$tvTTvf1EjreTTQ8C)f~7w?W1ZBER&INKeOtxLCb_he|av z#aTAdM}b1IfeU(6B;p5z;a!nv#fx~y6>JR0qrvQ&z+Qts<~@(lKd6ir-TEG4E!o%+ z6rJjz8(X7p!p>$T9g^J0iNz)*BaM&hNm5Wr(LyG2Ecr%Etrw(>b5GFV?{!2R&Fave zm;P#wXhLM00xR3rxS#*>0J~MMzFUZQL2(6T7iz&Dd^Yd&iNdN7N2g3RdWrPLv&Xor zrZYdNiv!i4mAxw?C3hyw<-{!s`b-H^`|oNWv`{P$Jx1E6$YYOJz;8(3F7#GVk=vzz zI1{|zNUf*D5gXJG?qvSa3kLZ1)om->lTgR08(V`1DxMQj`%X4nU7^>sXi}X7p{9b2 zGaUzT#A$u*G@_ls{03opBB|vmoe$lEa~B zLv@y&uC@x^4__oFA_pA`pu#y*rSQFbF1Y#HaH$c010Q0JpYs@O8#d+gYrNwWkU`}D z(_s~Nh#K~gUPpXZ3NiLOdB6BZ5Za2$T;fn~q*)5=5<;T|0yrl7vsoamWSuu924V*; zu!_0$JQ9YaqEQC_;rTGC4_q6HqrEjV8(rqc8F^Z1rYI``ZF-(B!8}-%7C3nv3L)r% za@eTmESM7qER~?i|}$MZx`X6|CZwP4jDcn9a+K!vJRfPQ452$FyL+rLX%k zaV5i{RL(Pw9!Hs=NIMnhUU$`#{)+{mnC4rY#h1go_}CP5sVhy-!A505$`L273}7rs zA3v#l!jol}@0B8N5b6KpKO7B%Pw+5`Z6xCyHB)x>E&EVZ_`j+%q;{Vhi+$_0J_u>{ zRMF1n>{DA`SR*iN2MTnsgNCMQ)u0(^M-?R09I=j%2-Z0 zvk1IU3Q4T|{x(H{h3)RwsPUjMlxivZ%V_q_!Ag3I<4?Nj!2>AdzFS#^!7Nc89TSbv z++3@y$(3X|L-aZ(F*9fxGIpxx3cR3SRi?%iG{43eTq|_cdkWY$bM-G{^t-uWdy!+^ zgwn9^471M{`v6aFzz~y>5CzRdOhd>}Aq1MX+Vx{#{88#$8UeSk&v#`t9e2{a>!WG~yles2-|4R~{y}&o zyG8e`aoGmU67Ip3C#l@89~SFV1vD9$CgjwQ!)ZfI>d#wfM~5As<4 zPp>dbU#p9+UXE~hm^0gX=uT6I=^%z`Cl1xw`LTOMOxmzQrtu{upZwH4i@YMv({yMK zO~pBt%V041iXqhHn$JlIW2m3N^PjWjQosx^a-vm9X8TBNK)H0lu-Ybow$w40^mqu3 zDRv&8BHk#b2I<^%Gr5n2`XD~WF7LDUSeUPDaaAxF&*n`Tt_>S%{DcUKZgv*WHa)}C zs2~x(i30fcT7pI+8c9M+O4phtP^4H?mh8Y1w!7O@hT(9#S;Hu$!`lD{y~khA8c5nU zRDB+v5($6m+XfCY?9h`;2*^Qqyah}#AHGf=s*b%|^jYgUBk|3HgN;Zc?v50k+>f&f z4ICHBas|)8)fo`n?V`P;We(hE4vU+^iyG!LPnlOAoFg4B2Ui8npVAu!2#+FnD_&Hy z4}9nYBj{laQq5j*-CB)4WI9ua-FSz^eC*_?1)eQSX z+qXVJesFYH)P~_@{W=_a^U zfeOy~6gPy9T?<7MY%4BbPW6-${ao)qPkU9_cy8#%H9# zJnAK?98vI+T}d3FYH7Z!Df|J#AXL5MUG+A~;h}ukZfU{|i8~NDdo;VW$`_W#ViNjJ z+|PIpi}g2Yac#=9z0bI_SIb9Bgw7SdPFhu(A}ziuZ_bjeKG#bwgR_C(e$qhEcS3wE zd<~vMT*|gWb>5clI#p!H596nGimlY+&#N^TzcH^*2m+cDd*ypcCxX-}HwmY`wm?y> zGw#lT@Yi7{4_6DLkwCd^Nz>LRccNI@LWJb+Gw1h|uVx9jU9*iwJDS22id9QPk+Qlg z$EixF0;UoWAxxf9m5EK$&>~X<+Rkb49#c}s%#g6~YT5b}J`P=Py#psknY(X(EvEqb zZXg)R>*(M7Sd8z6Zuw_R{6vDV_C?Ojpl7x%Evz63pUy%Z;`Tz%IUb^P0-F{cK=@&SpC{I z0(?~9fs8aDX%LK&=H*aUG2c8ewZS0qM1$Cc6({q!W&5v_$S%mV(T_9cRehy4p$J`q zy*9rjX1)8`#u7SGW!CPV7T?e%VGL8`kL1x}@Kf^fnU);476Vz1>?i&&L+}0G#(5@O zV+OtV-aANwy?07fm#ku0wrtr+oOK*KJ=r9?*?qt8;_iE8H?McICB=zjC${XkOIGiq z#3r$m07;M_dhflL0lxVQh#xq>JkNcfb7&k`Yo-1wDXf5D$;~;;jq8~nzib>xNkx2T z1c%=B0kj`@8lv($WzM6f00OKXU}%uO^d_T-&9?I{d~P@OkN9Z1I%oZg-5qWod6R`^ z*arV5m1f~yy_{S`mV=A|GAUhqU50a$5!DW}JVm@cYZu~{o0}qymUPl$s1xaaBQ7G&s(x%mqy)oMfLi%7Gy?P$+_1%&6^R#1r`@J#LdxgbkF&Bz%bC z@uyni;fEQiCZV$p1jk>b)GC|kCuqjCNP@>1b#iaItZGKLq4eHpIgL5d-g8;q+Fz7M zEHU5Rkb9e07V`{ED4~FRv4(y+Rntb%X^|Xbi^m1zjmc~`nM+AW-x4(*KW8Tm)-2_X z70xbFzw!2yp0@PQ__$IZHy0)OBq7N`jOV_jb!k@&uFPc=~#! z_#ntB7)uQL!nqNW$sF+rXXkjiB1p1zr5Oj;WufAK66kBs%^NED_k@}XP?$)M0p<}T zAxQ~z;F3G*4kjnm#?P=l{3Qw+J+`+;?W%-l9$!sc6e&0l#oin#yKHA!)TL)6xjn5%z$ip5@;h7r-S4*)S;g*&G z(*k^Qy>!k@G{pb?PAqyf#Tq#1grsc`2n~pHl~3%DAzy9ukTh#zVLVx&n)J?~Bh>P* z9Xt+YqSz42@55NBh@OE`gqPe)=NVE0s#h}pN%tG!j3-DTkiot_ciX;zx z7~d44Dnq?HSucUjsF7}FDp;_jYM$QZ5U4h z0dW|Eq>6Q4@ll^dg}a*pCRH?f{Q7=$g1(9VNe%h*=HnNIt9|I=Jf(bmVV4oHbs!7} z)q?x7v5co0`yZ4_j1R z(}6dyBi~@{PwllJ(drwSA55^(`Y+7vmHJx(>2{R?&uUN+9v($Ab=)#P_x$=E`g;`& z@7;BAc&J+&XP!ku@qj~x7`;ebT-$s2PnCNyKAAASO=BXSN~h~d&0XZ=Ws<8Amp`Ol zA}`7lXiMzM1LX(J6}4}R%R+IeexF@_+r|^dv^~*#$l_5y!@mr$M~JH|m&|Lw^>&zXpH{&(hvLmd(%MBQ zdzQEF#y^LNM@G+izT0TV`jUuxWF>SRsddY`3U(>cMZ`9tGDsSh!)r`W26Gqz$%c-j z2a52X|DrZm%9qy>^?JGB^>b2OwAh?*@{lFW=u&VMgZ2~ziYl%k2%rs1?RYY}j`6|K zA4<%NL{mu>0oY84TJX))i5Ef=b4Qzu3HpWE@v@vH~cVd)^}ls zn;45r{dNggpB`{{b<~)r$DW?fV7--6C{GO}VP26_id4B>&1{AMjOZYj&HEgY!d^cR zL^Hg%i9&Pl(CS;^lLtpbu1Yz6qEvuq#lbVl0?jE`Qhz(*Ao(V42Yxo>fYp*S`m$+x z`1X%#d<|vvRlH?)_=^muNT@ZV4*00luYA`IwE4PE%(>N zbwXrSUJmy#jW{xZF3mL7bd*FW;&%1#lSD;Ac3!=~^=;=tMuLqV8=KQIe}Pf67&$?lBjrt?u(Vus&#tcQ<)i1?0pY?_KO~q@E5XX~sZ( zhE-Dyz20Y!R%{B*QE;{yk7rwdx36$JM=fGq_b|jj;DQPI^VK4+%&k>D8p>DfZcYO( z^r$0X`dn4+n(;Ye*6a-4jC5#I4Xmkk`b!uq=9d8scfuLN0v?n4>@9XY9ao{$kY8}B zgSYlo7Gmz&BHN){IKO}6K3LLM9sZ=cJt~R*o*YKWl?B=83etVz)KO>c8|Jd(Q`RQ! zc0xi-3h$n_6f$ENPWN6ASpA+wLrwM*ni`t1F)EJ=Ia7RAW1W#RIN0l*A#9R05niK8 zD|YoMF^-?%lZAP*y{=L>JMK24Sx(?wI`xP(pIaqkzX0fk7CIH>w$xupz8AT%j6A}T zDQGw6brrH7^~!nPP{0v9_KcJWU)R&6FBa+@$dBm4`H1!rDS=!tw>ZletA@E0p`Z|Ko2p`0qL-~17 zac`h|mEidi9A(d@E?G9N7Wd!Kc#H^M@uYc~)o;w6t9jzW*gH9`apEiEI~h|f$o8*o z9jN@mINrP0gJ(KiA9@7W)9ePYUeK1F)9$&^6y zKH`)RhMhm9NUkE^+oL2(p%9T5+Hdh+d2%>Y$0Hc2W3101-CRto3HXo@3*NVDugv&Q z+07I5kNJ`EPvkti>?<=CU!*Z6t*1s9H3z~SXrv!tG`ziG0%qqrq6-VgeFuk&&pd2= zN7t>#YX^F6e2SlILF|CKftJoMfa8Vk=T6L0FErN>JDcUPA3dF0TS;Dqa+1xZ`jOGM zp+`;h=4(x7sfidtA$xpY$cw9gdg7-qni5r*DXoNCNFYg9g%i?~iZnapO#9<3VZ0N~ zh$v!MRiIEIk=dFQ*0N)z;XG^`f(JXoJOmcDLJjKGdx>0}nls6pWkpqpjz!fOkx1E1 z%jOcr-JF}1brFOtQp%A~@Wc^8V989_Mv}*Dj(|}|W04A(9ab{e#L(urtJshyQ7l*e zB@@SQodEmH7z`n-WqPq&v=}G~R4|bY^>_enF?;hBERs7LBH;7?fgIL9!M$4dLvJ^f74`pRF|+&2rj-_Si3l$9}C2&n4;vTeyR+YO4DbEBRmzHDb&!ZRHf5 z6U|hsdJBUlo=9yY4-siY)us10T>Hh$`O>jElN#rpK^8X?nYz8j z3cEVK&~cQ*gmcMtZ)P*8%YR_nS_KYG4dVoQWwmiY`n^nbo3ab#Khaso*?kk5Z;-Kn zVbgUt^Bl@lX@`b1p@Z=nrpt3RoPUw58UHz?aBmKWbD|S}Q3`lRFn~T|x-0LxJ>9%V zf6qn>e7HwJM!k=oIBnRqSFd4rgNKQgHK_tV5Px|={843g)z%Fs`cAe3f`7kPY&dcL z$C4s}7w0Gv+d*)SkB)boXvD*s_33@A9ed(&JU@leqInW4jahSW`0qX4r07+sjE|bK zX+A7&|AEuAK`cLj@FlKF)H%8Lv`Xs0d!t`?c>vJU93Ju2wUI7q&a&F(K?D`bQmY&7 zX!8@|Yu1yi_`_*Su7;vh@CAYnSI1=*hji8uB5%YRoZJ&@|NVwEFJghXhTRy;PnrOq zkcW!hG(3RM!$$QF1$=9KQ3ujxZyv0J~)@>nm)g~{wDH;wy_E0 z5Yu^zycmgGO^P~5vwtm!@Q8i}9(6BsDEuUY#^jU{Y z+kC=R?m^<6NUT^_b5bdN1X0SKE)eEsGO3Dt9idLWzIvgZ-6eYdm!&-+_G1n2>B9&e zO&6lBM~)g!2@d?9&tUs~4h^Z6zCf)KqwJsLmnT4X-xfKWq5i2xt@giG(L$V5z(nJF zqk$O#r{i^z5=}a1ii_xPMp+;C0ecrKV(YsizDTsJ^dt8JjKuUC;KTL1EgbeRf%F3k zRZdhFocTBL+F5&77(?HZc@8Y~!>xAHr8OI?1Rep)ojGzRr1pKTp}fk>b47J0@BwBS zz|lX;f48M;;+f>uMWd}kD7T-!LlhWxuYJ@l{^B=eNYkN=uQIg{xQ@JN>3nu|Y-y!} zxPG^*RF4_j7>kjgJwX4arNeAE7_AAeQ%PeKd@DK;tw{M7-!);qFE+|{0*&X#gre#S z)TV(`P3$mu58LEI62p%8lBd*3`tTHPphecJ?q-KM|@LOuo zeplZSQDzmPtBS8rnuHrr;A+2bOD_pa&Jy6V;;NvU^Jv{e8mlJK5%0 z{+@7!kmJ4n%@8g2%27(L+4d^m=rhC>#|zr7Ra!eD)YL;Bru6S`F)^{Oy4E$HP@xnYOlKz~ac z1z`|oH(!W1NAIid(;I4bh`_D zy0<4&^A=)=7c@gQbWaPOV5&!0%pmddY+reOeY=s@$wY3i2x}Cd(8&rmMSIEdWN=Aw zJ+^BSdFO?K6e)Z@ccMLdNo&T}**F{RP*^p&DyOJ|&_|{S7F7j0-I5La7yvQ4GhW|D zVBKDF6MIPejoQ6?$Zd`o2r|2b$K{}Pi*B)&~Sw^Mc|Xm z*>Kfxjb52dBo!nO(V9?TV4HuX0TcJu8}cn8wuEgY;PUVSvkpAk2R_Ql!g+SMRBx_^ z2S(oRg;AUQ>86ZTb-2_aw0yWy-(yRvv_B}*sw!>bd^@Td!G&N5b0rOs8rqnMWWD8N zkdh&)8?SInNn`%2Xjrv)0KVJE0Q1zQic)J9E9J!Xgp(sJsbq{Zf6b?IH)dn(*~jCH z|Mc?`6XUh6Un?i7pMR!ki5HufqjXmOo6X__J2PMJ&HV%FYTI+*u8`L14T8|Ir4>#i z-T(jCtpVd-ZRN>NrAf=7Xh*_Ok6iwpq1|_-d-IE%a-i}WZr|(5FCp2k{NI+h5!e}} zGr&kYb;8?L%4BlTVwu-gD6o0mQbLkuS7MH+t~F35WZfVZnMPW*o&EQ5FG|@zl zBUDS+t}ESh#&#~S!w*smP0ZUz+Yt~i$YA(&a|#4Mr->Xf|1-px_WS25V{uENS8rs69+Sm2BG50epOp+#RN*_cns|RU4&72?g#y zMQ;P%v}o%>y(#J7<*%XEDacvG_;R;psOn_>NJU2m(1E_WLF3_gbP;5($D0DHSQ6K|5V1Fa z4yaZh!Ub<=yp8nw^6jskdI!Tu1LaevO*8AqHhrQIWe53z%|3I=>H6VgHs^`@)^9G= z6R!k|S9`wEzx#WFAT5mb%N!?eM%uCXk~dX%=CV2(+AUi9{sDs%UFxh0qyQw{{j^g! z+-5|O8Zs_Q)Di%0D8udJqzaSxI(@$nQ$#&BNhA`W~@Da-q!P>Re_YvMu`k z0mf^ZYtyUWaerfd14!dOYtisKOQtu^@%|IT`&ot%s_#L!mZFP7k1Sl*uG%g1Hf6Geii z2>blJv_QQfhT>(26LucSW_X%KlBSko_|tJTaSeu37z5jkxUZ5hMnqzZF&PG1<6q{wN;8S^Y5%$h@1$jcktfk@rQ&QIULzd%<(yd;_)B^HiqJe1Hz{Q#=vQ z^*X8&Nh}ti8bdWvhifNwHaGDL?pE-#VEIk^e`w^F8xVHr${u2EhPa+y>sFi|EB2vl zKF$=?6UU-#O98qKEnaqEI5B=xkF1MefF)6`Pt34;C-#7ElVi^B)o5L9B5>1|LM%o& zQQy|2Mim!P2<|Y4*01wgp zgsBdd{`uX8n9Dr8e(2Y7{xsJ#U@M94?NeOZML<1)wOm)h`F-wgf&G^cL^nJbl&*)V_H{awmHxS2RClh_9C;%$6{-9FNgEcg6&?^f}kj zT*EMb9qUi4bB0D!!wX^QIjuM*<{(S$4ogI!uG}|*nCp8W-h+ymK7_9AKRxDl;pLb|nHJN3yW5fgsB? zWw$58;<2!uML`n8MKM14xKh?5YnZ)Q$=TcP{2o0FN6YzoPAjWshPVZ1X<@g{>)SGN z!q)|_tFW!PlUsdQCg4zXaqp{h<#!WbE}f!3w71+F>-|CE=tI46HDx;){qFTA$)#$6 zx+>@z4W0+LZm~_u);9|ldMG?$UtL~kJVkMN|3^#d9~NPxdD7kV{ZVRA+1*@q367#t zKG*d}RI^c-@l?`9@n@gk#%Q{KUvG*X|hHe5bi@N9b!Icc~N;~YE-}BZcKoG&il=5jt zr<>PD+GVuw4T)e;ZgsO8Rh`qG4DNIzpT`t7$)5#i1yq<(pyhCP>x@URc59#sSLi6? zwmj{zTFT(YsG?nBt;|O)KcBQcOy^tGPWzJ^tMSz*jX^p&v7ex%Q>l1(vmx&%)endy zLKpgIp^=dL?8`47OurQF*2Tt=QDQxUEp?RZzFSI^xj<^_Bau8d{a%1x4Sd`5Q6JW5 zRk09qEwd3R(aityOC;|)(o)|-`e1_MxC3-v(#I!%`&ewg2G?wXpHT@HdmGTr=nF{1 zU`5W5-0*CmDexa|U*~O?{UD<6lml!Xg^CGpN~jNy{eLyADMnbj%cY^G(49M);%gYf zHqaD(L3H*at%TgvvGGuUNA1tE^E*EtYb9i;xCe~P(l<8I;ZE5y`9Fiel9|F-m3=25 z?q@#&ztz2d=ONbZWZf1ikI16REL*%3`O%py54Cirl=Zc zuuFgOgG%Z1=w$czzOCr|bO)L0w2pg$Bit@N9c|nkmS>8OKBT}OU-6{}w)h?Zfs{AA zsYxVj9fI|ai}UN;@ zN6ZbwZ?EYl?ijc83KT&~>BM5f<(2&S(}~tVe)Hl2X0OdK#LeWLTgAX;FtB^h|iwn$&j~YH^>*`I}!$phK_k8b(#!A7a0q zo0|n*Oe~ag%|}#{RF}R%Po_l}&8&u?fPeV0yd!@oQ$5cdy_lpf0=X)5$V_7&LOMra z(+qC5HkS`>`O^{p_P2te+FY#N#i>I+Yr`U+I|8{TLbL? zrl~bYL%7BMR1>l9nU0uDL5z29N?d0?E$}{1gkI|W=l8ikdq3fy zkQbvT_k@IhDKB@btQ}7{6_PcEx&f|&>m8+<-8qq;(bP;;ZH|Z(Ffu41AYIB$$s(&( z?8O>pZ!J&McB-sc#H4t4+5a1cK@_7BqQ&Na@>HxQ&C*Xxz zLpBY;0}IkNl?A7Jt^h#|Bl=qQteG8baBI>R!%8)^w%KnOR+X1%mOpcl-mvU088%%5 zCYP%V@qDyuA&5|?QBG9*!8y)ziZ?iyg z@Fo@KgRRGCaFpLu`;lvR7fM!f13r63r6nrYTGEXq>FsSg2WRj`nv(?D($Nw>40!q8 zjLlgkK1(52o+O_5dWAm4LmZmZ&8-^TA7kMusOj(`9mUF1**H`dGXc13JswU7fkw*Y z8`xuIGr2;E;v^zeb1_^BvZxRSvk-`wvVMfEGhZ>XY5x^5f*`W-YPc3m9fv78CM6`M zh;K_6B8wHsbEL|eZH27J0G3E1(z_D27;ym0FtlX^PuCfP<> z#20#WwCGX0bPYN8kgks#c4@)22GQ)K^F1`HOz^xLc>dNd;WOn0f5i9F7VocAN`71G zjFp3bjnO|y(D#r!@iG>DrKHJwnf}Yz7arVj(1`hCfF%9(cw=7gS6hP13D>O4 zKX+nq!=8Kn-{ZwPg)o$Nx!^cYRE%>6!{iDCJ}ZyrBq&>x@9TMmH{!NWMCis*Joj4lW}3A@@N>33 z;Y`uNIxJ%B?z7R-e!xpI;9o2#V6t6aiW_Ev=4{>zcMlRI=Xyo4S3$XgbmkQs*uFs| zb1Qw3*^*XIG3JN`t zRlBw(sUQ_Y9Y{i81W!&tqS;wwYsuknJ(qXl)T{>W zN=%dvDr7oQr&{Q}wY*W!?@|668 zdGb)ItZBgmxZc%PqEwt>=VjH*L!T#0P8VOP4XRcadCjG9z_;<+g3$AjQUO#I+eERv zW|(;td1zK4vk?m(i!q4i-QGQG5}hMYEjegX227!{Y=trFbI@!cJgvNB+!pMtpe*7_ z_+#CE*G9`u$-gE{`hob&;p!*Z4V~Fzv8fOIdfSd#S!sX$Wuo&b<`&mcPBH(WIDc_9 zmJwqK|M!BqnJ%JYP~^%$K4bOCdeKWOxRas-4TTjbz$j_9nSQi#H8Ck`quvGnU2&gS z9+_>p6y>6Jm*V`Dsph{Me#ijPx3m0kdNNu{Dk;(&X1_Ou^O)`<_A;mBS5Z5e z9FD2M`7_6ooQ>^V>||D8W`HTK*Yh%3@!utrQ|8Ir=&2ee2)}q`#_`5HE+CVEE=q4;uZh4~0P}wz6DBHaout0;b z-hD21uWfPJxA`OX>1p;7NBwQo!F56>ecYu&wbhLa2+6WNi&yoz?9n>^RHQbrO4iqRU9q9`a(;v|QHM{yAaxMyM=&nIfo zQU-%@IO$#F+`kf4#auoAm`}!0Jqz3Bui<}{K`q$N>E}x~n&EsLdTxT2C+HtM;Vix6 zC+kFwG;5O+bP3|Q2KOcYQ%5-BZ1WwR0l$;koci4VUAbSeNY%fS4M?eJ4zfohDN9zJ z9OKkIV-*@Tdn%gO$`~-QsWJOP=xEI5W&eFt@Gp+Ul?^K$m9FrTS*DgdY{m?JSmk zbkk8^=XD5O`?Bc7j!|}S28M0!`5))&Mezjci+5RteNQ~=(Kn}(Yc5n@g@%|+HH`Za+aoC|t>@V*f*m z{$h6FMD#asH`7y;+dtIZ{tKD^Ra?%;DKIUiNunaS>GN`NmL56A;|#dDsxmj;OE1x^ zhhiyWqJHr;hL{Hs2g{?5mm9?O>A0!Yx$6p153Zq~(Jd+o6-|NgL>9u{r8i^tCxWzq z#MxR)3CdCLFOa_|R9fC}&mR$sg$e+bxTE(DJRD1Ul8oti2A%9LWb2L+_5rG-M@gB! zJPWPL{T?%^li=Iv-q65~t~JTS#d>?7`nDdQp4lc9V#U~sHvA>E8XcoCK{7kIldv8Z z2IC=0xMypgOCCyQ_K|0`yUc2n>8d==DkBpVWFs^JKh|GB-=Wmn(|0LZrWA6_-CBoX}@IMb6zn*nIyY zV{gLRlg!RSg?5J?Mq{-8z2DK9Sz~&!6hWV(O9-(tV}HhkJYt!l{M+Sz8Th~QIS#QR zT;ei#gIQ9;Zf50mK+p9tx6`wGuX3^SB}4#S;~9=d1a5cJPri6mkTZc_?4o5h9yD%S@-r*z!gw*}`3!!PX&Y9pYKJ0`Mh_8R#WDU z>z>7xdBDA!W1iuiYRYpTcBc|gMseh_5nJ>ARH-5RGL#O{Bg_k=LcVOwPSir!Tb-W2 z%q?H|L-!*gE*|7pvA+@GPVAUWUDpO|fxhaBx4pQ-S$Mx%$T|-Uw#TsdMLj9%Uak#T zcKJOk#}T2mVwH?c?o_uxvo;r$)Qg{ly8BDDVgjGf3*q?ba+g}9=_ETfBbdHQX6P`4 z^Cr{qYAp(B+6tw8#f-X^vInrvFw{X!;lwopF@(+`$}3^t1UsL`)iI9Tby0IMm{RdO zaY9xgEi428fi{!I+7xO29!Tw_RnTIokmbi;>r9Wa+9#cR^N?mbOQ^NkaP?<1;*QeI zdt?S`oP~Ib(m=gXI#IgIm$5Tpa1=QOWhCs4daAKh$9rSt>w5rYQ&Avbi7B|R+nT~* zLhveIrVxn++-P)p6&H$gDjISGVMXDcZ$M8L`J<51yY{=c^#s}`_gCxz(ysLje3e8& zRpK`COYcae;FFW$*K9AJUv$>P)2H4OlBQb_o>*&w69l$1@YmeIhvsex)_E|~SVGTRBRX$HL3A0-JtJ`BBeD0@>eOexut~m)=HadTou2HGc z`AO8?^TN9s2q$^*DbnB=obk~EUk(E4l|&z6m!1hlC{3ukX%=rUf2436snh+@2(v~_ zxtoNh{d8FU!%2rB>DYD);SFR#Eq*NE1QH#9IX)X8Py*#A0pq5hNiI}w?OkTwKTDB} z3M?Hi*xxt6l^QYxR4%W@37m=)vYZ~KD^Djbe_5i5*w(uqhaIOSE>sHzi%u|a{30bD z!_hN>A_E_6cK9UC`C_RhkV$GW4T=wZ}( zr&7F?gu7}R*y>o|=>wGV?wM5s??1cA{6e+b^v7N@GtHbtxc~MTqh-n8c&X75{en_5 z;)fb_2l>P-wgnxOtUb;XM+t8!{6)gpPTs{ZAB~sNmFuZ=NIBvh8p+>hx@5nGviEUe zQxmQ3fAjA{hFkA7V;;6DkAAbz_zI7@Q(#$x>!ZXUw`Anl6oSwHxJCA_9NP49@BC-9 zdiTCx-^OLy^G|Whq{(mp>2FTazweyG5?sSQodhYjpR2{3;|GL{qnPP4VEX4P@n=v= zZ~2GfqR5?EN?wy?7X8iPhwe&s;OA`s1xs_c);d-Pd+}jnB$Qyp1Wq-Xt@*<-K6~n~1C$xZxS}hAMnEy}m_w|qY%~&MrI+@R>+h8<4h@CDNql4uk0@+ttjvLR@Ck5?3e`rG zBK4#WO9nRgIsgyRRm8F@bbt;~B1KV_M6*KCoPdT7*SG_K0Z|qaYm*4Fpj6M6a+`x` zu2D%Q`l@9x90=EP1TsgcNIgXs*=TPy4p2*62Ew1%UjgDI_|+E(IiX{huia!%S$jM5 zTjPF20u;XF*HjavoCm4|sVn*PG9mP^6+L0d66_t%A#%A#ft!2YpfE$UZleo-tMm#< zArv*cv`|#N+*9&nOz9%c@$^#s3*zH*JC8O^WuGZe+3EF@oFVX^KP|SdGT+C4r3zNE z^KB{Lk1{-$0N16Cy_PtTJ-r(i*gH?=)Q|f88uF{WO5u7va|1w7y4p${vSk@IO8D0V z2hLcIsigXEB3nCyqYrwD*yF581>UiS=g>ay6NZM7?Ve1k&0Rqm45E|=0Y+s!<<}HrREjXo( z=2m<{Uk7eEVrj`aUF$%&aTq+iAu2NAz7TEpqBjSe%%uP|^S9{Q?CbX#g#r}Qi$6zg zcLT>RBcSeOJ>!-cX<+@PMl?fatSoudGAMDZvYl)8HBhyN8x;}FK zp|*5XEv)^JhyUoTQw=!ci{#1jojJ6AvxF7mEVh`03vrP^J`&}5@XKi>hc8fLZv73C zZI%6uEW&(CS3ZYk%sPX97NRU27%8H?{8)XbDY;ct%V%aq+vO~hiYsF>H|A|132{?m zP6%-D_aA4cT;GN*C`GY9S<^n~ZeU0zQ&=K_q&NZ(T{%`QBS&}8kmf3lL(XN`wLU|s zi1S0rMoCwdaK%_82HJHDd3^x>H^8OHQct)yA%>I(k+q&SUbchR={ttWYo96} z?H45flx0S~@m`g{{D18Y+x;a;L;v@~(E?{z0@lZrCsAM}PnKUzM0!S=`-hc!=C*+z z2sZ>VazrX_AV%^DXQar=pOrl1Z51walJk#^CIKU>^>qp>!1y&1lbrV$*WAhSFfngg z5YgLQJkVZ!*~Rua3XVj)7Kak^E`AN#vMW|(^h$C|Tq-oN9N`*iJy^65fxpWFq-_e| zm@_V0sKvl#f*?1+&JG?aj(dAUJt4g{-g)mxkHz8IuR|#4MUQkhw0F&rqabU7-3x{Q z2W8O4Rx6)qY;>ZZmz#WQwLHSKh5x(dBZVDXDqsrU7zDRbB+PQ)FX``QxdOig=jYSX zwBF&MIoIWUus+3>Wg=2L6*7#Y~_&YeYG|2=6l$0Dfl}9mo(7I}&h1w=E4d zQJaX=oKS4RY}9e^Js+)cdYk4+hup%jiNQd+?QU)Dq+V{S<&3 z6n?EFJaRdqLuMOdP&BLT9Q zRRr~=Fcn+^k(_2+y5D)tZ*S+|zTSVDMm>z|Tov;kK7ccD6b#;YJC-_tt4Wz>6KQRN z>nPrq8b|E}=}j&*x)Qqq59q8Jwj$(f#?ggO%l>1+Dq5teb#9mnY~|#Q728WukG5T~ zTdFo+^ZsxTp)RjHROP$d#I=K^!{Qc}c8HN?+k_B07%DG-Njt%FA zQX1n%{kvaJ6b!UJFtKiPc2B1Kk~Ur;>0J4rm{ZsJ>EjMfps2SA1OMSR+SlLR?`5I! z$~f~@EnH82>`)5H1@r2>#51D<(3T;4ofi!@jxRHHxk@#!*`n> zBZ_Wds~Bjw9ZGCmi(?4uKP>;R1taq*Nb88TK~S@0vcg^j1d-U(s}QA(6&i7O&lBim z2AQZ-7$+^>52v}yjJOLU+t5jH^b|Ne6;|+)Ae4aU!VYd+vCARrn`CzDr(qO66(RbF zn-IR8G0BE^o@lkXn%}5V(&4QKPEsWqE$m!E za0M;Ds87C~Ckny+8_|)g^8t4$rN6hsD<-Z8LQTaZ;($Bu&V*0-~&~o3Gd{TzbI^Z~%?G;vj2A1bt zO>-*w9V0~!NN!+c<)nBa@jH4sEaiF%F^F=x zaaNEX&R~P)a+&EA?2$e*Zkxz0++{8^mqi2$jJ+_}JcpSnngA<{qg}RHXj_DgWOgL6 zohIzgb3$BPwhq-l26*LpQbYK7q+UuRpiGEk)Y{_6Z?mfFVY!2*U)Sr<0v@oDASbQe zMIj{(Xk|%TS%Fpo52p(yILwrdX7ffi5!;zBq03N(%xMIz;arEM{>2kOy~_SlJPR$i zQB^GOcdjCzX`%%-Ld%NX{J^0sI$)hj93o#8xJc%W!ACD8uwJx0E^lL(_EqOgJ4OrU zGh-+IrRtRA{leD%$?zI3J^Cd8IU3&!z##m}2_71g4}-vf&QsM^3&>`nsd4deVZyx> zKaecXLM1wl6H`S!VL@ji*_7NMe#kG(|Ami=M(ge%m5+(1dbo4xXbOh^Nr@b+d1G>3 zX0^VbW`z8dE4Fp^QKynoYcEqA+wesjcCflmSP9S#Ig%!Ro2}owRhalaaXo|G;s07~ z7!R!Rmsh+4f#Uk+jMA9fMwWJFb;U;!;k?q4>D}wyxtWPc)n6l(pwCrAMr$*Z^+X2s z@vX~uPH+&l!xp>|!4%jxH;jHHp~*n`;-&5DDG$1_Vm+O;-#N6JJUGIBu;lM3C`g%GMAqj6 zlaJZ zO<%N;7^7OUcqF-lfGs4ZK01T)&d1t{%=nV)h)PcI&*Vk#d|FiRehXSg{6WMoRV0q~{4}e-BSj9l>$ZK|`e-kUAfRH;_UVX;ew_irteuN?a;QeQUA@`Rs|1Q^ zyxf+-31nN}FY^whnQh9MPlWlJO*R`2*-=?%tzM@~eT5Acw(F1GclD*a%|WCozbh@T z;){=pzDW_~aQHOS9>#6cfL!;;9neKq@9`Rl;sQ;TXqM98-x}n@54Xj+QG8zo#AvF~ zZqt@2LQo0KDuVp&RL9af33CPb!lk{UlAgu-1G<@qIf1GPyT6N9xD6p_#q|`u2s|Rw zKFwjW@x-iiT``7ist#Zvpb)mVQB3DZwYUNK-Dj;(o}i3>5}up*Ro`gwFRIa5V1BlX z!Q|8p4CHLClFj3U@VF)Yl-g7zNn0N0lNU$+tBetjx${zHcOeLblC_A>qnbTn1Mo$B z8PDZV1TqjmVTm^;;j#c_t@*@WzzL$uJ0xR2QIe3PRGHBX3aFrm)j5KK6}gxav(^o` zvJvOytH{MRO1#XMCnldL>!30aEs8@lel6+72pGuWRMWWY7c=BTbUg60EzwM1cchz z2&MOuReKeloj2f0^?e*rAK&>QcqMfu7Upn>d(;q+g~p22dWM2e+b}Hj{*49s-h%xu|~84|}y98L<`ZIf>H-fr8a`_V_c+og8f zq)j1d!-)e=6!ii?Al(5~Lrg;M z+=OyUFlgI4Q<&bmi!Iw)KW+6B3g3OTN(_)P5n{WBC&S6_O$&sHvsk@>iYQFCf1QiB zgv`sToXTL}F$Z^7!|O<<^Wah~?u=j~iT20$Oip-p|K3ApD~SjN5bUy06Md^fC4flR z)$tZuJ-)pig3&4D$UwMaN_pVs=wtjmy=OOZ=-5It`VldNJiwb4qXaHSSYFDM*p%&r zf4^A5Az_%hMhMc%_u&JNl8`EjvFE`fDsPd!$$s^=C z?gW@XA%>xfzPF@AaX(?zva7OcBqN5`47nwB_c`6qt0a69o`bW|h+`f|od|tzb#c5m ziakisVG3Q;d*mbdZ2ikaScFlz%B!PY-QI~e&ol@_%RUnN!ydv>8Fu#HiHOyM3&wjk z=G=5G)B$g(O6owVv3etYu-#8r;IvIeY`_VDQMJ|w$e={N#zoeT9diKH-m{tSXf_yU zq8GlgX4Y8F{4zVz#y+7qeJjsfxF97Y?jdUU#sIBpkWOmO~I`f|- zi71F81g{H^DRt&a8rG)B2U?kdNjHh(NFu5IOnWYAt}ZI%qz zOz7e-kTkXu=gW3@4%)&Lv*KPc&4}8W6lwv;B#6aFbxpl#d3B-Hz+oW&4h3LWu7S_C znyY7;A8>+jSh5~+KN)65Vs%U=XW;-pK~xSY{)qaT72H6uCmz-e$VP4nvzsI%6ND}k zw!BTgZ_9ZqN7Uqe1f*1sVsK;AE6&<0N=Tv3`u!e53S%heGKZx&6i+civO_fuj4xT+ zG|KnF`;2g@-%K3LT*UaC8gW$$bR;dBNZ7Fxy8E=;4GStKGfprxwHU|FMPr8)JhrW2 z3~hra>dar%v~;4FT$srF|9b3k` z+gWfg$%{T8``mh_Ya4JKw-#=>OLaWJ~8!L^BF zBz2HFZ5g^_X&S zcb5fn{#mTZg?0W(k*Ro34WQ=KtQB|&oS=ahB1!J!wqf-b&kx1L(5^H<53w{nCyw1AO*h;f_wj&>av&wFQ+`)cK`HK-@Z>=Vjcfg1;97GQjpJB^Zpf}Y2g=)c(`Qn*zvucZ z=`XKL0pnBqYO-a?{3p-T^I4jCOKDx#9gfxwthK&Qy8U^YZq|;!568zKl5WLifF>HNs{MU#cp$W1qc0k=6@q z3nYR|r^ZDLuZSnMIJbAOk_a`MURbvi_N8%Cf+>;Wq1#IJ-A7Ao)RhgW2m2MvGTu{C zYz=Y`)QBLGfA1zLX`b_MWFIB(mK|5z(beu+gB>y**YrB3()ptZI+w#1x*9srT}}hS zw7#G{UXw%10t z+~jk&;_Y;TH9PBYR)AU|RW9bavXR1G2i@hvQWH>ZG%fC>gY3AVw_jeWD|;a0d!zuY z1;?d06}u$7BAg=&K@!OtK)JN>V_Bpoj5hBgG}(!gFdRD2AO;t-&Su4p=}(>x3&Oh@ zE-89M?~X1Z>rUtSu}R1cBo;`a4^eh_U(s}QF_`%Q=zGqQ|7gRoUXIjo8BY-4h_a6kD`K9Fp2C8A7W(-g&k;6yD*+uAtYY2^1`= zPDUm7$f=!4f<}t=o9mf`9h@Np4V5YSSXVOsT%l3v=H0A8%%F@XsL5zN?^HUfg>!^1 z=~#(EKAz5GM%oPGJvMN31AA!m+76#51v_(SDwE&5GGDvVGK^8bewP$P;{(gf>M7Y? zvx{v6^P8>3H8#aL5)E8c-@2A7H`_A#kXm?OPj<`jJBdvc@i;r*lzW#r=O~3LLiIJQ zOPzijep~_jSixk&xUNu#b0?MxcUUNn*gp_+~Ey zj@^aR6_k{-qoL$y9ZBlSnNT-xuRCvG`I7r^Xj5~Z7{6z59|ou?Xa4t1drE^DJ?uo zjo=DoBKx3N>lh|M8-``+cBHcLNrkms_95{)+;w1qiVVM2PgCcR%48(GSmUNU#TXjR zjjbhT7$A&P!E8)p%jxt4N4cjhL$)Dx`0aRmAy0(R%vcQAn6AM3@_6?Kg_r3N6b~}| z*o!-iBfH*#AV@UbiUQe@b4abdpWsex`D%Mw&z|*-at0%QDcT*gT({!=2jg(l^W@nP zpS3jjsQ8=ZaP?#M-Y25a=ks$O&ORRxECyyGAR&`?RNt`wEtM@lb@pKDP7Im7oon?! zi~g~65;1sqtk4X?9azn5dZk!yN0%}KQ=rW7k^u!(o!Rctl;8Or7BTyeft?HJ%@xu) zD0Ol5M7U1g9Z4yAQ~P5%GM{v$`i^UBhcB>)O@yWBY40;h{*w_*C&sbEghWZ?yiYrO zvJct@w_fZpGe_eiRUD1>FexeXL+y0Zf2YGdcUja)C{BEzd3FP2XInVU!B9zOEJGjn?|k>ofCb|?nf=?&f54u~_4wh;sv_PgVhxd6F}6qd zXf&O5-q-AeXx-Ld^#(|(uGwVmJG`Az5XP<*Zw(%n{r@62H|SpYs#j--TW@)*RokAV znoh-1_3Z93R7eySyC;Yk=^1ENBsfTQg%bp9F&%y|Us%I&jh#Gkn}U{zA*wkQFzz6!%uDQUGLS+h$c%0#r6nPz)F z%el6LnN9sltAjPW2O8c>Ec_v0pkUpZ5-%hZ4R~cE4X-e+)2cPiY7uhCoX?tuibD@! z@W^@Ah?7Awq{3&@E@8u`KgxLRnR{{06I0Knpg;%~sZgS-?5fu}Qh@+*Rgf?jBT9Yv z^ygMFQ1b279m}mpWtC6!0T;7G(?U1J1A~ToS1ypi4SezjliZFUdsxTL#o!sg7kkl= zQ7d`Ev=r_Ygc9O3wmw?b6VyKJHX0E%o+!}AN$w=kOT8ptjV+5EOrx(g0@*dNj|R=msiTn)gD9*V-rTs!X*MuXPqgIC^$j!^5$YifA45E<%KSUw1bpAiWpd)3 zM;XZqOq{tzVv8+ix3lx6!%H1%e5as(;}wmMvO1R3ld`;3IZ8 z-+B#!B|O{$9}WvwpRS370hizc><{*^tOENB2Jt^p$LaHN@^^OPnY2;p0c)!jJqnjf zz&(LnD5J%vU_wv6loCQBJQ#}U2MJY$HLKuLhST^Wxmu6Op}Mmc1{!YXyNSH;0 z_7|(noUJ#g4Dnw(FH(7x?*!%p5s(M61&7uKKKnSwBr!75i{v=-0o<+a&nJml27>;X zxHu+sdeG+}Qq~}vcN(WD(`BV8UUXPP5NE5zBEqMpuhKC0F#=Pyn%3#f@k^g2eq+oQ5;QJSYNuV()EYcFuPeaME_e%>UvkrZffg_Ii}v z4(M3p=X1ltZB?aVC)TtFzn13v>!G$vr7gysw!@>!ep-DHR33ZDX8qI=ZDant0lfCQ z-X_=B?EJe2J#CkEzrc|f!Hf3U_>yZT5Wa`$Yvp%z3-AAE;C~^o@55Gep`SdBGI`Et z2o0zga-*&cb;}SVYbuPI@an&p0PQIBzrJntGpDbJ{{`{HfAcWos8IHZshX>`!Bndc zR-aTRilf|u&?LDxt>Y%^d>5umHeIy zaFyJZ%uLgR1W6R!*|)6iYVrPsWGw*yxNo?k?5zJ5OJfQNe|FGk7R7QAkGD)bHztFg zP~|u|BlMUlZ*Z*_*_~6}-&VrIcBodw``|bvqpnqVp1fP&O-9096?o*yrfRuV*%rLd zE}{u-D~QTXaTS~F>@`#lv5a_QwZBrKQywM9s7_Q;NYxZ2WNN@sV&(D>aSR1Huz2Db ziKoU(+%D#?u67m~8-HF$ z7>Scm-te6UEliuC@liJ2zZVa-=D?k0d~>+&?4%qihZGJJ8(fd~JCYzP(aJ46&rFNk z3Xo>3dqd6t;y_X^$t89%?9cfWe|%31d0gh2N0NaZd`wX^IQw;udbRSSiBY!Cs-R@! z-3b~RQQ3-T)5`T2zhvIW4|J^aa4gGtl+V})w^mPQlL8I`$thZzHf%v&n}UD>lrmt8 zOIRM#d6#%;RSvHsY&ag>fzoeCr5%+C5y(tv_z z@uAXh_m$0zY>Wod51E9IJeC;FjDGwB8{PO?#VMq&j7Lg^35+pVLHpz4JG=0vhF7bJ zR6P@^sn7c;VDIm&!~QsdooxKZOqsIr{4&7~dNywQ7QvJB72rnUV$4V%07(?uS~3&! zBZUahx$jvItn#h<%S7JEjBfG--AWKY+`h8TC~ki%)sBt4{Kvn3yCZxb5yeG`4rSqACZOs! zo3F@!lDNT17_t#M`EFpnYp~G0wmCpyIZ4^Bo|n0cocAd+W*UZl@&>OQ_9mk&9PA*{ ziTc+*J`*D`o{?flV_+!)lV%(*9E@w+hxYf;qF9aeYMx z;uafLsFeH@laeCHCXC^fRPGCe9yScBBkravXcTQSy-aIq`m_vRUDzpb2vJent#$I;m!!Rxr!>Q3T z9K;F+Ef8mMWj091C7A$bBT>Hv0m`@)Vb!D;lhzPrI26d~#?l57)JMl*(5YdYHgMz( z^vYKdN_qX4SI1>!Th`u!LkbP6?SCS|R}N(4!-Tv}<8>8_!B$L!Yxq<^&B%E1Vlt#^ zm1J?jfFB1)dCa(JsO&=!#Kbat!O%)nUR1Ao+G`ZaZR1L;e$6Ap3oNajNeJ3q0>U86 zuVF#(B@F6REBewy`{(f{89-3!KZ68-`~O7UpsI#NEFJ!^=!~r+I4UGlz*9-7# z05pKA%M-})ty=RL&1Rwk3%jyL(R00d^V#Fg8N)S3wH6P+K57k)=hXsx_wC0K!wsPI zRriGe$PK>st7n1}*LDi(nUds(eLMzvdLn3ZHZGKbqFz;T)nb=sM zl8=NZQw7NtWV&iZmII-X9PUCZ&_nP0312hXEzZKe(_8WgCiG=;yVEj>5XTSDn((ix z4^N7m4H0ZAU2^y_Q13cuAH=Y|1#?sZy&1`3X6#bzJeeMEKRm@i%n&p#5S2)x@XHv% zAI8ec4Ft^hx@@mo@!v4Avrb^OL{voN4yq{RM$%Pw4)#LkayljRr+GR836uTqE3*lV zU0DZ_8>_(HU}cF#czer{!+tnUI2Z90!;ICvqtylQJiS6$e~xubPURN8?NJ>fbq70i z`&?#U!134Y!=>Psd+6AMRa~|CG+~sO`PGL<>v)L~UVlqm^^x%8-A-E|cX|5&*Uqkx z>ak|@cTdyGW?{glh%o>7(wC&hYu%%Sn_VTJ&%rJbA4TZqwmN5mIvp&J!H&d zh!ZK;Sf2m~o!CLbL))!I^MP%g!FNQm7Xd|%*VSdAb_A(X$1V~3e3X`CU&@9HI0pG5 zK^wFYF-TMgOjOs+`a>~*214Nm$aqt#R8mD@EmA$jbzplU6ObkJz`td055$<@MU zKES;*icgL;6LXPeSGpnxOl7j%LBtin`&b*#ClR6Q_PBI=$x}^i9A=^tZx)qYixu^3evW4VsDB;I7QI4c5Srx1pT`hpbUy#B7&0%g~_ zdAhfchtUG4-WV>&L~6)XpcuqnC~dJTTN=*c4J)t}P#{QcE?PJYXJUnP4@?p!t?Ox|b%_O8 z&`YR|a1kYdcKOp|b)uB36b{#Z9pSe5;APcXvJ^F%a0zI72_@#};yWoO76uf~#b#7W8hT8?9$@l_=+g?fazr+f~jt zy5chq^LL@z<4>yCyV>It$}ltkYjSMt(ai5+WRvKy?f#i+$6^1(>{ENPef-ugatO-T z3$dD~$`J3}MR+`fu;D_9cAb)3{m{D7d^lmMrs#-F-1pBhjyYY2@^T>zat!c|LykI6 z(Hfp@VKG*6JU;wSMwxL`O%CkU2xBaqCCt_Dq*@75b2-g^!sMMEV+cEKRlKeL|(uMm^JV?^bN@~US z&|Fr{H)k^P6Q>=KLX0F`X`Q{WE>_7&Kqw6G-yp_W*VItWwi&r~c?@X{$sH`bA*){z zTKb$4r-}F?{~yHC=4sxZNoh`>0OJoEHaO=PyJ)3<0-`c_a(mtig54N;6eb2tALnnp zge`?r@Gd+AU|>pL8~6|uJ4sl}=jn0(>9va;wCcD^wrGyr{CRJfFnGZg-j1PUc6w}8 zkSDuF*w2jGPx)pD*Si&6RYtFO_ci*8CZ3O}7204)(5xHkkvQdnD-9=MGf!n2+3e|* zj#ppeMb&3mO9h#F^D<31W1L54|K`3Q78o2qP8MCb^QHLVU2%PPiC_=Cj zGEi)au&2uD`jzOJJjeZ@BzbB3z_S>RY>p$TLhJM2qPvqYAiHBNDGKvHDm{r(DO2iv zhrl0=s7Jjm2ncDcuTwM`t)K0RRst%*Uh*Ja1gQ+A+3{Arq8(=J2T`W*M~pqJJ=}Va#=UlnYdWAA{8S?Jt##;;oWN*LS-8}52>=S&k+&9pjR z!GN7|DD6);8s)EQ^*P{kB1NPMD%YAYEf5|Dqy0u(WH2^vaw#(GQ(KTh+X*$weYL`% zx_1c1Avkj<>^d^%!ohcnj#yn1im1CRXJK-_=s=yV$=2WvR;ba;yi;LeGAWhE!r&Me zi&EoOwR3@Jbld4mX1j`J4Z6?oTMF+7>+#mW=m(z`vbXgFmg72Cq!z|IZAJz3P5Wb=Eew@%sb==R4EN zXUf4e8x_>7L?wj!v+1+fha}U}5b;yGvk@vjK zOAtcL3fu>h4h_y)J0)`JsA_NYfJpuko=p+@@JJkbqqw7cTbl@;*o*?wulo zK1n?^teuK#M+<=eLf>Ml*x%{0G{S`B8r2MLw<3ev#dm2eWlgbFLR!nlO^{S{2#Jj+ z{l!~Nu$!TSIv%s@>_!Zwp?MS2%rTmnJ*F%NGdc_X<_9q?rg6^f3)|@yD5)hP;Zn<3 z;+=R`R8VSvH?~}c50k*^l_XcVnWxYh_t6(jB@X}TK?rXr(R8raylJj<1h)#xGLDFO z??Lcmi3&P9qn+N5h{R-Hl!uN{>S<+F;_o?RD8&hkj)g9*1-Obc+^+0}Gv|V|6a?EgQUVa; zrWEt(v=k$wSQb`px!WrTL5O3$yMd+osXNOfbJ(q+PpV@bISA>0u57YylCs2;D|1CT zb95yTpDGOdc;>^M5rT}GY>Z@XlIFXF$rB|A3vfoA89f+7Ec7dNy9SjHDK*&lIjI!n zGZ3;=sXY8RXLU7wm`P_k9;ydg2O9QF{)S= zkpROHh^3iIv+h~6X?|^}KjBiQPqoemGpJYVb~}xeu_GH)341s8l{p(lhb^mm`ZaJ+ zfXKdV5dOU$CNI`))liysy*5$N!vK~!fr%AGBGo5gW_aw%B|(0TjJ^%Hxx{+Eb^)LZ|K!rGTsX#43ohZ)HP&)LzJ zWrccPtk#Tfd~Un_ajk8?-fBWctCYC`KmfQQ8z*w z{&dMYknrCu$rtaiw32h%M;)$v6qI8|>-Yruo-ZwZ_8B~dL=53tb{XJiYchP8(v!7noZ#uVq1?67m)N_4|A7R!`Irozh&Li)Efv2Y2Ss~ejq-RYhGrC)kp$as60JtyD%1>BFwAEGNnOY0cIu`fhd zwJ^*GA{5q?F|{kLGn(@yH?Tr%DQPtEWPFb)ATK*v8?LsZH&uw09XX9In#WVXc%VET zX<`>3HW!u$mt`;&KgO@fIs9ry7;pBJ_Eln7s)CDN@}@DqzzGXjE$?zKHyub?RGHno zcjfXAK~kt#_-U)S^qRP82>Kg z(`h|8&|YD6GQoyXG{j6yL+Dkg!P1YYqWf}T!$4(80z zYeG;@#2k^s<46h=T3Dl_X6_Lq-D^@(k3VCnEg)6+7+*COixo@ycNF;yhC>0Mw0zqRZCZxA(3;$O4b};dDfKB4n1yGC~*h;h?C@; zIF6_x-9o*LsvAF|31=;QlU0R_m~G`?o=8Pdp|i-qG?|Lkzv3z%*evbPk!J_TO9OYP z=G~Kf+w+*_S31k6NQjbKuOe;*AJM3^;F_K+Hn7jd(YiBS-Uq;)22FhUgTg%jd*SN; zcwntd*spsi9Sm(8`LFG~KFl4pXf z*IqL?;_Z}AKZ)wEB7Y{3F&>mK#b9oo@o%1r{o|U(9LD^NbzQ!`-RnT88J8q;>xZme zdT3cW>nPi?C>L&HBe3~*hAsQ}&y@3o<;n-2zI)XoixHY`b>Cn=%TD&lIspWoJ>c)-tA{L)upssF|5v|?G{eDzK+ELpSg=9-)Bf%YQ#H$T0#JYrpa7d)$ zlNk|4@2!(1GXg|EfsQ}RM{<@+y-rR7#LVRAk+7)RB}gU_t@k}vRXuh^42Gdd_fZb+ zk*ks|=%gokhxl1gvY6*qDAR>i%Z&e#rRY3YVL%;GNw8e3sj;p`s(Ijnp^#gsm-_gt zdWS-PlujZ3cmU0!2GBnr555vKMpc*=;pGi33OLF5b(GY88!?F%^FG@@B>wOUZi|N% zB|ccnSV~uRDm=W@zxA2Fp2kxh>=0qUQGei^*%K*`!VWQ06|7bg-5l{F4vpKNKT+*MV={^nHY`VTKwo+aGho|W~gtu@Q+o4tOfE|UY1bzP{mqBmcd zR$v(f9>X(y0+e-q^4x^mQOwUa)WRTrb;K1BWr>FQYX3A;XB>?ZcYj>+7V%-^7|F5r zGzpFa70*jB9A>0sDa8&?Nn7S&(tn&FtaMZTogMQ7?||Uc$R);ju!exIOrx(C+AMxN z(w(e6gA(dkq8iHp^#Lve$h6Q~sBd~}V?^bj6T!acZ-K<4rt8$ry?YFE@&8l?(A}9R z#9eWg_(7Bf(*W5k>k8mQHHz{BstHDm?#j|T;-z%3V1c{?;tJ3E3Gl(1KLc%#Iz41b zDiK1oWs#x<#|UUEh@nH_U;+sbP|(vvu*Pdb<;`rAdp13FFhvfMJxhmwZK3#3SJ}#e zNS@YsrNZzP3LDT)Rrz9G*;)kaoP0&o5soL@?6f`*GMELBz`D=IHgLyPaboqsk74?* z!H?bvU(PbB9ygJ3^5|PgS{176PNQzXIM{oJa#>84m9zDl9+_no5!7DYgqK6b#{D*X z`a}R(ZKO6-*bgxgb_f|K;NzIs`nRU4Zwp3ihi_?+@*jRv@)Wt&NW~@~VR#q(+p*0( zQ{@sFX(rF>Y0Z=7ytKrH(T(uh^rTN z(ty|%Co}Q3loHbAu61DBbH~+m_?wCMv-4QFNHIL2b|wC7M^?Yqx$m!>m;@q{uE3pU zp=;wob*~obt|PMcyd2E}di+lq`B4)^R3Kg#BG=bqw-Sf$Y{B|OYiYTme&JFhyrJdT zgPl_UPIDOK!ielQ7*1kttV~G_cP^~1+HbyqEUdeYYT}W=zlF*>)rWEN!F{cYn`%&X zGY(I=x;`!z+xxM={`^Wj>+7*5rr1Cuf>CEUQkYDl{-3lxKN+fhFZ^<-K&yiFK0#ZR5{)0r<&@zSi%aLvE0;*S?5%5qRPKFJ>^& zL;HyIV72mBWCZbG|Kd-#Oi@AGrSy^RwDw)}iVY0_2M(Emg7@8rt>=IGTeHw9fegGW znr|1`0P^+W=~JkW>USWB|S`lY&3l1F3axI#om`vAitL@sq$qBp-}2Z&M$_ zu80sV-DU2!uxCr4aU%|=;&-xDp-M|Qc8I`$%4#`NA84h!Gc-fc!HDL8@pxTlB*q|Q zNgl&Tp}r~Wtq@X00ccI-WLX@(76L3uqF_6ot%qP!2&$-s&i{jLCf zXo$FjvkSSx(}sv1M7=2Bzzvj_a_go8<1HEq#K~-$oX>G z4nl4!i#SZd`JB+A>MUo(R5T9PkW99{?`jySI9zWFC5=^o1dao?TJsg7|rE_EUcmmg#`=JDRo`ReE;RKOFBX#FQyNJuwsnAl z+QNMpUV>S`kZPA@a|SMgLok+j!|KZMS2MOJW9i>6r+1;L*sd_rgNT)0VjPa!SID`? zat)6UWRLdQUXeCecL_$bF5I1CCP3OPF+z;o%@Ser4yvaFy%x&es5#j z6DO79Vg&zHgZUMmJy%E2bvNr~tBC4$CHW5&inne1u&I|Iaz{G}Gc&HgeuF)!xEebh zI~ZILOVJwYdz6pQI1RsW#&pyFnMc8ZGtC`A^!uwI{yg z)-QW8O)8$^jjiT|mt5WZ1=|ipLTqd0G4*R(&n1a0Bacy$KK+&4@ zD7HSNg!&1~faHmDvrOdSX;kzpm(4H6)4%jr^W`s|C6bi4P+K(&y*;I67h$=|9YCE5F_|w=E)|=> zRO7xS#d-_uLOF{|eNNXG)d{3ckYPgrOa{We;afb-#&F!l=?ueIduzDreQ#)Xg>)v_ zq`vVY*lrf#}xG!g|i9Z#rw>fA4@3~Pt!0Dj19CB!>(z7tgOsMVCWTj7SiKmi_ z_d_TmTO&N^ZZDsx`q@7C_CX&=UXUm)yp?W0iZ8~vma z4>B+97`J6_axgW_skwtoO=?9Z(h5czLx>ZSi%PN2#`#ufXdFv_Jzn?6^euIgg~5<{ z!WX~rpssN<{5+x*_}3@k%dYAD!^jVy1+`V}KWx^z_eq5}U;lc)>ogf{y2|DNrZeqa zX{J!X%stsv`E#rWtP>~Q4d0w4y`wsc`DNykL!N3%DEcjYOoD^mJMv7Eb3fQIm&-&_ z*#1m^1%kI*eep@}c;QUlX4E1M79Uc`qkuC>Km^D>z`7vPvsQ`RT#1X)WSrJruQf;f z4GI>5i2JmJ<0MurLLf7HO9rNjpR8p#g&B}u1-uqCwm?OaOhCA;YVy&UWm#BQaoS+8 ziatkK1-@uXbx3#j1OpM$Ev zGqYkLkNUDCZ(LZv?XXO+)^>Vku-4*U>}SvAuSb06ox9G+PQL|No89(^35?T%ANXOV zXZ_BhrJTo%T3a!TbH|eNUBJ^1N-j&~~@6 zAQ*{7(EuKC2+KI~YM8(}RuFk9eJMldsx=nl%Bguexm-pwASJR$WeT!c%}$;;n+Jsy zE(HmLkO3*34MLFNsKm@&W3ja!RwQ5I5ifS=U|CPtRTuLhjwa8KZcisf<1-v~o-Q8q2AWvO$-zFYmIbu!ZUbHpjFq#h?<|D=}Ah$Y+y$j47D zYGc`=%801Xu6;w$kjtyEb7TKjKUj24Til5(`(pJl!U9sYKoVqo2pM0(thc6*K%Ugm zM*mK@*;nkW0APq?8V$izi25D>{?Oi}1yLeN7HIk~wynlr`r7V0DINRaTt4t!+I*lV zceKvv55KP2rm*0J8_K`H$YeY27gn1Q!BUHsBrg; z=Dc?gh0YMUF+1h9hKZpTWL}?TxgQL*ob}0Fm}oYgbzFR{zkN|fqriN-V;l@`SD1Y> z_hc__dcA6$pbqhJ(s@?+)D}X4D+?GH*}CZo7i`sZ;GiHmdU=!xFLo?O02rPa)I0B* zv9|D+z8sd?Xd%!V%lUz}@_Oy!LoTCI9s&jjfQTtVA;(fy;?>N16DbrdiYIUi8Is$j z6&5xXnB^qeaU`Lii`LtWu##Vzmew^2tKOclpS5*FhU3U`q+e|ubiVFkAn}f^mg47tx#e%aiEH<{N1iin#rF&2T6N%ZCY56% z8|BhKvUvz=kd@rRh&*W5=df^FvjHPIH|K-(IB8x0jVp-v3NALyOgL>k`bHH0wJ9PLy-39gXu~U3ss#weJjSDRK3hwJfWp527KPnm}wq9~80w5F1k=@SR_!%6n-?eP^nB5f z_w{5DguE29sZQjGK~y4vMaC~Es1$XFX>hd+oQUH}FCmop@x29e6aD{Z=q=pqzRq;* z&CJY`Ou-I)9oXz)R!ySggwwRBGX z_kta$ugme@Ocl`g@DD7FP&znZKXx>-hfbcLu?T5t1*lFGl?ABV>v&kg7@QL7AE9Xhm`kA>;6e{sk~191>sJo#P>s zifB!S%yGxoOFO0y{ka#KbW63XRHW=s#3Kj_lNrFv14ECzsY`mP9bbHEdMwwiSj#SO z47msP^1l0!nyn67lR;l-%)xOh?EUhZmbjA$+du|ui|rol6~Q;rYHR~Qq%wWjCIyhP zv5}yjL(${()K-;S3q(hk@#0=>p+z=Ks znYt%GKL>12l|}>FbU8E1TAr*Oy{(hFkRkALs>W8m`N#lSM{@?_&_N&f$S^HDDWr~D zI)ZDGidO`B1ZzKENW?5uV9{Cx#;6S63FwofwFAoC_;R`Rp4eT=L3e-HHPF6Zj31N2 zS+I(wtE3ifV(%_`Dc$H*McKXsMmt`@@rL^_nJ|zfMGtP!$BJhG$(5%Nmcy+tkQu4S zSti-?SU2MGoLJws+~#IwdPTkhGJqYDuO}}`^~?Liko{gk-At%Qc~wL#5d18`_H#pW z!!J3-==)7-~J5qn>Tu#hkF@O6J3j@mFpj2w~eWL;(68 z=lnhOj~ld`EE|aow*U0IhGH`;nxJ(#ms6;>zlJ3}44Cuc_9nyCQMS>=!4RV92jSzoIJFfSBf4q+XRR+*ge+Z% zAvljPk1%#GMwvrn`X_RcLYjH+e9*h_2iDej~Mxn>& zm|ip=YD7o~)QNIqItHvHW$JPY!>q}nqRqm} z6FG0jmoo6RUKkYstAzBKcCHw#p`;9jp7Jd9C5I4T9Hh%t*BryV4NfJUa{eD2R2vJ* zDA3yhBI;T0P6Qf8qV0NBfnlW#!rd(nJX6 zuIO->Wl6qW$mr=m7%fnDZaGnx31e0QBc$*h^iexDLW4dDn-a8# zlW>?`S-NPe`do5K=ng3E;|=VCc9Q7i>Lf5K1G5h@nCY(ecRau|7fxg&f-IHlwSM(7 zMvQ1D=|~n(Dkd#&`_+bc7efJc*nn^IBA(~-!4YhFo_oxuDE`8PXF>q&Tm*y<|ad>^QI!k~4d)oox?O#Uwt=@98!yn&3MI`!o?$9 zS|{=`y>29Hvo92Pz%Zgk3YgBRM8cI_GiOh@tH`=`6tE|0G`h{H9?|X+X~Cx(pOxap z$s#Pm-($z4Wx8_&Q`-guZ$Xl~%@K7cow$?F6GR2jhi1Mc>0fJVKAtDXQdNU2ptIjt zZ5mfMpSi7jhmaZ#IYUzK;b@y2O*xy$hDb#ZgKwMoE^XR@nT{a`bzkP-K;JwOovD)( z#%$^aAsiAjf(rDoOA#z194KI}lA}bx=+v;5@=%vrEcPl8vHd)~+>x+|%RD&LIyZ+@ z6>0AM3dx-s0VF(;9X~@&7w0YgdMijgQ6KCT-N2 z|CsF}Ie}IBG-sH_+BU|-)l)oOD)N7 zrl{#e4~skGrLW&fF5n5vMruKyU*m;3a!R8Z5>Mr}+$M_Pgk#nHlgV%p3TeHQs@D?C zU!j2id0nizQil6Z@Y+jQtRoNp&c5Ax1I=SPmSs+DK?O(~;K!*5%}sWf5%>r}`9K{nkD2*s&~sYtnH4nR)BUw)lb+OHbV^Yu+gM^p#H z_8ZqN26RMLZ!AZ#`iKy69!@HEi;SCO;;wVm1#_ojNIio9?vuwMn0uBb>}7|bto$_7^pO+TM+C{2}lU;DOJaXlJ{l^0eS>Ix}b~xp6_I6 zYE77CTFFH>U;BjLh?|`mhm51yja-MLBguGku%insR-p-#VHSt6~okC z@CIgGzTJ1M2e_A=RFjxBc*+x?rMT{i+k>y|w}eJY9ue=ZxJHq+J;?&UQE`gj2i4%d zSbT&nLjnrSZZ3rgB2RrAS%i`^ldBMBH}G9nv-;6AZXu z1$8;`rfNIH<}dEfMVN|1o#KGH+P_(2s}3at3E?Nxj=Dt_04z*j*qL&BuUVR$raYnt zJbAAbhx;oGng|5gR~SKGIvDWoN?7|m8T5nVf}_MI-!nLcp4{)p{<0Uz;ktGbo$&VgYqRW;r6)sb0Hl#2|lp>r8$$5*dwUnD1U zqTNcwY;vY0*aQsda~ z?yWht3{KKw@3^Q&x4T4J_YG9o47Osjzm~A~^S6WH$lqSf1{-fgv!hk&35pcb3n&{? z8IiE$QyXgw^{KjFIV-O4jv&24IPX0j8Fk4)L_nFTey3T!AM;)O%m6f1;LwyEs|Hlx z1N$S(qvC<*bzj&5(3zdW zfGy?i0cB|^l8@^1YEiF2K&v*Lt{`8CF!e>e1&QaPC*zPPm4Rec!BN1b0`OK2BZSte zdwSw~02B=ACurd{`iy897xRf&NOVLbksI1VCe(s1dHmXTh`fCdz@Ytq#7yc6fcCW8 zzrrb9BU(_VFg{24F&Y7W&=c5<5$iF_?ad{R4&=A5K9W^&d3%2>rq?4wF+1v|n?t$W zd@~4^*iee9Z=*LrD%jm3YM1Sh)#IrSjKPnn8SD;ldO~wd{C#es;5>Taxk_C)FUC(} zYv_0JfS#?l*xDT2*jd-(Ets1d2(kORUPn75+`289S&h|&wKzO8YQgu_){hjQnZOUU zp@EBELF&ItCN}V#qoBq;Pbu*JAhX`_QSUgh)uqN?=5W9VUh7_bsrK2~1nM8T2y6cp zZS!i;HNOcWyN z$n=sLbw7F>O54$K=?uty7=#5&vSK*5F|vVI+azvJ1;g?FH`#*LC4Mr1WLkEL*Q`9 zUxKWXkqZtS7}UL!%oJ#d`u51xMt(%M>Q~rjQABOI;x9QNoM9`W*I!A@2r=j7E%9T2S5Y+UQ1K?hvt+@XI(b%*+c|DBfr7WU?{qFHBHj5JA`pc! z?L{{}pb(loXips~oTp4rE|wfn5KBv1iv<6HWo&!OO&^Q~>I>XV#6lwTcdAmu^OVUgE@P!{4U(u2 z(+Mm#t=UsHW&4+x<=#BtNP7|^vHCR>>-*}agUm#&j}jv&8nfH8lw4khV!PTLJbu;x z=Sy05NGu%SQOmM-`W)8h`GA&B57!hCiLk2B_`>d@4$aJGr!O<(Z__ z-Z1Xjh4KB3*-c=)^M)aFHzhfU!rJ$7T6UHb?UlpoA2ro+#wes^fN`DLMT{>XB5Bt{ z6MRxRRHtvfOL$*Wb%kW~(`F(E)3A^EQ~v1Jf9>NRC~lp-1~BZVy1{*SvXKNFDN6?B zD$rg=)=XmL{v91IG2AW_8GF578NY?VXO+g^y45ja10XLjL5|T|HZA>v;ngfDmAX%k zI0$u{Q#-r_qCVGDD3vN-KLh8Yj&e#IJ%bb#hav~);RvB?%llZukF{_)R(QR1-5eH4 zLKBE&2z@sjeA>Fv8GA-S$RPi;KP_;JXoaT!)JO#HBQ=>bjT{NjNMNts&O54C(+hX< zJ||U(@TJajO@;oAC@j2CcUZ@|m3GZNg$K7v(Fa(63ZI~d@I?<&PxeU(kzmcFB;T6C z8F?u05pFk;mVv-*JUrM3d4;wY_d(dR99en+&6ngiKi+2L_YM?#DG+Pkl*r+1`$`TN z=gu7#XBP-uFcX|IR*@`uWV8`F6Ah6Oa!{H9=*3G4b|lN=M9bq-e%Ck`xo8`M`dHEGIxH zhwV@ZqJm9vBcW_5qJ_BX2pn89GR+Q&c@vO&$3Jb#VWcypXbzW0IBp3b-m^u2yhbYt=+kp-O7YLyUE?dbY0F#rTQe%!){?k5R#qC0*;jRHa#-x}>-EvXMjCraA31)?$!}bl4`7B$7{g4B@cvS3=$U-Xh>E^Hhd@V!i>gScvD= zid^DDxD{TVts&THbqctWd?rnD!hs3zd_lU=q)ZcYYCgdnpjyUN@K0mW9F>gpT$;wt z?{S7+O;%naqgS=Yx~Ink@L02m`lgllg=w#$s*0@Fv^_AdpB!E)B!)4vVf=5xNI)QP zu@u4xjb}fL?5j`tk3*Jdlbr1^@1xtJP{d6p!nJq&fCJcU{h0UL$mupD{V`A)>>C+-z9o|K;~vOZS8v)u)q*w!xxH2`X{91DV7sAu`obd__R zu_o2r7%-T}g9{6Xh%X!*D^Ug6XcPp1L_U32;Mdwq)96CiM5XEU^spFenwbI-67f$G zIrPZ5fJ_AiTAR$5+O>kWf7b}MW-8+H>sM%|Kx+~Qs2Nb^)5zm!h`^SG;krPR?oZpv)qQJ{6J4(uZmqo?V@Ncc-w8p4rg|JiG+h?4nTcP4=;2T9SAgH z2}lLaF{ht>ewknhjpQ?=(jk3_q6Er);sxPGktqM&alrsaJ5=6)L%7S zhX5--bQ7D48wJ3N+dZg8)$jrM_D?T|E2m>yl`G@a5*)2~z9ul_bC(ehU+;>qQ_mPK zHVz*PapUi!z&dFb^<(yF?%_kc>a& zDi@cRDkyITVC{qD(Zi9H4vQO6FD43BQtxel%hK0Dum(ikbpl8U+AedF;U{y(oR;~` zm?^G?J290Gr`#NjK*ZM(M+EWWG?KCdaB`g;bug&Vx2ZYUz)k#PTZ4y8cn4-Y;bEM z?nFue0;t?&-|fA><^lkKTz8X83=-MYx%JedU@obdBnm;pH)0@RO+0y#*4q?N6PLDd z4qtzZ9ad}N!>YT4nWxAVM+Hq`V0~1B(1pj9mq7KpNeX*}FIo#6w&HXFt z_v1T?sSDonpVuPw6hniac1LLu;_meKB?>9ZR|P>k<~1UN^2ip!~Y1Ep)a~zma<3))|lX4`CQVI#V4~7;2d|MHbijDn8?O9A(8mfN12xh%^zf6BP}x$sg&5Hl0G#6 z51@Jw@oYJl;*hwT;AL0zrwyyxw^#!xNxawI_Nip33C8vFiKrK!;?=2%PwebR;DB*m zH6Lt$)N3!{5$Pe5&AYEX)bqDmeMy+TWKp5OvV`&>-7>ph1I=MOT5R`R>#RTQZUnk$ z9s>zp=JJD412wg#@2Gy+o8VJ+OL9XhB)TpCl?g%i2LCy+j<@jQ%=-T7=$^9Qqdx{A z_}&*Uo)Vx4@chK^b2yBP#FUJF9Ns>GA+MJ+eBf2TLBtMz@mlNMuDu&DrDG%a%lcv7 zi^MnX({sHJ^Se@VN!esWvq$%@Eq?D?lJ9#|M{4OMyKdLohQr+B3J{&w2oq80>QUpC zw}VeVEdV~=QnssK75fFOHnz2^or56xj&MJtYZpVs1cJQ&f=uf;{Q3uLE~}P~+d6Ql zD6OnTFka7+3m5oM&JjEl*{;n)Wm8q|a4P50Hw7x&esl>I=R+!ZlY)=T{`JE4D{YQqvPdPJm@0NJ#_lM?g8$*zq z!x$R)$?l-YVEUG6-&@(U(Nf9XILPLgKfE!zp0AR3K9EhgyS|w(1clmvJw*3@Y6;B# z`0t?8w8E0~2PzY~Fo0(7XVk8aRU2&jP+Vf{eM}dS<$!}VFJCf4!a!JJ^8-i5o`ls6 z!|l!T3$W#dn^eN3HR|`CmKCU#IZOGs?`#ce(VzP+Bucj$ZHI3iuCbK6k~8D`J@5c} zNDSx9n~-Zhj2i5LBg@$b7+HJ|q!$2EG%9A&Tu8%O_6JK#(S=fG00GEvjJZ}DLS8~M z<%mMpo7gSB!K6!)5pEOC1onDyZZ=$(3~%ZY<0+JYZ;}O8vDH|j^YqPj7;qB67`L#? z1U+ObP&xGITUO0Kw;b)Gy@v6;C7Y~C>mCYG&w8lHJ7F)v-c5GS)kTZlypJEvmrSkO zptWoFPXeSmj&b-_ZWhaRZ}x}tybtU<-F>n6g26;=Bve+3FzR_P7>Kswa{yO zod#1baV&|^O7+(|WuoXOPin=_~fN{_`Wa1`~)&%5YYQthw0Muw9<2)cQ z)#FSz8Zky~Ek5P(xmcnt^uGuFJ;5NEULC2`Cb14wHr|9tcgMbRRNUVFT;mqxfRb)7 zpz-x_$`IdFicO@qHG!i5vxr96C}|Pc(rC~YH32eteksHd^FX)l*{LCf2C?h1Cu%pc zN67KW?nm_x$YuRy_fgtycXBs+JiI~k6ZMm)oj5`_+$zt5tc@(si4=qP0I|h{di|dO zNb98o^%QxbekGF2%*hf{!lW>vVXL38L7LEAM-+sRpE2&D`8#QB?5CP#@xbw-A*M+r zgIW}~`hsXzxu>0tH~}Z^ISPc1={u8rzk! zkRD`6Kn5gw5aW_g0GYDqp@bn2{8qVJizIkzD0{pl3S+dE<);Zl07=jfG{2vH4BU_G zg~E9E4CE-s~yrA1Dd^lO;<>}n>i3eWdh+7iTcFPCQ5)Edv9HKxVo6hfqx%= zqybP{w>p{V*iCOS3gR-6o@AS%l>On$Px85(00`N2x(?IySJwt*KY!6y7?yWGNQv7S zIV*YO=%L#G;_94V)cogr^ZT({)rxp?Bb_ZtA7ZF_P_*9w+dGY(iT@8&Y3gt*v&>t~ zdZEwuzbAp;C(wR-AP!ijGaexS0ioClSleWVNb` z|7w#=jbJ8K-L%;9JAf`*+jh`WOZnd0^El1fe>;cumdm&50fsF--!4wn3q)LMzz z1nk#i7H&O-j%;ye`O}LEO@*+z;QYFJS#FLY))CaT#vSUD7mqr=+xDIZcXqQzMR8l} zIdOhf#9$4}zGXnbkJwz;Pw^#b-$pD@#^@{jX#V;4zZD>#D_5?SRiT~7p^}_&=yX4D%&u|@g6n0Dzx`*GrF)*#E0m& z94hH^=J`2P$v?gI_s|dpI@Lv`i*bEon`sSruwXsWI{yfT?GUr9b2!3e*3aOxU*{yQ z7ir~SjxR#xj~YHAmiD8?MkMr$w`p{sJ%s}*Afk4w+y6S2Op7r?XU?^$wz8!QImZ=1| z84xy_aicQ%q$pOKR+H#8N${pyn$1%~Kn|vy?{mSo?8}ku?CMq)RiG7E=DN~25Zk2k zfO{Qy55l`e@VXDWB26-dvR+4QP^Wq$W)0dH?X)VO9|rkLZpGe-wsC@?D4?J+PbQf* z>A@_N1Ka^f>wNXwk!|bG*D?vk&J#?KoW061fMVN#TZ|3EfxTS{0lYp}TMLd_tt;AM zwYe@D~G6yQ_N>eQi(+y6%|8+*uTA1Cjnk=w^0XpO&+=l)xRGXn+& zvPe)hz6x5Gw)?O2*x@_VkCoey5Wdd2>7F_-4)(M{scXW{I#wH`S^&%hs&=% z+1yP6VPVuHf8Fzfo%>Y6q>@yzq5Qv{}ZzG!5QMH#C4DTWxeOb zyX?@14NtC~g1Xco*lp)6n(58{DLMi9$!5(3-;t@y0Z!`JorR9rep>!HduNCAu;JVB z&T;P1_(SD4zjLX}WqjG_(a=lWnb(3#19Z;gZ?j~NiUkogCJ{wlCVI6iz~m-8hv@>) zq}p2M2opX76amgh3pDH>_dSWEJKfhqkB8X)j>;D(m#8~)BGV54%E-qyE&~L6t5VIr z6XP3$bVroH5K+eNDVOri5pzeBMFS1~W2j+|>D?)B077bQKXq#qpEOo?vg|T++%ZW$@#xPru_1kwecD;Q3d|_`Mwbok&Js+B@yvs8+ z?H|2!fZ;N;?^5rUXIu{dBEl2EGEMz^0~_YO?CfNa9ZrTRXp<!lL8KbMmTdkLXfv$fwq`u$OJ%S!aQ0t{L6lXXh+%LX?ht& z>j%nXsX*ySP&!5zf>Y0bC)IAE#nppbuWIru4jixIkr{$E4q(6 zIlqSxzIh~rtjO}`F3$coLR9`R24GEJ^?{^`vtf;jeO8~ zbktvXlxy-%xGOywqtPqQq$xGQm2sd|vXwn(yHgc+0$~eryLlOR4&Pz&9k6j~9>w#` z+%%4=*5L6JhfCGOL(_V!YY3cJ?Q!PKAoFTCvist##@bT(uWw!ddw@cy)u0bL#4F$X zwa*QCcDK3)Mo*XX2Gch+#%j>PFUmhx)>bLXw7b4zHP8MhWcgvmRz^X7qBA_O+cQq{IsRpaQ+L?wu%s7aj7c!g-7wbP)D8MslRn z%=N~B%h-oD`y(Xwr1?%=fg(6&_``9OqHS?KelM1!#h;%K1rKgdmTh}dBQ|& zRkb7wSZT%DGMQeqc&P(ttN@X(_VW>#Us-F_lhA({6c?7l6_ zgu!qDhmm&%PS|9T_B>luZuLKX;BErFXzuQhCdS+y^dt*I z0;`31$0^|TpuHb@IhAn6=u)N8=A_)|nlD`GOn6glYa;^l)R`^8PUR}Ig=(Q@SIceK z=aS-Z_s1=qU z3Sna+RW_Ev|Cr~l;t?iV;5e1k!Lr+IdI+$Q5xW{HV_*-1c3Mo2wFlPn`De0j+{m0l z3bSOHyf3s2-?^qKg-KXDfi-zbX;kO~Aoz8UIfAL()Vzw+QlY{&QGv)UhiL5l zOk)Z`^IDaqpQ*`9t-%W2w6?Am@&Ye)-rk+N2}mDnUQWmvfrx3Vd}P;(_3Si9f-b)Z z(m~rP%Al!rWTo}EKRbuc(y7QV1w?;7I2Ok=G&=}2k)8Q63h~3Ky$Yi2!LJjMTetFD zf=I+=K&+NQF#<}mV&Vs%^L%w8)4aK`7^|99zuDgPgR|2W+p zAkr^-e1q_hJT41q{FCIn=LogFRH0HQEqt!;oj7tOo4%}aMtBiey}1}L?$Tho`Y}#! z0%fMO0Nud+n2fD*9_VJG(%iI0`+k#LAusRyWbG%;_Qcci&cDNtw^_LDls35qM#ne$ zKN7E7pk48r=uw?b0sH21iHxPC-GsnxNPWOjnP9ZkqP|j*!U>KL0B*;7dbZ^q8Uar4 zw3dbUEd{t`Py}j?P|&pE4&l%maApn|A8O+c0}00%xUM|KjlBe9ahu60G<14AK5(h! z!81rirbV6O10l;ZD`YU#`HCWiY_A z{*4F>2191zV3*rQLuJM+4ZmjXKP|!*%AJ>rtv4hK{v((HT?KnPAOq;Sy z&w?Ecc&p*e4;wk(c6!eZz0(OZFjiR<b%2eh-#?@P{S9 z{?V6jM;AFvV zNI2&4=$qdAUl63N-gfbb`ox6wN|fgP=cSIVOD^5^Xzd1<(e&LWzz3om5OB05B7P~& zs#Yx<;YaIDHDVd^jr~)B3L3?{A!UzUE3uRK?y1l1TJU?&Xl+f8J*uJL!UAq3+@P#a z4VCDwE&kkwyH^IQq1UwEeJo!{fNF+IDQa7Y_ed09@g<&spzy8S(TlJ`ux_xx%6d_+ zZ`}EYh;G_#+Q5Bw8ThzW^FI@=L}KZXY0T^D&$Q=94mw0v>gnduaXT_^4GhfcMF_$W zX6D2$u%XuMZw5M5;8HLw5uu3G3MovKdl@?qt=pOv%HBd?|O6eWEnyG zI0OXP--{Qu&l~7QNJB z8naOe*Q1dCz4Zx33zNV!O3&{aAB`Aj6)GP=Jg?m;_0@GYaQ4bU^_>tf4e^Wq`7X6als6;KrevVPZG)XiR*nr)O z7lOUfe*<&l&4GwN0BK(931xt_3vN;PvWf-EB^^F zuUYUER{!6{tLQGaucht@NRH0n2CEmRqD3l`Q>gzMTwn2qS($Ol{zUyJ(bkwV%0#D{ zv%FsE9#(&-BxL6q=z8BsM`%`H;las%&2|84@=soEn{Ik#HjAEhJO2wwL3}*%DmVrb zU|4l2pt2n2Kg|=NK8Mv5zyS*zl0SnXODyHvcZ3^-Ta?~>9sBbJ`-bcOb%ygz~@AJ% z$f!tLUVvo9fZga6u0Rk|i?*sMuW?=TkT1O#jl!H+N@(NHQEhTQeBQ4c(xbak20d)O zx8|Xt`oav9GJi>k6}~;M!R|2;qFhe{eCT$^-Oqqp=K=Yzb37xA50`!)S04it?kc~t z{Cqi?Me=%j^ghp$1sPU7}I)5xso@W%i=uD|W`^_gm{)t6GfCL#hWKy@dyG)x7y) zEI$x7NIb5ayYI*TBUkvp-(kL&YQRGD8VojQxrVB$%^z`%r2Y+yo2%e&qg5WIDFn;& z`E44uaN;&darlZ0^Fs;Y%?s`eS51N;DLnwM{KxN3T>g_dAHnA5rd+`3^ zmIf+;V64CA%!|y+-29|cwGlXcKHKC?9Bx+iVNur1AveVuQAQt?K-cI?Xdri{sBGjM zsb0_MN*VBriYj^ zKavNiZP4wbRoQV4?gz+&s>$avU{;}vFWSw^mZv3wG63Dqx3rn8wc1xuR@^Tg&la=Z zD-&1}K;PW4Me{t#s_xfjbsjPEHiDUbH%zYGs%dKL1SdUosim@b<8!y9_=zduZEpAg z`?;?!0qW#B!y(%8Gksm$3vt@LR!YkcHmxY}(^&zTt3*5(f^P=jYh!s;OE)hyy0IBYx=_kYze?#9g|eWDgpP4&8^rv%Ptu-ko^Cs# z?FmP+adN_s@8$5QAf*NQF$lFtcUtyHWh6Q-RP#tkM4>gAKTH7cHx{}MPilZMGZX|* zR;$@$YOF{t0l++ig&fsrnE0GM6sxiGz{rLj-;NT@=I5xL9U&opo_2?LV1IC7xRGXeEXy?VzE(CXh;4wIWD{);jR2Y&g@8>Lb9W@YdnDVy25#V$|v; zUwo=k*r8fNALXvO+=T7qABq}bhtXg(UR3PxCn(mg)~s(cP6~Ulc)%o6wVn3{_JDFE z@D>p9AT)UA>hnbilb+OhT~S6H(}k=JGMIbKsSTJ=vAYZ08ilapIXftTD$?MoMSTO$ z16ZbPh>KWtUZLW%>eWGtPw!sXWEo&|&@u2HsZdiQbiNssg4G3-(Ze1sP!++^{`kd0(IQ<;6QeBWrU_g1^2Advj!= z(#3|A3{@pwuNge_*SW_rG#OG|pubXEk;|2S31vm@qQmz%j4{FWbN5zS+$W=FfPiUBr@xKk z`s$FhOX03^Wl#~g-IFYOU5nh)!wo*b*By1OS)7%j1-=vMBxh7cGPpXH3oavEaqto+ zI5)>hgAa*1)~#+X&+0;PnaX7B5jwS0kzkN{#sYO<89O`&r$mhr=gdgAkp?zl9n$7{>G7^>g&6Y1B<3 z=Plbnn!e9=OBMEsLrY(-hOA=?eELn>z2Qvg;?_SZn!Ujr<~iJRfzY{RcbvrUU#Lr$ zSE4pdVUP;Nu2%u@9_a!^pZuh7oc9wstE&v_AUzPKeq76NrwuiF;LlMX+De?}Ga=qW z;&E)q96zCjZ!K3Zm;hWs#=@_`uTI#88elW4T-*ss5F*sU9%!*CStb{ZCHk-uybG(Q zKg;AEF%9gm;nSV*W^Adjl<|`*)YDl6AmBtLAPFD0<)wm`MrLIKaGE)#5GC$fsEsAD zHk@@IqEDjJUZ2axf#boY``<3YTUW!NT^v_TUU`Zo@P-#UOa5@>eH{Bz=t-`A{7imF z*+b?#o^3s;w5-U9Fm`s)8r(OYmydYO3pv*3d98h0NW+P9Y_?5bK^D=lnJL(9g2r!qJ;*;UxBG1)7| zskQA$zUs}(=mTs;K>;^KtW?{G1a{e5s22LwF!)8qZ2o9em}+os*M*_(R+o~^Qu7lK zl8A|Dp{JSxkqGiu>B0g_Z)Ygini}nzT_zpBrGdrSv2@k4YG_|ZJJEdP<|pK1Yn|dp zg|1SKbbbouOSmni9`EeR12R3PVTxmwEnzha`JZJzN{K$6+ojh|92|CAVm;k;DJc?k z$;cNS=ow&BeeSRJR^IQ!&?0#-)hQ}wRKpxLpG6pH(4vdMD{N3chH_G~52*>cCTCig z`Kmm~BMx2^^t=1=O_E}oZ_03Z?)Hv9DG_LBX_5r%;vq9Z@?aE4D6jVK7-LKm8%Y3# z2e**JFe=zdsCqyqYjV4lsoqS1V3v4>fW#N3!ToI@DkKswx&+&PO)d%9Glfwt0%)L0 zrp12XijBscX@d%fUiSBxLK!4XJcVjeli`#+l^$c6^b*0Q{#Ke+aq+m4HLoT~ClLU6 z9R6((FiwOIno9esQ3eXV0LUJK3{-$!tTP}Ob2?j7=O3G*y>Zn$&PH}u!2ZX)E!*8j zyLF6Uw%k|n;K7!?BlfnP%`nAFC_|dC{K;qnw@x={aI$Hgu4rNKchM0(Kq@H31Ri`9 zA@J7(ai%C!LrI>=7)y~g7P8W2EC!cbLK$PI${`E?k1^Mmj_3=)fs={KG4N%xvL^xg zOUF%Kb1Zs)rTN%bvs=VYa`^v;NSXW)=jnA~j_JS5J-w;mnLX(D;#e_eMWw z=7E9RX)7j(*`C9)#yoa^-V_iL`Ny56?nx9Z9WF!yhc-LdyJZ! zfkz+{3^4}U@$(>5!e>c-AsT|re1$&%A-|Y6Vey}dfYx;2&NCZP1%mtOf$;p2?&ap) zw2jw!Us%11jCD6z2(@URO_KABl+OsmDj3 z$_q)bT33XgM7q0A2_JtI1a?xCR*;T$T&ZVXUTqrria?Vg^sNQ6l`^o8#{dxNRh3{}!zT=4h&kO(NG35VIUf7xTl7AEU>EE)LKS9QX zLySY;RwL<8tTJLQG$L{XBIK?iL(6-^^dWJS|; z;nE2tpBT?#(W(bQRI7O{*@@uK`J@)3Hk!+O_a?YGE9F=%EvZi}#`ryrEnDrd7Y1T( z_4WjoxjAGywJ*biL{DoF*qlEfh=OL{wn+u{ zKraYyMe}tGSjrU?7^d3x;ivP&XzGcY3z=sIAS7Poko-uAL&Rwb>=`&QjZ>?3cd*3P z7Lz*lAQe0~g(k3oz7cP&?Axo@F^3RQK!DmWrI`JRHnFlV zisXL&52uwgP|GE>G%Vf zP=wt_+rOS%^cPsw51xJbIZK{!>C+R>3#JwS4St6LJt_^Gwh5!f4)zEjl;zV${BSkq z*>83?WG`=F_1 z$Zt2DuQ)bbU(7iP2b3H9+mW$U&P^8Ic*wJv5wE3BVXi3f6%UaBA5a>_7$b-t>eMw4w?E@!z}J zS;umb$q2SR5SaO)Br-L7NqW8p`?faqR>S=huU8!$bf(s|e9t23YuEE7VL97ZaFD0F z9V5Ok!RAM_Z^S_`ys5s8|J_A6x?zumDGcz4QeztWcMdDWIs@Rmcx=5&vc1(qTiQ2c z=a`Sv8`q$b;u)0|gMM1`RTQUtPKEvZDya5Rzoj4CY*>mXvZw(oYs8*lya|A*nS0~^K>gP-^G=t2sxP z-kdeW%oIe7G}>c=}B38fvK>oP``xmO?)nz6LX7fBSdm#jJ2M zMnp<}*|Nh!ydviVlPFW)t7@#DS5^5hxd1dlw)V982-FXIG;06*1ng0f{IyGzWrfZvuA3tOG_e{iSLN7t)!20yfGJEA-*yIoEYU<9Mi%yqQ z)9_#r3C4)zW_TNV{F2++YFZv+{6MsUVKhy$RVA&Ec>OZ^y$77q>y+$oD*3? z?5f5QaT@LWQ_r4HqxGXJ!A|SLC~b!rySut{t84Jn`kfCR?j-7?{o&vSHG~4X(LR^2Mbgwviov-Z9W0( z!{IW&B))B~bf2g_VuOggddr;warX*5Q4^PI3WagDs zS8Y4FeLC97k60B?E-U~i;YZ*GHz=vcTT2WQ&K4rF<;^0e$p#IPf*bH{a$|(;PRnjt z5P#_$8P5FfPj%!lTD4uena$oGvcB9@nTp#T0o~ZM{d-jqZP&1`ecxdrx6&&QPh+zo z{dW+U_>}`yl$_4XF4;(m)_}D#LmfIA%Sc7Ld=ipRvP9cdU!O0>wy;X{H$Kpm5sUt8 zIn-5xB5dOxVFGs)EstPv(O<+K%;819;IdLwO-css4ZcsvGSJ1g3Ij4hHAoJzAiP<& z`S1kZhM@QC7If4JU8#XwFGmgSSVY->Ex4D7qDR{qF|-kdj&CmoKfz?_@o1+YaAwO^ zv*mTP&P$aD%vZq8;V7e+(hmN#!4;g;JgOK4m~YqP87VAyx%P>C0bkmLorv4QWL(UE zDwU;_r^zfqHRT0Sl+2*EAS5A5V>KE&j4fpn(T5iry-vvb1Az(i6|K3UmWnn~<)1c6 zR?3ws+H(r76kNDh!zH?_uvLN^nMe+=3Cf05>)WDS7S&%5t0YD@lh!mCe^JxRmzIqQ z(N*DopJRJeC*A$Ve)}FuTiNKk>@!6t(R!d4G>5amge*7rE=7;scPT*M=K$%f4>Zc# zB(qlEeZ_leEOD#0Sy0^x-0S{qmgc{F`yXfwZms(U02d%@kto|yQ$MEe+1lveA|$rJ z^Rv$@J#e!eK;1*r1Cml6+rI-AOvC`)=u}TjE!MHz?|R0U4}w#3_7Qa6i&05_8n5C9 zboU|Q_*ch(GX}zDHr`?c({q`^0V*lirzUYIhJ%(bFv~HR+&WJ(sF|RZYPXU$RBb|h zi7k-C*kUDg;~3Q4Fy$SQf<1V@Var)BXbKrBm=Vc%+7Lve$Vo#_8;>HGtHr@W4s-?WZK!kc3vGJ6N!{9M>SsJ1Tu-T!%6h(e}apW z6H!RDx1OyG(5n7~uChVoR`aoVoE!PRPK|*MNFin63~c-HvALIjj&f{izIlJ&>Lax# z2Sc|wPmzeaP)+?vic2N79<8wXwgvK0w3sqD^v*ArBRwP13wP4T;kXH!4te|@GOtk_ z+knYFQ@O@YC>f*n@&ckRo-)q1ka5~=y`%BjsR2c4bf&wW!6F5OI5|PjGm^wG2)~4E z;N)9vwW-IIK19*S2kZBW_+#|5jb)hr9C*(h6>&Hq!*V^X#$W##PA&t zreCDKl%qt0$R6l%y&Y6esT0Gkdq`FGXos@vp{~g=;d!1m+c$*>&DnG7X~>p`3)@>r4cN zLa-~J$FVq=)}#-Ks)W1K)hPxf$jBlSiC0x>A{rv@1(D&A+;MhIyd<(5ROyD0$(59(L%?;`GI5k*OV4=f4eJ2rMGpm8Xfg=#>`__5T% z&h}hmCuC^6QHK~Q|De=n)a_XlXI4pXmdnqgd!L8{OzSB&I3RR^$||VJJ6weBB>nsO z`MwP50X;Y0DEMjtDda# zr|=ne(}BkY74hx<+s=cd;MRP-{zAN>W7uPbjsmGk#5uR;+@T%TKty~S8bgUu)6ke5 zvV0HUStXJe(Z};K`p8(Nj>}UG0bpH}gXL(Q=5(z$?GiWve2H^0T7&FN2_=yjj_l_K z$V46^@Ak>SIi=~o(xDbGkeU76zQlC`#W*oiS3fjS+%e7X(!nAqk7RG;;ekRB*@7>) zaH?>Byx&+b6@s}S2NL^=Y?nvn+PL^IKv;GoUE>UEf5moZn8zUB%jo`XcNma$oBLCm zx<32n+04_V%l)eDi}%Q=lTPcQ;B|1b%R8Eq6(SC>YNhXA7niY?+RPhfXW<`%1;aKEOuPOhVAdo)Ivxj(Hk)`G8Ni*6eF;3BP+ZhIO2?92#>P* z_7S5XNS|s14DvKxoRo|d;^L;LcR|aD3@y3)c2Z|!_B@^PL{;Vh3Ax3M$Kpq?-Z~y? zAT0h20eEXt0%vZ5O}E<)-j1sKx{@O&l`pN3N zh|6jes?ukbH@>wQDgpZ0`nCW#% z*T(k;h}kpX@#^Y{e_gMZ$G7u8!M*j)9Q4tm1b@7tUo_mCZ}EMzv_s%F$w7ez)nwwr z!*}~AkSOT-)TpTxe~^~aL3b!*_#+RjHxRhK)k{$8lnr(_lYIzz6JI1f=DQQP7Dzac zf=EvNQR73r_qNpLny-5Z@T=6L{97L0GADGcH53oQvM1Dz)pkv0Hy*mZEUGTf4w)G0 z{m!X>|AU*`ygO6G#Uj+jpa&oCj|tOx<5rYr4JUaex1?}3(LfALAn%({VRwG+qt+b) z>5pM${s}+ou$!5?Us7tux-tPXE708NH*52`4PG4`uWz2IYS45&zu3 z00r521C$b*vSBVe`aqv`h-C=RqRDoUBS*#lh0JQMkZG7hPTpIp!<-Adax~GZG$yek(7(-U%zHJ^(JobCU-~c=@*_>^ zyP*1a<}r+S(XPgN8(Z0Rlcz#PGcixERZ8u?fH=wpS&)^qtsC&p#K~R8zsU?oS~$p+ zlhNfHI}5dXFo%1meey)3YL&|JW%y;&!|CMQe=9AuH3n5m0$&|s)UY5eF>);jM$|A7 zl`KL6`8FuAvcevQ?;*-3I5*5XBskQ3H8dNm1+4cG+5rRTe>&ZZDm|KD(3XsS5qRCf ztUqgtZHtoE2a!QX_GF=1aKDYgZ+9TpM#o}UfVJw;Q2qGrf1p}K$@woJ1dSOw7SHhj zriC`~a9N%3@-tDPDli4&b=VuJV@M{8ag{(vC5`sgY<_2fnS5?PLOJDNpdeO&rZb?Z zG3tII50`&yNZ3uaMnA}8%&$Q2N(!2VK?6G>hpnClq_bYqzvgtL8uWabbPyh}F`|Gr zWd?p6o2s|-vKjt7xkM7oe1IiD%S{6$7A3Fl(joA1sF2%53?KyRQZ+AKR0~s5vCI=L zCS6}^`yH70zI%d3cL0*O6iKi@BsMzU1h$x|GEpmGYDO)NV36s_1(Qu2GjF$f@L3qn zR9_FVR!apa63N*pH0n2Qx)zGEVg{c?9so>K4&-a-nKEIbg>+=+J`J{2OStt$yb+v( zB~;Kmv7%k(H}8GCTySU|2++PeP6;x-2&EP}N6$YsHM|gEyN(dN(mJ%=p&Z*q6jaCh zpE0@RJG?{>6+wYN|7p)AF)5p2S@|owuiUp2$R&_>UpF4YtiC52!P zV1o$VfyRl3Bvu=^tNnpy4?~#>A=>w!i0H-8JQ2UT9_q3Shw#DzQv%C$nZnp*k@wLg zgxrs%VfAgyN8JDj>wDbZ8UQ|{q`KnqjVI~|F(-TIw}deh zL+9_yy0qq&1TT3DGwo)bI>MU`J}{v^LJEr|Ajye^NiXsB1q^mu}hH4Tq)YCvJ)b z^!=x=mX8clm}U?~7{co0zgP+}{X5U54nX3k|DE1)nf1oeJXYx*g;5*2HMui^NbrY#H^J%Bc+#Di7z9yh(~bu=iJ5%yVS2kZJRsoqL4MF-Oiu z)dhL&U&1)xIOqRLVz+yxgpY;vQ}>ViEgUtjeIAHr9%n_b@P0ivJ&ONGtHBdGCY|lQ zMZxJNJzNV~{*m}Wuvp*;#ikv}v&HysLlj0SK%W{oqflQEnCq<55VfBs@ha_Gio1LoGEp=?&GRNPiLWVTu?ker4e4Mrj% zMlEXM;P7p5U2_42&%oHQ1gr&K!3D}KAS^9;WU4W}0GEYi18I$t<1nd?Z3h8fr<1@+ zsgo3_R_+#P$603R2e zyMr)HU*n>lVnn;@L}~9X(aWj-m3l^&dliyWepJQ(1fw=O_uBQ!(W^sR2&gZjm=(PO z5jwMz&)q06FcGx{qba$-+L@~X)=tsb*$#W?fhDG)6IG&6qrq- zn~H-xej%k_ZDW6HM%={*@LH;V5|P33kmmxD;jdFL030`SD86i&#p>XKU~MEg6UQFb zdcDombo45OIy9lMA62JdP?5_{NUwV;XNMBF6GnrMGiNmGd?@FtTp6S`3Dl=r8j z;1*jL2-Gp4Whl6faJ$e-y?&fHA1@9 zNqliJ!lour$V!lwf%!C^#+Kxiq|P_Yqup8D2pnU;5?mY@A@2ezVRme*R)UFLyCWfR)u;T@61rx&-A&K}RBEl)DdR1F!+!Pa&tMT&@R*bQh z80yX!u!DlUu!OhBm)~flbGuPE1X^e9lPJOh)NJ<;R`JPZb|iH7)p2Q7=}=L$A@^oE zIVc>838qW#9j3~G%J&f);S3xy?=1|sMkMm~dS+FcH-mZjko}IZU_nkfp{3QLTf9^t z0!h7MM1mJU3mDKnliKKZ=E^ucHr46rsl|0fb3U2QSrX-(jd27X@wCx`22VpZ?Xub9 zffs^%?E~2c z__Ybd0S)KyI^wX^L@uwO8YA7La;u}$v#^JYMCl+uVoXs53}HAZjogolBTN@m<&SEo zP_99yf~5`ud{EeqfZvyHB2rFY<}(G0(pqCZe;JA;!OaCKUGDF@9>5ySV!_OcGkt*g z$g++75v^s9{IvSNq>BG_Oy+&Q#%OAI$|1E&AGbG8en(wU&_#u4`Y5bfr4P`hEaEA6 zrv0}+q+DnrRSBnSZJ3^tC-FI)a0r8bw~A<)-)Hu2SWE)#Wv!J5IpU^8xZe4Ot_nP& z!$NUR+#~JE`}A)Hk2B^q!E-6$b0w(_I;qilO;PlLqGDlqgb`|VhGly}-u7$(juvg4 zKg{ow>>=MT!3@kTG2=UgxexSQ2EAYJJJrAgy-;tB944`^-OD%VL<37ze9j)vj)1r7 zrdO~eGOoFjyVZQ0O)a7MVAJekEzej=;;sl5@_TOlHyX0oaV!L%^^gJFDg^2iCns-* z-ChSoDf+;4_E7{*f3pbI2z+j>3iYs3D>Qe zT{lVzP`daV{HHqCxuykj7nr+#E2q#iNjL-HbkA3lGDc82tMN7R?P`O!h|U$s!n0!G zdfjhg`0v+?pZtrk0x>%0ZSRiMklBpgYK%+1ImCLR#gzdEbO3c2^X?$9;@9;seUqcM zndr&rLX&Z_17oLTvKCFA+{fN@6RpYoxr|oU7|Atp$}QZP7{p6)gnq*qZrw`vIIewkf%0Sta1?G_U32UD?@E`;d3DWFB*Ha7w`M-kwfmU z(=5c=1#X84wE}DV=pFB~<;o`Uar3)VVuD)t+V(($SfYLc#fnGiH&Nj=JQ z3H7(A(-kio^+soWG*ZqRr!0Hm_gU8HePob|sySxeyFnB#rCXH~ zz1cc@sqhRYyHl}9Ng%v`rB|5kG4PjIqQ3iq}s$8~vi$TjFZ*wBhYC1ieKFR5Srx#ZRoz@uiFt0)@#&uqjWzj>90t#K}q!_A3r9j&Gsd zdyw>I?PaWxkjuay!~Jk#3E_wm<-$B7EDXcPuOUw6CgYmUS1@#`2?L_%;BN3v`2jMP z1p%FD7U{V>eDgpl^Fv}IX|R>oSAE>bJ$Iz!IbPmZ%Mr}qGORIRj+AnY4X%4Tj7hVr z0Z$ANXz^05K{P|V@|v(;+0s6K#yAbL5FnGpxqGEz6R8@37QmY=@m?Pp8Zgxk8*SeM zv3Q5w(Lon4BfA(gZJ3f2O24yq6It$E6JVpUD@gp;g6$zKJqUi>Ozy`a)|dln8mx0f zB@98mg`PVI95^0r0JR?fo>>vr#0YRL7h^WQQg-A;nSE=*$0cphnjMJo_6FCRrX?l( zXL0*Z3X0U$5%DzX%Mw_QK#62FO7wIw$~Y@D_ll;UhN~|RZ?aZq&WSFFY;L_Ds4j&S(6>=awc3>@OZgcMS_JO2{@MD z3jK+3lLzPGI(G6cH@82hBMG}qQI^p{$%i15%D>>C6sbHPRd8WU%juK8NaHB^23E_Z zbS82`r%UT!thJ8iV{&7m-*adpGNFVqcAB*#dcWG4{a*2jaxfi}MqAZV0$j%LEFhLC z91AR5IP^UCDgXkHXWN|Coz>wSVB`%r_I6=7UrRd$Fd zhqO(l`L{OrGBtwZU!yuZr`PEB@Nt)<6YR0w0+Ui4+9UTJQmAz*ej`?{)G}+{Wm*%m z);4^7;{qPZi4~7^xF~340hzo%6w9+rcQHfyGYuimq?anU(2EiHZTWmV7K=pf{yGO7 z&XjMa3Gilr2mJln)JpNCdX}3SXp*aaLQ1oz-Mldl|C>nj6xS-fW3hI<5KV=JeayYdgFR+Ew_R;{3xH8MFAQJi5YfkOq)Nz@tn!YqENPUs^WDXgd;bIh zzsk4sl)?Q}zu4j1EZ=bysBfgSnUeWaNNFgSD4%aT3u=Z%bsVD_9Zo+>*mQ9=)jF3QE~N@7Qp7(9}axPUIjTWS5%X$Sp#lEBCK=rzps+WIlI|C z$}kEN5%219& zLNUtqPsdM?Fp(JfZARfGXl2>hU!B1HNA~Td%2g|0*FR|4Whrxa0*fE|3oz6Qua$%4 z9S&wOB@^Y|OqRF-`pWzT{9qWWW=Pz!*#Zy5!c2w0_&WOyB;$`y4KWp9dJ;10!UcG$ za65%p>|W4XBe9YpwbSw;(2;x!SO)SH0qg4@!(_l1E7-h`ptwb(4pQWLBba2sP$Z#h z=Mki|)So;Lrcx+6OG)ryOANzCkINkR$p3lLpL6;jzUN{JaTYN;4o(C?qv#8X;W8>$ z{KF!ZbLd!#Gc0Y_2gU3KSb#uRt2D=k?#pzQ#)NC%C4ryxs46OR=)=9{uOfJYXp-SR ze6zLg3e>W(?Q^>wBzz)9-N@lfws?_)=v2<8aUq8Kt8#aY@&(`1ynXkCIZJGj@P}>hNMy-@l>w zybH!iN&wGP6MBFsVD$CJM*_sMi4Fr&ExY z0xi?>j931(Cs_4G*m-KM5g~;;;&osN4+aq+Can<`w(i=vwTv{hN53PnGK@!%I=VoT z%3aAsCaFd!1n#3JcB_CUcovf(S}nIzWa?f2Nk~vJ@qW;>(Xkxu$crsuWy5ZYjTq68 z_H>!>>%VEUt)ylQJ&=+|M@7t?I^9dJq26vVdEn@}!9`q&pUlF)+Xm1Vb4C4FI{thu zt&is`2X?~GmV!RVq)VmeZCxk{HBi+89Bkty#ZYU$n(60tG~3Yz1fyiAH^DP5_NX9- zu6lm@|9jhc$jzx-P>gd`QnFB`6 zwTl{!@A|Mpnru8kw#B8`P`@kb+g^|H49C;?3Q&agS4&l&FV1Y=L~aRYv(CG$$IV6? zIW@B>ky69K@LCW0CvffmUa@`Z{BaSIY)6EVwU%O5$RlOfNdxQgk)dia!5Sjk430wO z|1QIrTuRQ?RhXVa{u7KahA{W-pHx~$QRlVb{BN_amAqrENL(CEA2TEWZmtDW%~rjE ztJc8A>8&kK4D$H^79}|4+G82-*dCwcIK3^=X%5u#)H5k}{7%o@R#)nYI(Rn&Y;i-k zAKNwPee-0JSxpp)=6`B?9c>$KWXTdJa_8MX zcYi5spK`%P7l(*&kLm|=be2jJ%GL0dEP?pVSHJbd;x5)&?uAToyh`UAs>C{-$=_eo zMm~;YgTGgu)^_1b?TOzT{|td0NLiTOZPHJUqQ<(zxp#QZ75iuUeW&3n}6Bd3SG!%Kfk$)g!f!}e#yzN zCTktRPk01$uKby~%6>3|VA$pjr*LL3e<#fJMoLaHr2ee|Tm<=IGpL}PwEVca(naHM zcTU)o!#YwA5kxxHK}DhuF9fd;v{_n9QN`dkw?zYl$bWgjkjy&b)Sp8R7&^^&$;M8i zGOV75Nj$}V){kvH-61VUA3rK2z4GXfN6XRP^2sqvni=0LCQii?QvvO}JGItl3Mm{^ zFjGF_JOpQW)zkg1gWqnBq7EZZ}SNKps@hRveJQV9i z-fW~jj(t}KgQtepCoHo6q$9!m3V;7yKNEs{-a9GV%a9*0N`3&bJMrg$#C&l}bNM&8 zaaQ0!Cwi7TdoD;6lZxEDx8$8bRwHpZd9u_v0x`2>3-Ca(h;c`(z6lQ&?tQaXJ05`o z0xrOy;YpTCGC#IfN>%ktfGX^~PoOg$IlobFan@-?mmSh&Y~eiwTz|>*531@tIswm2mSS!LPcH#T0&Ry&Yj!Oxb|X{DjJ8` zaA%Qb^G@{zc;>Jccn^o+Z0iaff;GOSs6N#8?uVm)=FExdH^8vL+>jBS{M0;(}S`bOp!d#<0XiSu#nJpbxDswqyM^>aD-$*p}zQoUVBg3 zj9x*N=0}=Ht`SQq=P3eS6vj;Tc}_sgrgXJ@s8Db^Q0^So`9H!$7syhJbIV@`lT)=& zn&|WL>h4PYAk6G+Muwmn8G~S`lHz(Q0#OEQn*b7qoW>(_NWI*z&L|qfW+I{=nJ0{mKixX zV}LXv-S@DlW$Otl0tjSC|NT?;R<_h&jeU=gmuv3K!ue*b=qQ`>Ph^K%snF!+6+FWD z0=CDIx_OT%@5xj+tbly`PAmrP8~?HeKaDo}p2Rg|!@~ETE`OMZ{s-06q_jogoKG_7 zkvV(6@=D1To#L_$NFh00)n8P!9#NPFhV;C1(egWJRfY{DLD>x3c28>eZB{p1U`gR= zOY2`lE+5j*OrBdR)O*ukGg{+xVk;vxd+VE5+_3tQAARRO!}~mgmsYB&)1wUd_0z=@ zd#}p=xw6Z8^-$fxA5nRE=8lxFeg?`wJ$jZgHU&_2ez+(oHhg0@*;o6LaOnA&vl7n1 z=qQ9$qNXcXPTqM9I#J*^`RkP=wv~S9B+f%LF`ok<)6G~<JN^2uLb2g4;Z2 zKt0PXrdi9I|JlY046@P33`V9*&w|$}Nn6t`OopekV;-NN0|K`s?CGut_|bAz3Xjaw zaOJ_z_u6CKe_$q%M93j-4i9*-S$O*U$sVfF&vfs>t5XLsUK5XVQf_t{6=Q3Ta680n zLEJ79ObUuQ;>bJ_-9IFIhl$s*qP#4jSy1IA#0eK~qfIIuOKculk)2P2a2-7Cl2lO^ zo36Bi2)}usJeswU1iZuG`AtMgMjZ}QWwxH+ZnYT(mav<|Wrv3F;cb>3T&xaKn~Hbk zhB6v%@?%Hx37-^|gt4=pH38FpuOtD7{PhjmCS4TYAW*0%Owor!a+fD7OD^e#!YLkx zOS=oR>tM%?Z$qGzz}6*wPh&er7qo3LBfXXlZ#WvNKqmG?>@h`KXbZV7{~`plh11(h z?~oL%&a0OYQw2y8UXvPQBz!51C(X0BhwM&|!?tw?-3%tGm6cvw2 zG5L_7DriFhun-nP6(G8=LXZw$?!H;d0*wCRTSeKi{x=` zlS)3dBOdVyn5*j!G0`l@FPToYwx3;T7-jxojlxTM7ha$QC3S0fXwE%hivvAoMn$}X(P;8Tm4WvIfMLU6?<`Q{YAF z#?b{`uD0Sx@e}`0zh5a31vt#&e7y1c9Ru*|4y5_BLu` zYu~#!0v9IS1K&HaHq*~5Dfc%94s7VK)#)f zbtZ;fBG@!`<@?OsepA)JKco@(f;tp;=FH_usT_P24KodiKJi(f@>e45FQ%?F(PKUL zz~t=stmXRpVkYO>8u}qjOBjiN++K0jzub6yGkf9Iwx2!?F7cTs!-)usPx{l8@YquG z){P{H>^R7frsXI6xGUE^Tk~g#VKj6g0(mZWc7F3l<`KV(N4$=weHl)Hn@Q?j{5{M; z_1PXS(I7?*w4IAYH)`$DLrZe6!ur*w8)`WqzMMeORLu_O6?{dQFZt#!)__1-|04SD zx*8k8w|)qz`~^Z@W_c4$+dc4bGFwg2xBK_7pz6`drCN2Zb$rH+!)yWUQ$EFl)Imd@ zposFfJ=w%e_tO&7S3x|X{DLqmz$Ak?rzdhZLwv9Y530^PDDI3Pk!gHv)Hh8|Mrx*{gZ6}p$A#%`%P?s zqtrZcbAh(op9X$3%2sAC&77Kx9Fm_1md&^ug+k|vaV!;%W-?U5eDvUdAsI8j`5ea-*<|L-wz)qj7{7Pm^Q&>PWjC4ZUi|HS$UrB`NI+ zYKCBOAt~$-m4d|pL@bJnqbg5cJy;3llT}y>wg$NL)%?CF zP=3z~?l!-G4ZQtlKs02hJ`D}H9=odU&FHCIC|L#{1LEmZuY7`95vb0c`P4;wO7AUL z50~As3*PI(;m+COqsRU*eA#mi>{C#&N;f?)KJK=WJGPV>TZv9t;);&8+n|4o3JxvG z1b38=ZM#d_yg;3{6puGXTGf;fSP*0*Fd~+F-6XGbI@?4}@Xk=mx#Lf?IUUsB9wl8ks;?hrS|h?2nzBotaDT>ro;R z1!_V5L9=nnU={;s3^6M|?~JpAXWcn$*(}y4F6@czTMN;&%13J}&BE*=$~fUMR%pEP z7hXM8m>@cvKNGa9W%!lavMqA7y&ij86l4EO8BGh++(VAJ5tZXJhw5wVWB*%?oki~V zDHN3p>T1Sx{~UL|;EMetL3s?QttiW9@zUtLK|p6c+1qO5s$}DwTRipHT3u%1b|Ok3 zWq%==xuNHkl*l7m-@%ATlf7N9OsrnTnp;*J5mNOxIDf{6^!Rxg&JKIQ3U{U0grAJ= z&Y`H`$IctH<(mjMV-C!dSXEymmPRZ0i11A9cMHSY4+jqmSl3+GdGCY$5s-}bB}n$x z40ikO*Dw}R=TliIDJne&r2^|4<}@Dh7baC4vK*+xy7Cl9o2K)LSBd-Id@j3qwREj> zdN>A^Q;(jE%vgM|M>3$ZgqjAMUwfz251W?DOM~PiKPZlPXX1e$)umV1?+B;Kyu`uk zE2D3Qz~qmlJrSb(nmBSrrF$7iw8w`rn&{kRNt%=Tc3O@rlJ7>>!s+KK8TM~g7iK0y z5gQt%M&~M1SD*7zjHv9D-xZGhvoi{9ge2Ou^6b2E|EKi@Z+vz@cr`ox_Z(v5o$)$x z+lksH`=6cBoU40xwDvmCmTbwX@*?7e+Djkmpq}KxiQiDD18H@`<6nw7)Ig=LD(62fR2vi@6=pu+Z-Age;99kGXG0^0ud8?`m&r z45iGZ59!rW=s5A;Ur>^U&RVv_g4NcR*}gHxqb6y zX%^SODPKISC25Zs9~=G{xO=tx{o%4M`s%HL;#e6|zg}&6LmVIyz47xnN_C=D>?Kjg ztNkA_V|8`;a}Z!GJ;Kg~P^)+xL-c4r9$&6w_%*2RO7AG5f10TE7h>dOORKmnIizFr zxSj|t2>QrU)&}}Jr5Tqs)JJ-Zj&d7VAcrD}$RgZCA&v3mog%uMdeV43qpoB6kAy9d zEl9r}#}hz$;mLN(+(`l9LCap)y;tK`%9xV6w1c9dL)1bM9iKvjx&$)ACU`Ir1sRLg zH?h~sM{@)WR#Z(?J|Dl)k|go(xT`QA84i6U2mQcXpAjim$BNdghG+guP_^S9fb2r( zY4DrGqQP%foV`upCtaaxatN-vX^Oj5L6Bn1fLe=##C)!_tX7~!3Hbu2Eg4Xd9w;)H z)EIsn4e;iX#<*~qRz8u@V6Dm}OJ)uek@$DX4vK(%vBB{oOYc1ucf-(mRuY$Jq$LOR zJ3s63iU@7kWqH_1lVZ zK4`1_?tE2(hL_)DM&0DX2Cn?9_?1&o$Iui?8u5>krLm?Jk3$P7H}WaEGhhz0l4V|B zrl#CtW7MVbav}pZU&B;Du@B+rR^^1**dK{Z5s`ea`nQhvq@q5>C3i7e!nVj5Or;OB zBrmaWn85}8HQ0Rb?Wk%;Wq`*DUb32*cQW+hINfz|*0P>;^oo9Ozrm&J!4e`c~ zZG~{*1wHW4#>xO>9I6Q*5vtTkJTnw!)NdyJ?#FPJ$0TAyTzWAdT3&$ac<5 zVO`c)L7YLn>T`jcNx0KC-Z=fre~sUsAOdUFZSNUnQ%7Kfu?TkIQ24bMYPmE3PD`Kr z!LYn2joB&V&5so4Z#55;0LHTSaw)>Agc0Jwr6L7)?&|XMyMjT^7Hnd;Ld8zaKkZezoq%yr395g_If-6e>e{zgux!;Cyf+g88^Evgmn(@U3r7_fe`u zfjp{us|x@@yp$I?XU7a}V2`dadCa5)50X$7Wao*1A5 zH6Id8BHtjvn$uyQ&N6P#$3CIsm0vd%qLopX=9b?rJYW>Q`oJL@mk{Ib3T=1 z(OAC5!;?gcY>~fW`^X*sG@ZmXR57c+kE6x=jX-`>J6hM-oqh93ch7<{(Ou&R2 z!KNqc^Y_U7Ajh)TCI3&(elfD~>HOW1JA&h-L3@mUy=(5EK&fe-xhjQe?T$)qu3Mc5 zNR<7X7EY34VD*9e^sbvK&hDI5b9o zimFQr!8L*>fdbWP9ICMIiogGiiz{ zzH4dD$MshpMkfhHoMG=EpWw$T(j~|j&8gVt##%2~?4kJ!DonK}&7U*PkZt&RP92Zo zrzlm}x;;ci!=d@UN9%6LuG(`}{fY#Vr+xN^OfE|Vggx^vt};@;H)`L634vgEL!l#; z7y?qBPM|Zz^^*9$W0la@M`r&qtfhplWZrUbQ=K2Ul5j|V_pSN@1>3mo;|4XYQkcqeS9=CTP3N(Sv zl9tenP(=}%Q*MR~fREDt=CB|C$+o!O^|zUO$B)XNCf9TG)CcrGz^R{~BE-~`k-6?e za>NCUir1j2NqU2g?7>5;=Bp4%A7^2ehO^m{xYPhq*HD> zrhOah;xNd15s-4`@Ua7a!B%2M(Q=s-mqtX{W9MdNWh{I{?8O z{b&)bbsg}fvjgP+rbr0gi2`n>B_UfXMO!Q=z4$9Rs(M7#WJ-WYw0E?@C&Xg97}AqC zRs<|kJPfdJ`!kHn$ZJ{bLH_c@Sm;mBeJ<=6fjM&ZD(=iYddGFWVDf#)Zz`|fVB8XF zn8)vSz|uCM5zi+D#Z8zusPhyk(cU}4%lFqZ&?rTuLX}MCezM#v9!O^8V|jV9mN*FO z!gy-@K|6-kn34+qL z=*PR5$=YP;%wx`n%LNgQV9|IQ6y9&-KXjUsezZ$hLB84kH;`d-IJmJfGtU;eL4BMT zss{c5tC>n_eZ#ti*vcZXnLn54>U(IctwQ#4cjztD50{n;ULyQW6TTM%j!E)x5BIL5 zW~1+iHnAqptJE8~9LM(841C+m`Pq7LwCak^KG?(-m>WEG;FZr`PSUgwI!$3k@GxtU zr`K1FtL1trSY<#W^t9#CvlW1}4dFG2&!wD`Vd^m;%vTw(EfH#c${%Pgj-8J`y(COC z$(Um)2~}KvRA0fcc3W1^%ElCXUSlY3kolyC-v%%pd0hVXfa=hKCKBTjMtTZCTFXK` z5A@oCWahRa{UUd{R{YCE;959^gMa@Z3g&ynC`;f?4KbZC_h3QUg>kgUaR>2K6kK#Yq0pWtR|}(JE5B!V5Tj%i;obj?Af^p z?HIP3mdi$kMV_(ghS!t1u|x0njsewaHRModCM6XyCcCtb>u6U^zd;sgXa4QxT zWl%paQaG`Ve22+U#o>yGu{Bma8v#PjTGHD4W2<;R%NeVup0z5*t*Bg`d^#>JDwlG@ zbKVL`g->9U)N=aJor@4$R#t#lmhzBIFv^Kg<+q`hgA%|ZW;hrahvR0e?h1!67vl-2i{}+w=ln z*hoF~{H|~j+7)ewuD#KR9cdu;elA-Gdt{hDxNQJe5p4~6GEls0cZ9Hh%)s$o` z!f}*xkAR)PaJd}nC3;R;JVz(Ef@B>yC>U#0$|`B9u)rpXi^rd%bk@)r>LSLfxXcj> z8GA=64iB2)Y21%bgH+*45cU~gs#>v8up}=rtdvTKn;fk{pp9UFLP;H~74tX&@*OCX z;YKjnQ7S&mA!1hx+-XJy&!gjlnA~;`+JzvhM5VEnUMaFrxs)p(kCXVU48~4oQ9-Fc zFuxbe=cr+QMP7q%)hloX4--FU=MT4{LnU8QGrF+PrEdPl5rA`cEW!`2**=K){iJiT zSV>TaFrYHRu<2X&6(FNr!HKZc;Bg^iehZU|lXWtb3rkTFX$SNYRz=xzm)jGhv}~JO zCFNB0bep}t5UsGW3Z63H#~xr_3opQ!UAn3RCNs2DT9_%%(ESLsxp6X^21zWuPnS$4 z3H-gpD#M>DlVw{)8o>S4leGjB10Minv?H`&_MsEPKsJ-9 z9i^o!DRLHFok3i6aEXv8uH1;z)FQ>B>x6P@FMLk4ftenb=UQ`LVUxFNYgY;>QVSzN z?W9k5tssq&Nnm%2H7|Uu>(|R4Qlj1SScF;gD=!raj_!-oPtGvwO6fH&!@WsIbF+zL zYvzRlAkGOl{r)^EKD75*E-wxlmiv?S)i7P7lIBM$kDFLatn#}p5jT;j7)^_M<4bu9 zo}zo_8wrkLqti{|S!Rt9NvUV+`4ru0fchn0xnfhrMZ+eq7)U8A3~YP4qFO^>Wd-k5 zG#{=&WzYTIFZ>S_?5o|$FSy75t>;r-uZOTP}f*)B_*Bt-5aDw?wf0< z=>Bto5dI;$(Q~rHomlzzf2<8mpw(k zu2l2vc_y55XNuqNLjm*X?JvvU?tEc7t+cys>&X+5mP%$+>LyGjINqOV(m}=|*NiuW zKFd;2>)HSZSFYD+`O!1R%lkp@?zXhZutF$*m-<;0uH`TgINE(S}s;7cOMFxx26 zPnq*=str{GWQSp7r-BhK-c zk-GH}Jk9;IS>%Rm7=^P1vV^wlHjQaFjK15u5G9F^lvtv5(MUh&g9Ir!+}+@eaVWM) zbqxw3xGbzbAR;FQdnOZe5vDGO-&jH63xAD7^l@|6wTeE6Zx4HHm~5Tvvsasso-g+k zZF(H%ag3+@o<;IHRHZGr(%7Tg|9ZJ%?%-3#lp0w~TYd=A=nWJHpY;fK zCZbcWAgW)-{kZ@3WE|`I=5Id@AHeunjUcMaj1{?8o}-VH6Tx9^eUgp82SvWh{2ra9 zr9WGu&4N(u22!ox&tguql<9s3m0c!z=#DEVz6{pyrT0r@sMJaq`W04d4#OaeVU&wo zV4`JR6sq_*(Uqy|3s#|BvV3SQ;K<3cLQx1m)_@mQ4*71;I-qL5jsWtqal1aAMG}iE zgi~SzSWNb<5d11JSPLpUaRFErOttc3es1yj z)j^Wdeu1!KBDe@nEEd9)iVAL<_nry>bFzJa!psaPwvaW(-JFoL^7*NCHBplm^hqd4 z50g;^H)D?wLLoc8&p_7aLF&mFn_QJn3TV|Ep~IeyLG%l(j43{-J6cG!-k9i01mniw zD%qR~QuWUJP_wfb7LMXN3fYu5C97}))5PP=m1Oxrs7Bf7uOIgUYmw?XzYtwMw@k>* zHwF`4JAcmj+-P?ugPWE+*7|1;S-%hCFZ?&dA$AA-ku^3cr_)%r8ihl6bNiFLYcNS@ zVe}&;+-@{SaX6LH#SteR%{j6k4Jw`UZM%~-{^%E+F3Cf?U>`-C-KmQOKfpS(=XxZ9 zGW(LEGFDuUvf=t!$th5Pg)+GPhUAPZcA$shkfOiD!H#oh3w{Wt1hKm^tqlh#VL;8=n<4^A)q4DjD73U?p@CgP&81Ol5Ax4VmTE=t0-Rf2+$Cc5BpT3|#gJHb)t>h%lb$34;$#{-$_jJ2>dU*#c}DnLu#f zp~zmmoV7oKvHM2?G(iWqiLsNqyQbJ?)XOeyskp%@oe?8!fS%Mg@EVp0i=(a1uRD|b zg}l1Kw}&N}t!;)J4n@*CoqKgyuTxK$YX&kd_hX<;RT0b=kTE`mw;(w16ka(}j-YuN z`;^{uE&U?7fT>*429|e23TCqtM!ojgEK)|!d;D?6A)9w^3t7=&-&b$H&By@-($## z<@(ZP@tc5h{_gt154VL^BHX~nfSR!Rx9h715G^~>FG$`rm@7o+tFaXgS6%v(Eq7l3 zIrQK`?o(*n83&)0|4yY8wfO!;#+jdza`u84JqtV>M{nva+={q~NwxCOP5}$$Bw!Or z4!f-Dw>}YLDA<|uK==|j6|ytz{sgt@;p=XUh{>*}w%49)Cib6|Y?}-G;Qw;%64#GnbqDi6N4m8ZO z>uTucOwTb8q8ZP3*HymQt4L|1Yq0O)J6}tVyiQsL?Qki*YbjwJ=bX9Htz;T$Ihfs-qLNlfIL-L`8Q3=%y&%lCN_aa#`I`e&Yi%_w> z>ZB_?2r`$bNzyK6`@<-N#Z5SN&|k+ps$O}Qr`XNRD$>%`UyNuTxEUEdnisoc!1sWe>*dO z(-3Rr)-7ZgihpkoVC&-|yEd$(=Da^My*xV*Cnq~wUU%`y&wup7k4|RmmXmv#qjxhj zfqG*S&@uN%WOKO3wAxj}o^_%ZIrP(M>o{CodM;EZkD?hi_z|~SrnQi!b6`V;BHTuT3?B-^Qz;FLZa+qRuz4OM zYD@_>UamsD>U?c$m2jT7lFZC3^`nGb0tF`}->F4A34$X{@+xo7-BlZ^IS@yRYW@TG&CITvl-tE3OyoK17} z1hvU5PD|eoe4;>$QSz2x{wr!+Xe6jl6wXbzTcg=}RYlTQ5|ki*M!#?lM~BNM+gzWu zAeq(gR|Vo*#z#4C#bkaMq^={OiCc|agK1|wLaWg`O?pwx z?<}rQ9`(ZLP%d}=n7ah=%wtUjRfJFm2UnTlQo1V_=t@h7TfCiy*x}kln}HJUK6@W$ z+67WFZf`cf5_^<9Xroulbaiaux%FR_A8!@54l_4N`U7@8xQ=1@gmr8DEx*iRWQAi% z5XX!Fm}u-2+o#n0Yv%y^fZ1P%$~E$$V^M0$#)sg;@K>xVj=f$K#zYs^Dw;)t{%CsK z^xntZ$R}At@bD>9IFG8c9g_t9nwU5Uf0AX->kMi6b2+d1!yk>+9X9%tn0&*A|K;Zg^S#d=_Mb0Cf6<-Dwiqjrc64KNFX2)oB|YmE8+!x2 z7_jfN_mmK{XsAL}OO9Cn7cTXYR`N^uBED*#Jt2JQKwz-MXHkE?`sV7=MiBoJN)$ww z?ATY$`K!1`V&Zi5z?k9NIFVA*q`xkuYrIr;OmtZk;fQl%EU{ z`OtTMN_i62;_x0n9BF*Xc9sl9x+1ss%^@X}qSy}C)C}$@V7s)Q%}iox4EY0ek;}#D zzAG9Rn*)#^yLqhWKqpIO+>Z9+sMfrLSxw0rHR%NH05LEyMuQ@YU1BKUsWQl2d@5a@0a>&&#fS$;;Y)WLT(^#?`gAWr zmO{_s(09Y!YOhIc5{Q^M2jOxna9ou>XTHV6^%iiaBrSy~#-BTDuel^~k+^ZQo(#r{ z&b{nTBR=xrUvp$z$zX=6n^Czr^iHXAH1012o0od& zlGRjXo3eO4iTpw^_se>Tw>`y!XJGE{vG5D)h0(T$e#(wx5%<$UUHZb$zcg+g!{D1L zhrpk09bI5xn&zh*b+x%rqgI@I*7G(3@2im_Om-lOSn@_VX%e?yvh!#Y1s+M``D3af zZ#niC<0z*2nmv{8$~o_Sc~ZbeEu6?Pp$HR~BiL`Ediwk<0ZPBupXN!bEkR#}>5&xagy`#5 znR}l05%>HHoVR24(UnZ6Hh*SAaWv9mDdoCd8UJDKk$;`|Y{4(vz={}}n>_SZyQ_|p z7|{Az2Enhv*RT;!tLvP0yJ(6Sl5o>YIhkLaMZ!S>lw~)>V=GyC||DV2b89 z0b1bN59oOvkZN7T45n`NmT{R*(uL!4Mch)3FLLjN3f%7N4)a*js#~eH5jXIT)DZc9 zvqq|H>4YjBp%GNZ+tKCFRTYLF*3 z&H52+$F7_tW-55t=>6Z~RMb>=4wGQSWxy00o%SN~uss&97b^0IGsN1S7BhklWh_Tu-4POG zD3V+uq!Sa}7LrsPk+V#WMoZx^6Gs!9a!;{-mZQ{~45QaPL=g>;gM{)DYJ-3-dp8LG z9ZiiM+Hh?x;&O5qqT|YTZZ52j17NYDtN?bl))RZ0%!;tQxP_*mHc*;jv(k~pU0!$~ zf#UloEL<>&*&lQU=5v#=_?1%!_Quy%hpqipNL3w4i4%GUnp@ndOC}llhR@owvj9*} zwO8xtHg#zqirib>3?DUN5=DmF`PGE8{%Km<52|>74|1e@@4x7Z@(b-WaM3p4rU^;ULR5q7O9&bLVj-`&TAMzKQDj{LAv_w>dgbaVb zw2F{gMrok2H;9dmtyqF1JRLz{#c}~VP}6-N=7l_M?*o5Xy}6*)1_{&@Qok4}5TV89 zM@3EqIK40BM>}+t`RgxHF#g}-apkPN&6}=mva;?)=zlT)6z|$vJeMO2ol31)jEZTZ zw`y2oMUd)vwk{5%3jm>-wWU(oOqkF{iDl^o8E(H*hCvwO^2v~bn$0T#e+gp=j1{xI z7}clF=RiWLQUTE^h2K!H z=cE(u4phC@13|Eq7P7-<54;EStIg+k=nJyb@6$39kh-e494gLcZysIQAy8mJa_+-4 zOd)e9`dJmBr&LX4vmga(X(zoHTk#?59ZYxxZ@bN(?P@4E(%&hB_D*KBF(}jSG+{$c zP!G`V*%1PzJW9C)0B9)91v8@=k<4C_VDekn0~nF$?`Qv_x+qK}G<;MRnoLM>`{nE2 znvB*|I&dT68X+UwV}3&Q@NZ(ae;le>u?rq3qocmL=Bivc=5**-jyatXZ`Vv!6F@$0 zXS1C|6%fiOJbwcs5)($O#9X5YVY)GH3}Sug*5KEH!R!9aGKKZNQzNAi~eUc{&V?c z4aH>azk-R8HK{C{AT5}W#jOXK1P1F$(~CS-sZ_0yp{vlCJegRgu=kRrec(a4FU%-N zR4O});PUP6#P}6fx@^*qnt6f4j?Lmc?sfnpE$dLQ(CWTbTP-_ZzCv z#Rh+5ru0sQ7?6Sz ze(;N~BHe^^DfEeqJu|Wr%NF*3RYOTVc<<{(>vroxS2|u))SjT52;6S^9?_Mk1b)zv zq$UOZ=e%%xKSYRGt<3UFQP!AcO@8GQC-Gh%!@`BjRV9LTc!2#Zl3f{lJv`K=@>c#_ zjTPhF>KxBK2sG~E%_BpaCO4I)VfR9SV;iFG!B|k6snqtdKv^N>3PGC_rSgWk|HAPt zu`t&-Y64M{>>i!lVl+?_DF&8cI~27Z(}cUKX+KWTo5j!@=~+61T%jXdEcTsQw%P1H z%#gJH?)GTKo4p<2fF7nMYABQzuWb9%aA_}Y8~2GYZMe*Q&J|{EnI~BRx#T!`mBnz6 z?SE@aU|%PG)>NqTysFEv1h~~N#B)pMois+W;LXs4uj2&I-;{yrw-wPC;JV#7vlRDX ztXhV5aPgxOt|ibfIJtl2S)UivSL$%;lnUjhMAZpU?5ylrA{ zVu%{lg>Z$LKdjci7LiRXtu!4Eh`sB&gz?HP?t zE-oj0*-DC0ZI(NRrVKYx>9Ifa-?4mEwGVJE9|12;@vma6f2oV{3S|t;jkXoy_&jVe5;DcS{2kE zIV0%evDf5dx{)tW6Q=5t-`-kiM;Xp|h}dH{9aHV%_ecc#wSq?zKc{@CNq4uXm8eAJ zRj62wh1Zy6ye^}pQh4OPle^349IGUflfVQF88Vf_gUgK2NXwj^+GbI9lqJTvBL$EB#!YquNP-u14RkbRV09CG*`d*0vay^=Pb`AOh|c1Og<&wwt=v+n-$>lgeK zCx?*SP9>qyI!YwT>~*D-t{p*SBS-a7ox)JU+*)cnSF*!g@h*g7p=)*3$(1`V%{Qmo z`bKkL2UuK)kQ%hto*K$|xPKxp7#G@NML;F-66)^1;N~qCkWFq03d=+E_m(O+9;lCV zj^1R_aLacO7)DxiReK>Hrw3Hg3vMkU; zR<(7&!Vi}b9sUyPab@2`89P*2D}l+QG=3sH9Aq=1uf{dUKD4x z{zyt}K1v;R-b}B0TJbmtXs?o>Oo>k-XZzGO->D48=bA zHAPU2`?^DA+R4&I=I^g3Ec?`oEVJ5mFlvr(b`NX?bug=)m1@T227{BE123i#{JX5s zdDKIQgtzn8Q*RirMkFeME#K^KYj_&^kce4zy}`WeDUqhRg_I;fk?`C@Hu^OEYVzqP zR^;x>7Wu|L&iEa2`e@I#_?6M9N(9$9OO)gHKj$OX6CLOF+N=02T@OIhsRfb)e%EBM;+$jjJA{^(fI-cc(qQ)b< zIi0NZd>G~STc4SVCZSy7X%E1g^1VcQ+h5!*N|~c>i+GI?0r(=90XJU#>Lwq^*O_Jy zvdL`cSDv)HL+LguquGHeDjSArBLk(A-7NKX+_wkTpLj8Qpg?}Mnytn4OEF&1oWH{R zP9-oS+^fADV{6>*MXwhX$w1r%#wm;7g6qfO#Gm^hxU3yJOlI?|cg5nB){Q>289=`{ zR2zdsj83M9HN3s$!_$t5XNB~C?JSsA5G8Z3)r7krKBRGPQjYC&k_p8S878vAq=KlS zxaTSE<7{Dym)3kFmZ_2fcsU;Q52+t0Dm;hrwj2e z88^{oqP!&tl9na)oCOg(F%argYenP(`xzpOMoOoj54!6s#VAUJWen~LcO80wBk_qm zcr{wA<1#njLFER>hb~D?P;zejM)J^)$n!$(vr%v|;iU9z5|Zo23d7o^q35$`p^Uf+ zW`H3?DMF=O60_&HEh;l)$I>;@?Ca43;Kbu3x3Fvz6VnZKK(rZ&E|)J`T4r4|u%8@K zmAV6kXHubQBs3Lr5-PZPVx}+@O%+`(DTTpjhW#aSuQbJx7REhhG%^Hz z(Y}VqAH(6TsST57B@+IjX&)X9HZTH=jJ-1OSNxXG-%aqUW^L8eVeTT?wYt!+EMJVr zj3uWJsO9Y5jADp7rTvw~4rTU=XYmO0Pv@Q%K7T@0L@(@8BB`do33HyaK#P%O+Gl4j zJi~C-TVx|;We$6gU=5!YDX3CgFzDMzR(bF5R6z*4qnX0`IgK&LHdJY2$uuXQ*Vb5x z#=^+7Rn9vtpKSYhZ;vVMPXLM>q2fiST5M2=_JG3}nTXG>&{lTEa6|hw{(gHIY-vU3 zkmubC$_{$52~n{0m8q;h;(~6kKaW(G$YeXw<+$fo&gyus0M9l}MQJAV5K zT&IgLS-&$gLk(WD=V@x~Bxk@qcf?z@CB?|L9oORcea7F-ox~l^SojUt?rMBRn$`h1 z$x_7Y_QucRN_WUb0kYkQnPK-I0b_HNEQnui-f1vnhja;H+caHXV~8-$tQ+!Rpvp|P z$aAq_{7>@V3i%@zfzgFxKFAic`PFI(-G&!JZ=M~bHu)U>h0EqHw{=6{-mqlVHqb#-Qe_Y!qK`vD_Q zj%r+co^kQ4>kV`^<7olwvY&=JHu$e8n(`dBJDp;WM9T;98;@$`sfRh;0KTqjCPt^f zpdFIhNczz9p0z=@C8_dmbxKL5)--lguvOwee%p2$!2D?+Ayba*J)#2h)M$>##xSkn z6`Qr_%ZL0_B{fBq@Q+JZ10c*u`b`#&_Ytud#egED*n$_8tOJVi5;<-aVqqo^h>H9Y z(&`2?lV{e@fa(z|swq_K1Y>0WL&{K*$KmljWt#oN~)e zwK};xM>ze2-m2bx@x2Y(KmnmY8oGkh$DWg!axLn2-+%pcduzmxymfSyr7zBnkdJ7d9T>1**RkfgACcLL`csO(b5kTgr^~b~EB&V@iNOb(ltJ^#!Riud zy~%FK()b)QuZ=w$j9_HX0&1!jRwNjd)cxJqNwa}}r?QZq+}cA9aV zny5|}6F4YJiqA(xRbNUoDoIMTR2#OEa-W=IR9$#fPa#k6Q^d#20E+aWD9$7}AOpk7 zqn8OdDssqO=Om)BiXA|5PAyVJ%SW(7oI(LlNYEP4d*wozQ3B{FCOd{yefCJ`U@UbQ zCB*XqniJS_bM2vx3?`^q<;oTd5()_$i;)GIxK~PNB@!ShO016-TwGkn3ntOl2|w0fzbI;=+v2wWi<347KIlyld5vb{c%Z@&icz#M*-6Bp*Q#A+I) zm}dJ>q!)@*sXe}hEu$*|POTqaLNl$zVk?H{m+;{o3p*T7KdC2dix6|mmteA?e0xmU z!!!oJei46{nWvo|9PBH!UULqVmsD+uUus>1TS0EUA?a}1;v}?*(XP2p)N=pd!9oe6|nZB zKuIsH6WOVE{!8J6p3FIcN*|NKC$-h)}phEUrT@vtzWw? zQlhTqIwH!rt4>>>&l7;KdU-XM@3tOyQEQ?Uf@kHg%zfK~RIOOG_p)Qj%E^cM4>-gMTyot7r`>{J}Ej~qQ~(nbQbh7b99cg`f5AGBrwMMFQWU# zPFjDzqf8!D0Mm6zT&c@@@`Mj@PL17jrwCcDo(BZPnbhN5IotjCTXlsu1?hRF?{hm5 zKlzNv+;OwoT@5T-)$6s@epf|cJc$#e3yFRElj)BOsQ9-CZkXQ-o{^nzRwqyueQbLC zoJKk*9#sT}QB;}8PiYXQg!h|^ICoX>DmnJhc!DqmP}mq2VbM#{=cQJHh#1OymUjvV z#4NL{p@Ao)#DtVv5YsztkaapB2o{@K^H3%Ym=^Ihq?Kacoq(mrl*bPi$!T_AOwhu^ z9K^C1N{66bXUcBC*^3MtU!F6%2~KLN9P$-1=^Uw*sSe~=!z*QG&JYzVnRndrg;j4_lyhN+p2=lHeBV-6m=(YLmbDKi*U3zKqxb9*M4&-#5O$DiTL zYLLYYXi)r8^cSY#trCzZbs<5Lk8WQ{8BxYubT^Wpk74GSgT7laDPvz}r?{QgLO16w zpGpYi7n(j*5-yQq{C2;+D6b6T?XJhSxB;4?PR884@zVs z@Hgr7ZGU7k;aYyK+`dQ1Q}{lkC%9`l5=%O01Tk`$%#U@HwgNj2pPCu`m(rG<(;vG> zFG_uKy#$QBIR*P!Bd|dTp{K0?LTuQlB*-f3CSg?db?99<%MNcvz1OT9OjI7qo@{Yi zGp#U$GjZSTMlrr?c@%^y z8zI_(lfB<)jfIq@bkCI0cGJ_iXCbW>=v$)3eFD@j%K5RE*uFnO zE1>AEgHvrcdv9f$>Rl58Pp&C9#dfwahy^%+x*8Gt4E3VV`{$fISrr-a z#TSuTFx6F=*#odzf%Fc%T~Vi%tcmy9$N_0ww)Yt~E@t%EVT`$vkzNQl2qVl4 z%B)Fa%Y-mF;K-F??F~+*tDfdZpUyQA`2KrNiE(6dr{@0ELfZkupMnKcaY!&$ zNQ!PD_=Ks1w@A7J#c3a6xoIlo?dFEui1XeoK1eZbif_Yjm>m)$QDa@1mZo$%K|1Eb za1R|qq%kqG(NI0B$vHUaviUYx^I z*ruIGk%A@@=``*KQe6vk3|{hGu4dz#gSXxm4`oAWq-#$o|0=A+w^7WIO%lxP=tSl_ z8JgLn+3_L!Cy^7XEqm4R5lMyX?@ai=7N%=TvB~(Q}A4ru42g)p>n&bM-Cx z_d99EDXCAWT8oJJlz%a2cJVcngUC-)d*PKIJY9^_d~qcw_{jD50up2Juh0elm?Kt} z(XSoBXcNl)%9Fx;O7IXN<&|~$1HDhJ$#`tSW4tuQI7h4dUR~+u*DPP|7m%CC!Pl;( z(&@HQalP@(#)Y@IC-uCan(k^?^WiL3K>$Qe&D*GEDlGOM_DB^VT#88Nbt<3b3-e$70y3uppBi3YJK@LWxdJ zVZ#~DOx!gvF$Q(GU8~Qw4GTK9DvBA75(yvuGKKpRzg)QEfr~HpUJOqixNz^N z-k#IlzOnvBzbAH5{0?$)k>=Vp&pnG&m1x4d6~?WPc*Y8Thsdrd^}lV>?L?ZY4GKPA zS!w#=_yU65F&NB|<`|8B@+a!g?e)=@E~@5wwI~!X8dKlgg734w%lBT*k76WrQpvkBw0j>`gCvsPnnweYTff^DqB$=}4iZxR&i zj_fCn#qnBkyj3F29&7(-grlmy$)OqlYr4u)GO)KbJ*$jD?k>DB!PMe)!%|r`o77wR zkrI*mCN4;fUI&wmhCO{jL00Yj3&bzeubEDV0q!qMK;2u zUS)=T=4ypm>AbOsqEWVntTw-&M~{?;f?0nkly{=o$?Q|VXeHDm1Ujzh@uQ1z%#L;4 zg)^bTy8~=pMCp7Ne$q5=5;I*{YHp=yiE?~cq07yQj>cUoG^J$dVGg-g*3VA25qtT2 z2vy$+Y)ZM7? zbAP^TSe;g`d59cu--&hi2mu#UPCi8SzisUGwiF^W%CXfUa{fP)F#$G8o5Qj(0uj7z zO;*W5_`F>4#FQS4;^C~84_xy0jo%D0OA4=w>0xxSM z@?i`5R*pS>v3I>dtLhFZ;$vu@+I9FUZCvor^U(o1&KB)Rja^b~s>8y%ca7wmfjh$T z-Lpqktg#^Be4ws)>diwrZC}4Tiss!@TL1J-=@*S9Dv{zZj2VBHET6A$^vC*wLX|#} zBN#fxOm7oTpCxQftz||=nw!@LOQRckMAsaTFm`UVFb@_hD-1H)yRsDlVaTbZHTM$3mEtbpgg+%>m+(iL38{wo^Hucjo#wBrC9ly@m^SWny*rpR`L)OCS<6B*W0k^1 zJ6rtuGzVo@@avJwGM;y-VqA_gOE%h+X4H2_+*e>n4?KEzNfzMmv@*l=GOPLldaBLE z4OXOAb5%i(O2+j(Yo9bXFn4PNFh^~wndlwJRNWlZ-)xQRSW1G1d`7d;lUY;Knntrc zip!Kx8LAYc`bz0TmynkeXw)4@!NpfZ_m#JK%?UpBbcq&$M*%^ZUF(}UuT?nxH2tc+EI-4xhejt# zl$?Epwm0#yA1>fbG%NK4q39!{^DKR#irup zcHKHsDlk~H?3rMA!6p!I2NOH+1D4HJ3^MqrCvdkdxdX9}ZcHv>MU)4(W=En)A$%fB zOA1d>Wq}34V{y8bj5SkDng60L`~2PghxvZ8cGZZKF`^O|+lIyXeLF{$4qhv9O?V@; z)>GhCajES`JEBCCsRb89b@pVOAKsE~Wp7=J_O@?YEo_YQdFtYZ74=yzol0bHyoKQ% zKkKB^uV7-rw;l-x1%*%cCHavK?|@}<(-i$=Veui&!sZGym)}8D7Zp=*w@ulolDBLk zV$Z(Joi{}_3M8Sd@poFlUp%x){=ooXsse)s3&MBT_kV2@lo>q7kN!_F%_Y0nq^u=* zoOoe<%3ALEtZKhKhuIu_nbzhGRgce|t`z9o;x@ldZGGf^Q_9 z&8Czdugo^gG3CT{kqb$4R5ct1&C{_A%;)+z{JsZ8R>j$rv6aRN2;hqH%ch1>NC+* zBW|9ypC*mtq@*ZgwY9XN@wxM~zX^vTK5B-H5sfo2Ea!w3f9t1@*7^CLE-@y3()-Qx zBYx}MA%`Gm--0Eb>V8nbMB#HIQSdrO&h7NfsM6+ho;>Sll)ciIptKo;L!wh;SQF6O z68D#wuyB1ak`xUjW9~I&YUX;dfjV%9`l6=P>y9erIZo31xN&v4EwaE6yW(oGcEfx$ zxmham^IZ+Ub<%F%CsnfJkIi0rSpM+EY5CBz1Kj1FlmEWn6U}^LoVa`@-nNvEcndnz z(^SGI{oRFle(iX}?|1KC`!$AHER~)+w&X+m@bxYWk+?N{xCtFfmg6e~1e>i8O{t8D zond{$e#EOtziv9UM5bm#3A>|*7$VrP%Dg{yA383k6XnMX>QXcaYeQW}-;hdZ*j2hd zfC(QuwZkH9o7VGM^{vzI1fl zTWhbF_Qtj_vyTz{rsj^AdDBTF%}f2Vt*f+P(@8X{%M{zfUv+k5GG6uvrZ!oBXI&+h z3fV}MJ)Ly_p0FlT#RY>BLa&t4V3=eo=^VYDt|lI*y)A)xibfL?7(oZOlKnI#zBfQK zG%=Z1Z=J{gdnc9EO&zh6BG#qcNcOo`eau_sz3-<)JN7hQuLm6k zWNT-%NL5fyq?ZX2LYB9mB%onlp)yxZe~>k4ugJb;?@2hw7BW5L)-|u#0v)qKFH6XD zd2ZVzRKfg1GqbwghxQi~Dct-_IwJ|UETlc#$nytt5A&aJ3HKLpX^MOXk)j)0O?)z; zCM`I27282^d|CkzO1qV-%!$~yj-CAgKlJbSf6k2!oTDk0x)AyrT|P93w`Vj$AO zo1);wRaC?52akL^MhM+ELWN9IwdguozQwx7}e>b)7f+b?_wNvMPyVW`0WV{%Oeq9pAtk{JadF@n?V)+ zG3&EuSXm>Zsqe-;nf^}4eo9w4^%af<@i)^`^;VQKSm9ah?|?FCNSBqLei~Cw3>5qLf;S7iyw|C7kH<9Z1aPvd5%** zDCBaB#*O%UC(_l9eQX{<@wQ#3BP0Xu7wA`x|9jz}Os*m! zmq+ip6;mjfAGsn;va63g$EGgp=#f{4Pvmax?#TOi4aqCsX{^w!Uw$w2?$jO%$54G= zDg8}b%5Lx^-^Ocfq87P)l$?PnZ783fop4y9b;Um*$GfEAr9xs;o>}=<{o8Mlzttoa9Ow^T8HNVB12rr;6!yKz2 zDv5f8x(8D-%IBkn?iEJ+sPUVEvC}$$h3JZPnN1@$cdGICkDq8;+jJuM@4D1cECAh(R ziM+CFx&2mU=jkF9Z{MLYy;Ux=IOj@Ud3v2_eM}*{;I@}XwXJ5YccvuM%wA0gZ-n}$ zyWR=m%8@m{g|X$eM2neJcv!|I#q-%iRVLeuF}#~Ku_~=%+-SxJC0!rd&v_|x~CSLAy(uxHh|Htbrtwl)r0ABn_bBkj!Pw{h{O^K7c45? zBubt7q2hEDjS6PvQM`9<8OMs0nvx-Oxx#69)Pb%f92aO!&LVp$EzwXjVPU?$xJ_EW zfa>EeSggfLL+hQ`~42J2QD|lo;3?x%Nt)5f7CL_`a|RCU?BOZ~eCuf~3*^ zZHpQHZ8c11#Cy<7+`*$=HTJ!Xlj6>Bc3*Nd^rem&GKdn@<**vW5Nb@_zFh-oQ zljFWY{f_$D)nk6$K(25>qHEmFH*w>A+nCnB_G|@j-b3BX2!%5jmSpvm@B5y#{J2y? z&7hOk_P!Rw_+7XC7tfimX~g(b{nL)ilYV*CjC|*?@iylh?F==W$DZDMY+xqw$N%13 zwD&QW3two6f%-c8T3~i-7{5b`F@xq7yClIJ%r1vw2hJWk<}6YYr;I#I>K4q&g6Y4k z$SFb!aq(CyrqC&(I{&X(3-GKN9Ji>}Yh=!OB^PP*wj?Eu%*_M!5F6<=x_GxqUJAFjpFnNa*$ zP*}yUHa}9$tq_Joz z3|i#&Mrc;b{+6*Wcz?OX=qvtYekmDwdye+d`18dZd-1&==3J-P38}ncn=(v|x%mfi z9a{-Ud>@12be5%_gdrI0?sgiz3i!`=H%i>)r9P1l(nuJG@QF)%vuM`y(l5yL^59l% zqn-hiFi)R1FzdaHORpbcAeT*Ojq=nwS~KyuLXC(b2vc0d#)u>M2}Kegy=|?cyBPlD z^wIfA6i-Lz_GDb?!Q7UBbkX5_@jdOHBT0&ntH&y@p^RP0HmR+(T6u`LbUMHLwn*x1 zi)Wb*-$Nzxw~y{j5)Jf>+)lW}BVf}4>2iDXV6q;M4C3#-5_(kcx#2L1+?LLN3z&;_ z*{p`&b57nHCL=tve|V2i_I_%qs#WFVICOIg%UJo8!5UhR@Jqv(%>BfBV$-JPC*72z zn$Y+}F}CAiFSLjvrv##T4ynP_ETEAp^WCIQ+BUU^oLW&J%pffqN}^EinA*e~r3u#a z>B#&d(d;s)yV7*lL`jC;g0Et>`XXUdAr)aDecUW=BWNU$17)@>pD%bwS+W!Fkq!Ie z6O@%yWbb-_#w_B;=f+*Ox`bwIbqInEl8WvN0*W_>%+ zsH<|@+}`Z{tzCxT(X<{B<(t>Tzgi63>z8vkcJ|QAS#R!t?JK0Vy+yOL?N=ynlKO6(31j=rAztf*eVMZ#Kkb*+7ucOX*T#MYtG z=kd|7uv!S0Phl$}M| z(kiR8M6~4_*Y`GRblXJocyRi?W;O~fB)@S@s=$upAMFV!62|77tp9+>qVt<#-*QHZ zM)Z}{VHQH!o-?3~4e(g_(8&(8~4B$ zXwk3ZJ$zxRNrqjueX;C$oWmqb@MKQ(@-lW+M2=BJtu$XzK)7X+?r>4Nx9N`Z_Op%k z8-rB`bCQT#MNvfh_(A4zp?5!4zBSDTPz4b)1jPxZXuwz}=>VpM| zrF`9dy+~cfl(|MqAllVV$E=s{v^B(Yzx2QiFfINhe|{j?@Mr9)PWI`t+4ievMz>S^!sqdmovdJ_z9Qar zRZG#H&?Ky$P~aTH?YxtqT%aU3@9musIYT`jBDQ`(|N_a^H->D!Kr~j4ap-*+lOZa>GZ_^x(&e*4+!#u`N zKv-vfOrOQ|hx-SiO#<~}4A`lxdKa(-Jqhb5&XI(G-wBMaEe<_KR>lDN@{ zhKTK&ZLf`<39B}7qdXy@Q=Y*P&{_XR3k!Z9BXcn9RK>H1lGJ(9sq{8W!sl|tB(kMa z&5E&}V3_LK}Ggo5Q7r<)?JRk{?@tCNrf(iAp2FmqT9GU6L=Bjf~r?!)`p23*WZ^du_sj!POSlP2b#j1Qc+QdOM zDgO`ZeqU-&P9F3BuSu|j>r&zs<<@R|V2PE)MfPpq{Yv7YwYd5Nmjb;vl#pex+U>Ar zGhCW_fZnlz;ue)S^!MA8iXU2X`2kFi<48zRnH6+=_JY04hi}~5#CYQ4UE=Xbcg$0? zUoeo9^BWO&L*mCyR)+ucTZ+Y9TTLZ=<4qwqH3nzNQAhlx9Z{u)cxH?~bnM=WmYb&0 z7*8S{cS%{>j&Ucli!i}&(_0T1@8^GkqCNRS9&ukiY$EOsb z_IPLDTbJ#1sUKReHRP9NeSH5-vrPFDkB?$RZjDCp%?zjNChv>=%bwEys+NhIbmxqc ziqDjyqU#SawaTPq{=2xrFsU`BzF}9m8AsUsSi&V&`8_)$4X_Bje0!g>qtj#cWw2Gs zn6 zHb+^<R8*v+ED$BB&7;jJhD*3op`%*{r2awF@_I|1$x$Wa$-ci9N1ikBxPxw^ zRHS-3#QZcZGHvb7@#^9?RT~-Er@BV#54e&S=f(0cJ64f&AG7^fRPV>G9gw*M{6qRA z|2o`IH=oFMH^W?5U9@|>0)|ZE(c}F+AD(I?;8AzMr-RKevI)kR_gzV<7z-`6ky>uG z%Q_Bn^VYD(!6IDmE_NWhIr; zY5t+p1P;qt3ed5|2hb>oHQKmbr$G~2v_s2FO}q2`*!Azv>+tCd?Ff02zN=UEP@?o{ zDRAdIUwv!9ox4_LY-()_EyNthHYkg`VoZK7{I{O=EOD>yZa>?dBwXKKwe+c59QW2M z+_$HB!c7Hfdq0Amq%0SA+X6Tznu%Lm-sS12*NkeIvw^L9+4mF`=M@@3cBsX%V8d4V zQ(e!*x4O8!43vzrSUeipQ4vx^8`AqB{4$>%%@ND+;}=rIGv;?xXSjHJE~MR&7~=WR zGVOt`fZEIUY3zsOLMKcwU&rW3W~hy^@I2$E1b0d6$if>Nv>c1p5>rM5zc1dq?hjK6 zsQ(haO=sp;V+I`g;u_(dA8!=4Q>_|QQDJ+>XeqnZj8SfN^!46QGaF{^DA_mLPNKs7n#L8rrF*7&Wm>uavCNWAnHa6f)KTNK#ER~ALTDI9Z zR}f-^xkjs0lCo9NChxMO*v&Jf>lm&mvG%(Kn{Chdu2rOHfix6TWBxE;4h7oR*mPd0=I0?wVhNJbYbXzKzkm~d*BpxJ4>*Mb~S>K?!zU?%dX zVvB`=(x#KVuXi)7n`GTPjtF|tnz0Lxozf2W^J%0rkhpZX!c17l_rNPMxyZWuA@?|U zSr;+8l|zU3s@#l$H?otrL{p-rf~&1Lr5J0jYU6EWg5$CARwlQC+ut8@?M-*=vXDiu z(P^W&=&eU@%tXTsjywK&jM5eDZ7yKyyZ+&QPfyzHe!_dOv&nfoaNxtW+qa+n$BvA` znx+Zn8xULc)!;$$I#IoChAQjG|Wn$VqbR(B(Yd-bUO)bm+Q^pgXa zZ6;AvEqX2UxtO$qnMkz|+HCt+!b)<7#R|oqbW_zYU6?{5H}R}ON;+pG5gvQ}f;nW> zUzs{F@7`#)3-^z@O$mC1>1+9ud2{)z@DVQM(K`kW{C~NEy4;%VoN?*Vv-dmYm>(8J zH{X1)Xj~9WPZxT=a>ac$jXx%E)n_FHM^QZgEl#_k(IcJE3GcYwg|2>$ntrt-9aD1J zs15Dt1HL;~au>J)U%YUg+_JKAyRMi~&;!ecgPBRs=O-^`1*z98h1;X=NJuB7#O(_! zyzB5S#9_w6YgbYeEZgwNl~-;_|4N?A$>tpV+3k}&j6Th`K3#ozsCbQ#kRJKnc|tm1 zAN!ZT`B7Qkz@Louw0_74_u_21+Y^U=l3N%#E8SIhbIIFVfB)5vA$a(o_I9h;-}kNL z@8!;Hve1?Tf`<8xEzPEDXz7oE+9&@Z@_+r^|GA*< z4jLwt!q*(L{xU|mO*5R)pQ7yqonw;OW`dM%g&(QQ;rBU=)%3#a9XGgn*OB*v56^cMnXI-vl6G&)=aPZUuB)?QJe8P@M8eoLa;X2^ zEp*4uP3$R}vO=Rc`uCqo4zxI(Dzei@Rb0d#K@U-^-&&5ntY@@^7X&yfB^4VLY`Kz| zNLviWF9ute#om-Xjo$poPQGdh0mUdH?$6_qvxO+LyyK&vg z3Va!M(ODLUZa$}6?LN)h#RxyDs(AM`TeJUm@zU#@_>YghIvUD9merZIIuiikA+p`GbUPh2Npgu5xAh8t$G0h;zI>`3J`*XZ`1PM~5pc&~|02w5F$b8RA;{Zc+Yd4u*bITs+u-{X@HYnX0gy+4-?5tr@)^|k zuOmp)Ed)6XSjWNsH{gG23qgLgi6F}m-)kV7*np=bP}exMf?W>y;J1M@*qnxVb5MSN z8F+)H_`m{r_Bl0{M~wMiOjr!0+Wt&~^?u1NP&9aUJseF640!!T$;e%YBgnSKx-4f{h61Y7LZC}DZ7RoPx z%TE9U0h=<&S3vh?z>N-ZOhDYvg8r`o^T*(C+zj=Z|JR4=Ymje{y$JSM*!~aT$^_j` zuz3e;_drfzDl+6nz*U2+A9O?DUk<(w!M*}={E8Jp{u^@h1@L|Wbgx1jPl5lFpqqgl zynY(?LH{w3e+lgmLj5G<=M(VtLy%J-z8R?h3^wN>&*#8y1h{U13?`^SZbLl(2{D>M zW&z(vV4P?D42i|1`A3}&z3w3P_u0lQ; zwXp{MaTYi}1Dw7A`!4|IlfZi#a$y4b+aUWl*dfsF1N>$1^DoHB6=*vMIGy0@Hpt?D zQ;YQ-@cV6u=^pU&ztH{{!220sya>FWg!umq7+*pk90B=Z;O+wXA0WQp0iRy*a|(3# zLd*vNXBKo{fIReo&OV5F4E$_De!l{-Gr>m^#<~RjKMhzp(0vAc-UYE<1;5w9{uiJ> z1$lcOblw2WCeZ&A;Ecm|4&u41R-paIkfUMH7lWS{Anw{Z1O<96u)hQCr)n`k``3ZX zJ1{o(fv<1EevQuxv|R?A|A6gY!2bYB59H#HP&*<2Z4l1`p!0i(IRyK)$;Kx#$2tWr+8i zVD}`*t^x0#f&AZqSsODy1+Ir7@6&)|f!I1go&mo=K@SW4@ms)mK!4W*&J%#Q2)ciT`XFF@47whOeG+sog6(m@d>HVSAfJDPzIX)6 zJjj0!vIk-Nb%^OC#I_%{_W-9J;LHWQT23^;`@2rqhwWNkz776f2D}r{&I6t#;Bp@1 ze31Vb`k@Q_J`1^6gPi;k+KvF21wbZ>zk8)Pxa&l@mS ze-Ao1@H-0nPXQ-4ly8CVzd-jK_`U*h)Q(Fx@Vp7QUJHyl$P*R(I6&ts;9CM%QsDF! z@ct9v*&r8MXuk&i`g0i5F2MLbOCHVUP zz~@6?_ZV>bKJYsU_*mff8RT0DKIXs&7yKUromxNt5%Td%(5r(n^h@A52U%^>@fc2)KO> z^gaP!Pk~-7mXi>J8T=+8jvLUn1?4#O(Mz!ZM`){^zy7;s3qD@~?&rYf4Y2)}13?nN z6Ajx~z&{Q?k3)QSfWO+gaRlTtuu}q7Pi@>o`5ugyIlzA%bf1OTSitWN(6Pbz5(1~M zTEGwZy9DyudHZq5OYIu-3*c8f4p$&P6ZpRic)bX|UV?MZ5@0bw_YCa+0M02>fPWXr zSD=r-2R8FiwgCTYfGdUa5n#U#xrY~@kjEe&wYqjb`(NO!1P&i=!#D+7EAXmam(!5P zMZo?Q=-dHZEFhynE^6142O!1~@ZAY`@v{h`hxk6M;R1(WfgKUr{|;PRL6-*gUjcUy zV0;zyKL=hB=uHafJcAipHg*@5j>z)vHz>!80&P)`CMHDK|8%K+rq z1N*f+{~Wd-fH;}Zh6l_)K%agJx&8yl!+`S**#0&67eoD1z*K>Z2ONI_+};GckAVNb zp)Coq8bG#F+XsIigWrCTRRHr>V8epk$YE?e4Y~XS$Z9^jAtx-*{UzAf#@c<$YY z=V1FX;FBQM4}ixmX#Y82Y=Heah`DzEb`|QMgTL3ItqpW)KBCYci=gusV15hy*6x=+ zvjPV2{|#)5p`Hb=kK=w_*KLGWQpd0|*Q(#lO=GN}Z zegWqN709rl|Hlh(P66IAzlKnn7MAbSNcdC-2!3jBb}P2entG5ZQ&`~!SE2eO|+UAwoZiVNCoL z+LEwcyMJ^-A0GgJwfmwMA&0f|`zqw-LE!Xf;M@<#%kMz{F37`w0`J=OWU3Yelm~!M z1awr8H!<|f0^l`(?+%FRZs5ECZC62d3iv9ZZ@Cc5bHIlPwrk*zX8wQA7goSuKj_u& zS6+Y^YS)c_0`^|uJr92Mu>U4-_!sy#KtFyPu;q}~PoaGp%BPU?0f<2a{vL#UJO#0C z0RErB=2y`E3uxPd`V#n8K>a+l{{gnYgxLNH*e3A10=cT)SImO_AE9j;#Cj##ikOR>+JmUa93xM@oz^UC=*8XR$ zhy8y*jIV*-%T^c%kOL;<<{scwyAN1|_S(JJuOOcTYD~X7z+G$f~BHB5+S6Z+$OVD~U=cZ2R< zL9e&gZy>(}IerNG^nqG`0k5A!T+5&r2YCR-%3i=(gFLx_FA8)%fj)d0Y)?b1bSOUs zj{5@G8*;Kj5ZA!blZ2c# zrEA%OUu@=cmu3jdsAOaAYF&3H0g+2~ns~5cC+16Lx^8_g;IX9Th^<4!JC!V3+1A1V zb(1iJaGH^7f$p?qeY$#mxRPyI5M|Z4qPtr1XW7^_x1El#6w4VTlPJJ1^!oR3fvY%F zm>8?BO$4@C4%OZ=#=b1P%wVS)`#o8)dt+5JR*L0v8;Grui&vo?*x(lgLb!#2dDO4% zMYbu&8!qv*ZNuatoL!dD^ILYjyU2B>rm}|=#uHm)beR5WgY9K^b~0RKrM^NXSIG3~ z?B{~~0YW|=ph!AMe1-R56qj&%nz$I-VU#>hE@$(Ni?$Tb#%S9VY&ly6oYpLzPTAlf zfPF zs5?7kss~HDE!e;<1f{zxHcva_>c&&3fzlym!av&h1`wws^C+pf<0f?4p#!noN{Ojc%@Po=fWI$FYea zSy>?AT=Ot094mvx7e{U<*#6Fq^{PZt8X}=+lR}!N+)Q)B`=`F+bR)U7(ipTCc)}7B zyPis>5**dYgDt6gZF6Xy&dZSGL_!j;s%SX)1J(T%K8+<4c&imosGS*J#r9I}^uXhx z!qy!Q__ca%3t5)=1MnQpYwTa8=tTHuDTMvlHpt!tPX}>~xsAnKr^(x+FTS&zg1h8IQ@5 zN)9a*o8Q2NY4*Yxt3fVo)yODyjaejfK;ckQ6kIN5L~D`(jodNiOy#_y>11RV=YknskJ^mo_TyJ23@nvCntH&ebr`%^M~U zJs6@ZXmh-4MTb>a>Q8v0d`pf^kcgsNx(-6FQ=@A1*l|iZvy80LiLQBh@v3!i- z=`nX;gi@3#hTVVWjNM;tpb%jORk8iE^1 z)PhP|iS6cz45ex`kQpL}RCp0q9~WKbdZmHJ9c5iQzmb^osV>Wi6-q)EX_jE~CX}O5 za)p#+qiMhDT2IZd7GSE)Rl@2D3?hkj=p>>HUuTMwB%elE6bCqWrmgVZuTMF$!o~bFq8wtB$ z9$rg)K%Za^k6Y41T>H2|WFdB{;snV-UsL*kAZn$%Ex!aDo!Te z%FYcXImb~IpEw)!WHEJR+0VC9q-8I{Jm}AjW&X zpWK*Ni=?8|RveujO9jm6s-5Q&Ggs3x@~pO+;o^OsMOLm;mr(LbqG*Q|x5X&Q6=q^q z;wu_;3v3px^|oTT!dYoMBy#F`GC~r|3mRxXd{NPT^LnF=ieT*VQhR#QUcg&qyBJNr zSb<;9m2Mewb7f+ZST*8oMGR`Z2_?mpL~%@8gtHP$!dD0m6tjWlB?_wygoNJJZjI*K zLUNiBFR$dOwqyG%RkfunNha!|!62^4rcL+jSYo+k_F-E>?ISI=1fN9-4H#6PGrhr- z`^ia6+Ky?7%ZvgFL6DHX_lf+dPmmyCPdT23hq-54j zBRYy+CG*>yG$oQ)WwPZ#4@@XK_YI2EzO6i3vYVX7jHYdqh9wFrl@# z>M+sm8Fr#yjLt@5Y>c7_gRdh*lCGYG2CSp=+%&u5CMiC0iL!NT7;CkBAf?QdD*-2( zN8?hWf)jC`7i;JC(-ny}X;9LR<2h1>C8Swgjg>ZJwly(K8YQXH=`OKP7cNmcSi!2p zC&egAZ3)D`mr(9av^=TotRtbGR8jm{XIVQ1UnPW5*a}Nnb_^QL3BlsF!h$bP)W_k) zKl_lHowG}m3{Ld(vN&TFht%o)sqGC^d}p#zDP-a!H|eDciW?**!X9UDTiuleN>dzU zJ2aTY=eHuR0!-wiCAn`3^fTh^#zez@PNA0?&Ww$-b`-F#0kytiS!zZTxIM&nUfDCJ zF)OP+v|{7qoo(5%6ej3ovvJLRMKVnKgkBvd-wss=4k`$$<|H~3=H-j*hl!+D`Bu|y z=X@R&Ye}$qP51M2<_`4n40F4#L^dHGnx{y49?5Ug+Me*bIm3mhz7%D2A1pCjsJnc` zq0qG1hw9HyvWO$h1)P4}QZ37t8nAdR$8mGV-$1mZG!?_q{3Z%_zrCR2E3i5=V$w-s z3d35WBr6gpLR8KKDk5!Jy{*u)d6D=qWlP7TndG>Ioe3hgOI)wfa1e$t-i~1?y+|lp z6lVqHa-Cyg*~m^O>08#OQYnl_s#TJc-W1~44ciTYWp<9mCt5T`tTA4S8=P$oW|M2& zT{N^7bVMFeSto%9%{CQ}l=8Fdjqy1eJ=#5v5(lrhD-B#%4=x@MPnW60xb8@Kq)eps z#fb$~s7xh!$JjV;aX=u8iemL_9V4^dn4>Mnu+w3ja@O%_sdFG$-H-8cph@ zG|n_jl;O(64aQxJY@o|%#CN5I92Op#>3k2U8uU zVfo<{29AyfExukuE74FSWiBatoZ8HA1XDOivq-D33GuljxFSj@NhvB0iLE0Lg>PpF z5w~}k=FXIS>BgOr#f%>_8&np3PAr8YVZ!7qxq!PaV@T0aSuVwU9b(6N+MJPR%s#z9rIm&n@f)pkrXrDw<}zI* zZmv-w6ysUlVZ045&8V!z5pty@QpG2n5|xF5PVd1j%VCb`mU51#`@a;u*O%*PcI62W zAP7SPdhf{~gW=r`bK|D1%*x7C$yJx6o}Sff9!B#g%{=v*HPbUoz0?}1tV+tt%Dj0^ z-049*TKttQV2`VkzB4U-u^1iUK)ZHq1gX zV#^`^dPB}H3L@ICY ztacN%ka#b8{Gt_LUv9Q>Ha2r6XljfwWbin=N&;W;28T{GPJL&`3P(EE+tk_5=K7J~ zOblLbbxl^TikJe&vSDOOskjHQn7=k#Gdo=ST8M(Vd91FVWZ2LYwDu%^nY<`l&X|?6 zJN65MJhdzPWAtVrhkoYBxx^~spRzFe1s=)EWjjS$h);`?xwoG@&-d=O=IxHCC`$^PvJbT zGm^p4@yXq6udE79r&c>VFiY>jk%|_c;?0U{!U|kkqR5$I(g8nnta5H z2k^xVm8{@(^1t4J;<%0pj#*Jx-O(FA0;5eOXOsi#C*M}vpvz{lHmc&Yr{#JPt+oDV z)4~9wH1R-xl8FH0&*126_K`3h94K+qK$h?H{G!~|$7aHCefS@nxqtX?qw84|nNLd( z75&;LS?@Ew0O}*>fWAEB(t)i1+oyHNs*J+xeFeXWwG79s%k3 z@O{@e2+R%s@es$0g`t{nt=k7rj`E9SznmklzuxR7?U_IMtkY0afAfHDxx_GHb<3Y}p~_m_<6EUpK7YEXg*Tz@-bOgG+-f{{+;>uRTDDYDZ$);0?8 zHao(9JxMn`gG-ly2+nRNX`C)??&^73`j(f1!52H9a!FddG=7+@x(>mgXxuk{Y(edP zM0|FRzKNtX@&a)^p?LDSI397%*K=52Cs)GYpL%?6P^4d7gr6W7a4{IX%y6uZv1lwV zyWiME>c*z$GruXm6;0Wvs%-&Q#_n9lKn&M)dhJ@Q2d@zmxf^Yt3%SC&Y7nPw~i?Wa}9(Q zw$Lv#fL0OHlexusN(Fkqm?C%`%w)DTRN=zkm!i^9g!p*bSoseJ@f*X%9L%;1qdG3lYYk-s4%r31B7Iref*Gm)2o)XKR;l35KVdA1WBOGGiUTS<(8J;VkG!O z!L;EF1xC4X&FV&XY~xTFs4c$e7J^H?V&W|%=L{#2Nwoa85Vh93a{@bW@(a|OrS;Qy zf&ns!JWn|t0sb?uk#L-Ymxb{s?G8L?O_qoIV+X)39^G0Wqo+pY%D#I=47bSy_y8TU%xhTg)ZXM zNKI_gT#{Q|pKMwW1DR7^TIkxn=d=2+>PuC2R?a%RM-4kz|D@`8O86hOt0#s0e?L$` zX~9;$B9K}X51RVXIncjU?c7SjDONGEx%Q~a)46fo`-d`I-&?TP*6uvs?$9I0RCp~a z#J7?Wov-HZjvno>-j`f3s1Wu1oMabNlloZOLVfmd{x??>Xv?W(Qn<}!8{sDdYrTJLpqb=*KXLmwkZduV{d#UY{@fcPpPj2Q_iA?JCgiV>Wi{oY$y*=?it%c=o);X~$Pcd8K~SAFXsb1^UFwe@0>Jm$mug z!4TMj7$WI5Ug}G`Yx0IG|5xoPH_X^}G@T!Uz%1 zGDs}LW0GjI^*V{^vb`L?>h^xP2m%XV)SRh|*Oe%uq7 zZG;5&Gi`}6^%8i^#8wBf``Fcxy#TwLKMeMML20KA6R2#deAx3tOfrb=fy zPfIo-z6$>0juR`oEz!H@I6zAlr2-^hzQQeK8)E2rPM;-gMVV|JS<{P4sp2zp@-$obq}rH#T< zS|Gj--Ci?{d)?3s46SXv`#4THCVFWUovfDr#-OtxYc(AmTs|+X#i%k{$&GGRr#0Sz z+S*2~w^#Fu^YsLc4s28h>}lYsPb?qn(q3Vwd48@}4#m>d=(7CyBKul+lFxT94b1^3 z2-SZBTz+Z}^%futUIt zJ5)#yPW|ZM3JyfpFbG+qryk?V&KS~U%Q3^)+W(ljclZ2Ho=sLmqi?*LrI7U6vYTyN zhRKZ%`TKfG)|@#1s7Dx3+tX>k{jQG@{f%@WY3-IQP(=A4JL+tIV%DJzk6vMBL1(HNHH_iQ-=90@=epIy z=9MyE=>*IU_4RJLqkR9eZ(u6HO8Qous@tXf2hqr`h_ma6cXIpPIW(7|^4<^DvryAq zoce|9yYfGcfLDg0!~Gj!^j?z`-QW3nP_N37(92nLasHKe`$PR(cs$OBMhtT@NET19 zZa6h9Qx)!V%WAaz(5jEma3Uvz8cL7*yW7c&Si5COFU4ox4QZMSeBTZWi(4+(Bo82@*vW~h?;SyyxI`e#CPC{zd1TR+Xz4-jW%aCj-y8}W2>p6{rQ0}Rk= zIH>>gqXkiY?kQUa5s*v;!*uPROJ`oRv2Os|Hu&R(?x-9Zgb(Qcc^w8XkfESU>lD+j z_1)NDPY10`cs|ltR3cbud!>Qq_$}p2ZUkr(aava-z_IG6_45>8IEn=Tu%&c`bbH&f z9gUC7CxV)`{t)jrb>f;s9!z}7N3loeJ$ImVJ4G| zl(tJL4Z_a@%fwdInETv%JZQA@TfZ*7OwRl*lkerS{~9<$ZTQG|+c0G}BLC8S75JnF zvk9~~GPl7YYq##YSfp?KOyDU63uPg62iWi6)-#hmP!OJ7qio+77$VYWS!$bpIco_0UfFt=Rbf?Xz{a=Jw`I?+Wb83QT2L-hc-k zAyR3sFED43qCiO4RyyPS@&JVbVw1~_<$_@$!+jX*Gt2T@9izJ5*hWp z?NZ-WsjLTM&aV{+_wS9%3M#>aPm^yKEo!&;^ug&!qNb(B9H$(EDI6SaLEG)C=)Qvu z>t{BAo&7tvwrbz<>6ALXPV@@fG)TI8P>Za_q?glSG#s733BT*Kr$4WGn9g9^j!bXy z%rdbnfcDYRe6ZfQa=w|G0%!kaz^4NLex?@JlTZCR@Z7ePpLQhK40m0JKloc-b3Aq7 zpl4AY48fZL$UI-TT4;pAy9=_%Y|b9jCK0JhZQ~~`$8_43A2Wq|SS2ks{H~fVB-BM86R$vM=@`e6=VJ;%RSywA+LkMAQDS21L5TIRiG>=fY(xO(7s72m0i})aDa(;SKSks2N5Rm& zF-IQ1j6MI^H@6az3Q&a-GofvL2-%{%l4wLjr;2XiH!0blZK-y`UvN2T@o}>hpJ?d% zzL^Hq_qnj}-mHhXT%YQCMp0vo(Y=W_NAw2$nr|~60z@%^jYXRS{E$<#>b2#vP;*Cz zc4T9VkCP+(!y+}x$=^GpmmACFR>3xUPQ`mZm@rS+3BAA;@p9WT@~!=d76c*&*9aI=l=ZeO+6r*zHLrV92uT#PHeNkEV_S8 zS1mTz!nN1(m-_golxn4b zE8sRu!}8D*_?#W^e?BAY56tJ=yhjTwdJ^I1%Q&Wt(bk!iz-FAE)* zuQYu-ZZK^c+cP-xBg03;I3FkFM$@sFRF!$tXN zPqhe#)k8*w8C9=3jr%Lf@!x1!2Axn4u6%0R*LecXiS(q^17fgleiY+p=wHtQ>{@{#FD_hmH;o|5 zgvh&0@|GE!Z<;K6(9ZLrP&I_xUXskwu_LHckCu3(I7I9`Nnqbb~$oiA{+x@Fy7 z>De5WJAWTKf4>Yjz3BQl=m!>y_~oMv+%22>NyK^Xlu-Qi`} z+AV{CtoW<0lScndbI69a+sfM_(6Nq`+xLavp5j*LqOOKBlD&satX+M@m8OS(5xW<^ zjeP!g?AouugZE1U5=I zig~Zetyue#zx6KIX}}hx_UHz7-|O12J~4a0ta{E`lauIgSq(?NX{#5`S=A^X#kGD3 zNe(X!!=*Z?30f#IS{$&^>}F!A|MoaCxT;XaTjiJ{e$=A_iDdN-dfu&#dHIywX!M&6 z{ZdWF;~{1BcU%xD<#u|>|I0`$7zl@ZL`iyO9BYM)0AYwKT2f*v^iEYupRZ^Wwi)Oq*8-jp6zJGgtGWbZVzFN z?FHLl(x9q^?r6V?sa9={+A)fV_08gPkkQ#grJIw9l%>>08@dE(EFx;Oi*BM|Fj}Uu zoH(?Yif+C^KNM+Yl88Ofj@kFV@|boc!Js!6C|$nhdU(yOvn_7Yrs?LZnaP*JJ0asE zt*|9is}!nS>hu%1YW!@;9_ojkJ5S}_)BwJ(%m_a>o|J?>dZRn|bS>Q7FO0;D@chP4 zHuC)&9K0=37J;L}8|PLQayijt5l#jEcJUb*uqyzJ^XQn3=oAk6WiV0=S@wUfC zglqVA_?Dw+8d;W?CeP&brdcAvmDO58}pyc)<0B(A;e`I#r3>cXp)}E zHHgHrvjlC3%`@79%cC0w5_F^>>eaRf(hDZT59`s7fileclkoHG^l0N z@@fuuC6Y-ErH%$uZsWFl12zDe;XXG?h8ttp>@5@C19oVu3xg28H6PgAWt-LAmuLv< z`>jzmO?&;VFdif-5NN+kbC-8!#Sf&*jd6XDdgNZG+vTPR19#pf4Y|g3L9NEO)CRmd z8hP4bv1Tnj8D%xxpW3Zj8gK+!HV!Y;J~!{uHlz92s6=$>g^{WoBJ-_6h**^JG>m;< z(qllMG?MkARXJ-Q0N!rNs7`e+_Md97qq%X+9Sx`q;=3g*Eg@s^H9f0QXr^|2T|&B93k)bQaMAxoi}>NvQWC$<0DGT4HB_P6AuMg@43iAj zo$VcLo6%GC{fT6_F$I-fEt`N-HKnPDBQ+lq`0P4ru+vZ4gh4j+>e(aV3_gI8e`K`~ z)eh{G=VZDsxWTbr0AG3<+K!Yl*bO5m?hx64B4uobM>_uT5IanDu3c95}KoV1Gy=fxe;O36*S?5Daqziy?lt3M?$ zmTCsDu^wL8W)TeEX=D}g{c!_bGqVzFPKDaY5}MsN6iP#I7I6-5-vD=%D32i4#C} z5%`P9f+f|*xE3l^rO^PtJ9?in3?bP`v9_tfqJp8qjBbr`w$r(%>z&Q=7|P7wM;56b zyf*fH~@JUD7k?p?ErABdQ4kitgnfT~P z0!{+H)m!!O8)`%s3AZesOURmrK-2e|hAt0B0*XW9-%ZS^MPXz$JgaYwSL7Xvr<-(X zl0;ptA?7jE)}6!0x+h}FdNAiT{UoDvB>Y?%twdCJEP*rVz?>f%WOcZqtA-1vo;`C9 z43^Ibr7BCkXLYhZ%!S*-8!-6v(%XfuB&o%rPQU%3LtiopUCy3`Cw|ZrQ*)hpL9Hiz zaTS*9oTv}ED=K_4A3i&-D2fiu?BRIbMiFpodObPULRmdG`^kLJ*UZK(jy%9D%sY2D z%Py6qTf0%RJ4^3x+{;!H^y+G;eMRS=4t*wW#(22Ly=-5ybW0YY>F=${HbTC=wL|8* z&ZK+Tu3f7E@TzDG-dQ~j?;x#ST1Pw5k2@HdvXE_EJg~C)u782rj!f$F^4*|^77lO> zAYE)sQFM20^2zG1hM%52*S(ujuW?Rn-LGTJk`L5X0jdBkh->ns@5i|D0PB;vwGweP zp3Cok6t?Q+nE_Rq3opn&VW2&>E9honHc}%-6yWa_rJ;kX6`Hc)VMGcef3X-rFPgY<0He3gam+)yIxltRwu> z*~mpqMEc;#?I6#@ceYd6EES9tS%$VOUIH%Ddgiei@+~HIHL* zk13sV$RxR9O|5k$!hMSlI&}IpeL6W&a=w&?97aq}G~8Z5cNR1GWj#&?psFu-COg`P zb0>md*I;&-Le2-ns*ktzbxDaGws(Wy#wRVigErRUZKY!8<#AAfc8 z=bhQiNl=$ivI0fK5DkB^<-~k0c=twc!Q_J1@(LJ;zfy{|Cn4kPtyUhsD7gr$CY?Ju z&Aqv2XjICUrN|F^gk#P1(+5{IJg@Co;KdZU`!MvOx*11$H@+C(ENcT8ee4tFl)Got zP9#x&cXs%-g@glY`ZnV#9Dj^9-BElF7nH?)0@4@K2R z?jOBn04p$B!`Ce+1js+Km@u)H7~& zMlcTl5x0<9UjlZ)JH&mrI^8u+j6sCr5}a@MP<(w@(=8dpbXQr~r{_Jx2BcNg$tHN3 zKK{?oWa7oJCI0pxGBHH`?HRv^@bKjCwjEI`$YGHKA`luvU-~gL8*Qi4<~3C3I;{cT zf*gD^S%4pv%LhWU(+d7+Y$AM#e5-7Ezrh?`(^+Gmxfy@Ug}AyQx13%NcVD1c$_$y& zT38HP;BYs2hklBQ?EGO#a?KE$wVFzi*yG%CT09K8N&SXmeW>YQ9(Hc1(Z{CI_xbI@ zbZdZ+SO}k`9SejrebP>m)~ZfLf=CDl;%a?s|99IUe$m&>^|kT-A6sHsg0aTFIy}UC z5Q>jiVtS{^(u5+rFE9#kFP|Sn&yR4x@~Msbr&H#_(T~OL-EZc6E8N2Ct0A=Hth@%z zzlI0?a^7b2ai0l`M4J0>mAu+~;R<0s+f1szTPk~ctQGr{hay4!nmrdEuSm-=o3nQ0 zuy`ihWBZzI-wM$!z7aehUEimrR9EQbGg8GxUBA;jK z&pl^&oGy=s_E{Z)Ed1xI0a872^@q!qWEXjK86(C2^%m@XrA#U1{8!XBi&|bd*s-UL zrVgWx6hB~}8$Y>d5KcYpB!7OYpo2mzt2GO!59-J6y2m2^;eG0No`aUUZ}aQJP5^kxJcy*7elzx(A&(f;A4-0$ zc8Z6ek;rnB(3z-LH7B-E?uU?hC|Wnz;lHvNr)J4B@SHU2;r3oKg4gX|*+*yX9 z7&@!6off-Xd22Q5=fkvP{>ZX5R{(8S$DIfLP-t9v8%a6`XIU&pGGUw_o*4>G|mk&z_GUdTz*6UVcFmmN>UF0?>(0a3@rVS?i z{dw6+8mupH;DFSQ8ypaHHI^|OWRp4;bf)dALe<+}OxH#eGc=}N;i}Q6JW6?IZJX<< z=}^ZPgvCz&!XAZ`@qCf0IIMbobFm&X*B6-ci492O5}(T(pXUr2J9NLL?6)?$B;xVL zLoZ9pe!EZ!cN$|-p8K6I&i9Pn3Ko1CVi)NvBC!-6D5;j0j&+@U_fD07#H!)?-CUjC zKq4Du^qztdu5L}AYv!6u#<8$%_1YcQ0(zt>>~Q8Wog|v4CxU*o<1BUZg1M=MYRPx6 zYV7D`P;64j7-;s3rks%z>!)gFMn3uT;U#^407#TZuX-|cC+WDs%QVj!yYe_+H9Z^R zD{f;-_H*dlswW8&Q=tZ%$>rlAHY;JK<^^%WBknHL{ zt8BcONJ5|%6rNWFUqL>}y+p5`+JwkO)}cl|D=6XXJ|9GVi&v`}ka=_1&H(1AcCuJa zUDq}gCz#p|nMOLyD;G=Z<`&M8y(P`<7a4H88Z-4nS$%Li7x}tJA+aqTD0z2dP2Pss zAe%PcsQDtto5m6|T@}pLzP51a9jDu_U24G{^bHHTb;v6kCmQ>!0c7tCqL3DPdBE&z zQ-p66QMyxNh%+j*j5!pfu5bGwdM3etRCE8tKkKJpe1~I)T+dHgxIPnC% zfCE`xUOXSQ@o?^imDaHK@x(wsqqZepHpro95HBrwOP*;_#QCVj(pt%Ti(LJhP7nxa zv}&@+lb-e5K7>FYztQnakOijjcpQiq3*dGc9V)aNSH`x^qhAj&+iN4UdjJGUt~Z_M zt8v>HU(U`&x~Wvr8MDw=3yZUc#rk1_A9He4uDG$(G4=?`n{La+yj=nNl>X6Ka4}B7 z?R4-tg3HE-=CKWj%BHJuBY-G4lpx&qrY$SG!0^h;2Yz^P-j2s$tnTUN?e>vLoy35I zE`m&BET%bw?st1r^U8MU<@J4NAw1av1KR(4xneR5AWw0j+FF_ z+ch8aPCWo5_;$~q!Ny@!*r!qf6AlmsvF@gH=(5RNQUX>UA*)@w@ePh0q z&Ra9Gae*O?s|oXhu*06ae^q5mUJ7g!b(jRc9yP3HwGc_smHUb9oFsm+%>CO+aH_X^ zhMMchx)ea}zFHzk!*ph0=bebu+0*cuOl{c$(>_<{*1%aT^)MSPPh_l-KzoW?JjU-dBSUCG}ZW*s}4_CfNpxBcS6) zX8!ILF}W`3Je8COjTI-@PLBH24|c#x$jfkzjV|8Szh1LRMz;=aVp0eu$|D zbNTH}Sho(RyV>iPjvO+HDvpy7 zF&7I-2J>SV_jcBOe&%doJ7~V`HXC-i(kVPGO=7~~8bdefZ4CfT3<$nEp4tH>K&Ch& zoPDOJs%Y)?DcUwCR~sAA8RpR9+*_Q(u6I2Mo83{Qan@V(qifm^&!fq*Z(VS6`WKLH z)Deo$40Xf6JypxfiT{E#z6d1`kXfsHUZ__cpUe*?5~43YnQ10gYavYiKH&}aJ$H7c zwrWes#^GC?D6Bn?5e4hcq_A^H!@xq^3f7$Rld3oquA*b(M;_yQ|H&cPI|EA#lu~sKL+BQsQwZadE7WhRT(9R$>F1IjxxGPe69cL$ zEjt=4gO4Rk!TG?RwQ5`V@Qr1owve{Z?D~g`FN0Rxx+=);8YKqW^k}2A6Zib{Y4jgj z_p_Y0fl~VOcs+pu5QOa=F4da@9Y~apIJ;zXskb<`>3l!S^G7yxL(p9rZEO72{Gp9Z z?=`9WN}3YmpMmKTqI0eihPQ)%y$DrTnXZ}cBv}Rto~-Ou6&QNGVy zXRiI8Ynnq`nU}*uC1WM+p3MQ44J|peqA=Z@z>WJFt#wm33|R^0aL%~@*LLYM$r$zC zv|UmZ(;Re4O_iXn)tRXJb@>+^;bYl$6ypss#f^8_X${*F=p8;{&aO{AQ4XQ-yEoOC z^$_(hj2#q@y&@t6GzNj|oR+$0_u0T_8x2B37BD82*$t%M9p;~%Xrrcm@(<%MRwg6*l*ZM5c2(=Qt?{zxM|OPhc@r_;w<7{eF15uJ>$y z4j@%+q;>3Qwt+znHl|c?3}epo&b)f6YTn9&V7K&ERdoOEJG-O=_vZefYY~87h?Y9} zLk<5`!xU)mvy~?Xx^tV9kKZg&&A0hpEczlt#x16vnWa|3m?qAF~DnxH(I;x`}zDOYmDFS<&Ee-D-UW!@5jZ6SJvspZRs5DHkXIV z;zW^>Ta%LxYD{Jy7oI^oPtRVP41>}4P zEA)BU**}fip*%av?2fgp5kX$q#>9n$}-?;p@!k+JE#zTK=qvl2pNv`EJMtK zO>y2$_tu@4TNb#tv{EDVHE9mYf@MvM>SjBWhMPnETB&t=dL3IW%tu9qMG=eB(**3Z zx0CP`b3JO+Hig@*=|s273My&FzpoAgtHLNTj?eqrR#xABb(YX9)l2YBKku+kEcWRO zZe+SUFonrGG6}~SX*z*Rn%eM@W*}&In~MC#PJo6%9{_C3nSgSO(^%dIp@c5LOu%rX z4PbD$Wh#r??HlyCP-t&pYYml(LT`R{!MNFp$kp?)Z+U9;@FVG2p3P zw$8Pk77Q(G;+sJ0v+GIEokAlGG^yj(i>DDyc@y_a9*B@#mX+Sah&hV286% z1o3F^Z#&@+1h&F7Z6j}bUHC!Q3J%7;>TrnHe0TfD=Hug}R~8%*EIzbPDF2GM@!IYQ z8%w8K4c&n6tp)7kktMc)#0f3!3%3%dYeb-VZC?Th`f27gAJ$KuS1vDy>=RpBC_ru3 zg14MZe^g@^i?n_)j$~qRt!1q##?;JUoB4qgb|QEL!3A8khmV1vgMm4#7G|3stVMFH zNDgiGrB1h?GdMQZ2W9ClKrCvgUSj9|ah;8pNk6Mwwv^d*s}0ws0;s#*hMZ$&+OCVH zyNqp7-7&p;0ek|KAju8CsR3k=Y5fWTC&Urkcd9ozWgyHG|E^FSn|d-amKwDEhJo&C=8%-v9D+$v4l_G zZPRQjzX2<~Q4<;_k_(AYXHFSb2-$AjZo@ASPl#3Ci#lIR8$s7xi=ofRaL9y@3qq1V zMP^F)nNs>4-l#7hjhtJ}UQs&rwayM>yjeOg!ndr1Vh2{S2$^{Zz&*DKW zF%h1`RO@t7b{8dccf;9fR4?EzaPbrtLRer58#jcszpL()?v?^oZW7AcdWyn$BK%0Q zJm@-kNe^FB0|rp<+HY?xMy5SJL46c!+25ue-SXZ8s2QLJ^3a&hv^*h+Z@@oxOJ&sF z@2Y3CBdwvz8;b4md2VeOtVl*01;o>HD{rpVN1fUEX{f3*HU{Z@|CF5jpXbE5N~u2i z&doR_@M=x!(@lw`UXLDxcgF=~aX7G$gvi*a*2xv5!-C}*R>EiEblfPryC(}BI=ep% zB18*)ddO59q-?5RN|nyu#3$ULy1t$TBeIS#-}lFnDwM>x6t<_bRq94B_?`spLnrp0 zus+XUb?0lnx#d#JM!N_5Y?#Oa^;y?>2G0X_%`G;s6N_c&Dgv~gd>vQ&jmvdxn&_Y3 zS;w|!I}?Xo>-0#`MyXe-wy&*i{d1Y#T_r(n^U@_ORZrfFP}eyd4#{AM(3;6XU^9)Y z3GX8DFv(nOSsNPA;*RZ+PtuU=@>d#1K;KIa^9~HCOKmm4HcilCT95RzqpZq9m?d`j z{^9n%TMjCD0p>=73i*Amw=q*F0o{ZhZg;W%=EY#>_Srm;Dz==aE=P?yB5n~31kzrF z&j6uPKIXp{kV zOg>E$(^Gknt-PySV16sA$88{oh;UH2SDF0oELOYBx?Pq&c$zi!dzdME8@Ro&rtI(v zFk(KK@Y+(P+&!s`bd_+es-iBv11i-xscJ4n?q3KwY{RVWcGxc$Ia49KJIlVERBjz3 zzEUOF;9@&QOr$ASaciSDL#5yD)#{t;;(ADPgn&19*Z$W0J2pI3pJU*(`mlIQ^N9jm zM^i%5_8^#6uEEXHN4sVHVCh;DHFn_i*aI-niMl71PE_r}{j34LE$#38*MX_~VK-AaLEp#mFiw9cA!bc zW0vfXE@46nuoFO0%-%ja;!7Y}A14cj$lM|(=79sEWw@o4QA0jgRA=Wrcg`*OS2CPV zhUhEQGCRKN1`=k3yknBCU{TL&;lpY?L?~{Ja9V-pk#U#}7`?}g!=f8!k{zjTmkPR& zaURd+>9OAF3@(-9BjmX}Ha{@BRL?FB_Hu(76{MplW80Db%^>@$Sjiq+peRqgu3fu1R|2sowrQf68&u@w!v6|{} z$eFX z{PSz9Wve7PYA@ddZ${Xy<= zmC|yKIVQNUa&30`T_uAxG__CV@8OSQi~HhuATF4*)#b3|M`}>~RQ}?xUZHl?HkMbd zo_p4azO-E}kuQVtVRyv^EA0FK@G2?3UmykM0s@?tg)@W z`3r>|5~jaTPh#uBgtdCPZdkt0w&d^3j<2`7+;}^^I*;WhM4Pz3wwn!6BF-jSZpATZ za?4LwUT${#W1b9))<04nW&}|k^}?bBrAc<(C<^ogIB;u4(7n_p%IZEhY=eI#{Paey zVC8=b5$H#O;{AV!?|Ta0{5};n$Vcc!=yTc_)H`9H^>FJexn40Uy1hLEJI8oy$OPXX zCe4#WVzl(`E90%F)M<^9YUpYBW|abGr~kgS-|?>RxMx=E8Za-KY@V(E#F47`sBbk` zk|@$yT=A2XSzTtH>nqDnuOh;tnKV4rhL_394my!wKEz@+fBZ$rP`bY(W8moalTolT zNW095zTxNpH^q%k3as4mBc(3T&!(TpiU$06DndC1S=kYLPT-oc=GR*ey=12(X17rN z_(!W8uS1rI1g|ncPr;E_afj#o(MZ!}owzlhaKz}X*rH>3VPr8M>xFA<^erGGlVc%a z|JbulT)$jcbaxczGx?7D>FZz%y2?`Tz+P-(`SS6VgI_Vz5vt;~b+1QEa(=9dYx^Kz zGNN%^P?#hPRDG|Oq;5%E|ZzpNcT!to)Sfh-g^>+2LW*L1r!ho z{>^#L`JJ_r-r})+EBWD>N9;IGCY+>4Yre753Ew6<{JQ}?J}WvVZwyk{_bSiJ89@W6a4&F{EZ z$Zq%_^a+K{aM8tWeE;VYo8YWM>padH3?a8UZMmDkgVD0{4EE3?5n_L;^% zCGB(kH6eBXJ5sVvtLp0BZZ>(xhz~h%TUKo29pAY&+ zZ=^Mlh9HCIvu}_gNRv;UuU!S5!>OuMarA=9urzWCkB}QjCT3!?PqSEb=Geg8lpV05 zin!cHy*cvoDv<3rq@J4=8Z;Q_nQH;F$A!PBf7b^DXniYm7}=SYt7242ArK(z492gincuR^X&LCEoYd#A#XF7K|i~nzaOOulT#}Q2OYQ7V;jAA zKr;SCP)pVe=NOOvjr)`J<8rfQxv}r|?m9P?X@fOHaDmoCeOnPX&bJC(=?`tyYM_@% zzui*NlRtcnUR%{VkKH8@tWa~C*_8LLPyBOpdUDjFJwR}E)>gb!GP9aX!m|Iy9~pO7 zku%%Z_E!#OW~rkF)9Z_?g;~_q;mbMd@LfRDYD7P;MBOu;yeHO-b1APc73|mlJ}R<{ z(OJg-WBqn#228)Xa?QY5(j>X(*qiX`ND_cmgx!2?)g^!-ImY7uobZWM$u;^Dg;bV} zdxOzp`}QnwVG-?&WeoW1$#aH9F8})z)awIkisS08@DO{P6-Mu)9G`V@Q_3Wbs2kb{7`H8A!cAv?>jF{g^ zt~sNSmjYd=oKcABw@>5td559p@Re6nv<5X@ z*<^ggk+Wt0=c5pmAEhPQlH7FGe>}fu%vTS;V({)d7$>7|xJPB*?ExF*k=1o)3Z~Zp z?qVyc<=n|<2|e6yu6aek#eJ6l@?Zyb3;$vmSh#V&9Q1&CWbmIT&R4J`(KFNkm}j`7 z{8TS2M-V4AK&J4sWi~{zSMw2C08v{moc))d-4-riXYS9U`}m3EiC)Ze{pB@poyL-ncaRb6OhHF&{!&mz6USq7q92*4Q2IPDn~(0z4c&s!4F}{U@xIm~ zR9Dd94z*Th#`;*K_Do1wzwSMC98ynIGl4zZ5bZ1^*1Oy-*$g^9j1RmlHm7>VXit29 zU0YZt7z(qx5jz9t@KrG3`)~(qPm1kyNHCv^#(XzC^0RY@f_~AmDsHH`PV>ew zYEr<`dVQ0rxO=SeU00wA%-_2(Z*FMsPky}EJ&d{^4bJYTm4OA04Kj?S1IB&2i{(@8 zinj~i+e0fo{{N8j<*WoI`0-uetYofjs6e^&4cXYRP;(?+*0i^NVYE&o5aRxySnrKdp-m1oD+nmVLn;3?ziW_mT*kN*i>Icy z7j9{u)jOcdl~m{t9&9-E93%jnU`#QE_{X)E>%UmwDU9Srn(vipw+-o&KI`%(owRuP zu{!Iz*wZbYe6T^^hjF9iIOt}ho%Mk=SFrnpS*0DfbBr}{^?_e{FBc7PQ@ zG7W%ccwh8FCcAR{BIAm9zn+BYxYGA>d140z=)lAmQN}XrUUAl0l)}H!y@($DLT);1 zRQpkv)4!XT=7yFvxQszOt5GBK_v(&cuWw5Sj{FXvnndGp38zF!# z;|^AFn>^ym!0pPq+PcG<*+I*&gUwdFG}Lqa*Org7(K@QrHC9397JXwhxd~e^I(6>) zQePRXaa#mnQUTM(F(8RL3h%<*W~A-v~0e8xr3D3m@4`<69o52+woWV+Q& z+a0x`wYGoi=E@-p2)G`W)Q4{W1=x(;L z*uxGK*|0|>yizfkc93>s2xG<3(Q%GpKkvI7b{2M=vI9XUBKM{`} zFtkD1z7nO@Tx{O7$1nFXhHVvG_&tjD%d@uKQ!4<8vjNA?=};iOpj88QW7cEbr{qF6 z2r*FxF1IxBOCz#Md?q@qahR+LFJk+C#GT6NgDra^{BmJZrWl`m3)#HubHePkK}_+& zYn`vIbu+cu`WL(yH%>vVxI;Qu+eK!}^hU-sKkv?u-^BjRecI5VP0PqetrgxIJq5>& zf<|YLP-7mO;a`b6ZVzTn3Ug{?O?83{3E15K(MuK-vhZwd=>OqA#=!|o+w4kd#>}0E zz~vU&t^abNEJ~BoYV_9HFG6XMxPGcJG7XrJnTz87@g7qu zV^QKmIml~VcWHiQ4Ys=1g_Pxl4RLq!%MJ5?iCV^ILKq$k@yWqv+%c42OxQ7b_iB1q zzW7~_Ge2$$Z{Q{RpiUMbbsKh7v`>k#4z!BEf8Fl+hhjj0St&%dz=0VDGrNX4cBp3{ z6{w3UbF5;*{9SESHE7Pvkn~s_RJr{Bq1S&?8Pv7rKgFWlz+Qc^5H@?u#xSOZ=Fuc2iU!t3wFkBx)16qt5#YcgP$L45LLqoEv2OGp z5~kuiOLg|!&V#kjBsig9>BAHximdaNXi`kYc;nEU}An@h}AC*GZ! zKe)O@jGR94p3zqoe${gHG@)*tzBt|!|7wexgN^Rc8rr_zc^X=$DKnIO$XqOq#qn%g z@bFt?(?Po0y%}(rJ|Ay+*!`cux=Yvs6=yy%`$M^E>}kvGb~_jQ1%?oFD2?npuG;V`Q*kvyrC&Ci5oRSGNm>l{0;w->tlwPq2sC6 z3ovdQt}Ie014N_&9j)QJu$7Uo2J3y(%(+WGu!lgGkEkOI_!`Jhr!eOpH8$B$ITnt; z;LW(P+}Uh}>8CuR>wA%J&3R~mXBV2mV}m0O(5bkmg^Jnn5&HhYKEC=hwBrF@2v#S> zJ`5<6Yc=CNRM~2rB*b1y6MKc zEZ1y4un6N2IP-{eg7oz}eGB0e2Ezw~=#`@H*ZQ4FAb7Bo+vD!DIAV-^7g&SQg(7}) z3tJ8}GV`u@5^umyU|@ZcQC@1E&O?>h&~}X(zy%PH$=b>)liQ7kA=2wtwga?JJht8J zAf5-5+_t|iS$_MqsX<=UXU6GzbKYO%_`Hr!O~r7@(+HRIg%z8dVep1iIQ)P@NTxFYd4D`%PHV(KP z<~F^CeM&y!OgCYAfVcmWp9bvj_yPbeF48WQYUGIlO4!$Zt^ehIjS5hQ=CX2M<)?Dd zx~-?xOo2*;usAezX94aG>a!3+2!JmWT(Wpuit2jq_5JbZd%Kkuy~K4(HfNRAQG1>- z_x@lTDdlC(H3HSD(7l2+2j0= z(WVZKen)p-X-NnR>t?VVxW?a&R#GY@mUyI;bEY$+8P@^EL2aO)sZ&B~(Y4#;PcmZJ z9e#NnkyzBp&S1Ja6kOX=COC#!J|k#rdA6bVQTGou^k*aqS>|Bk5Jt!1_(l&ridPrYyrInWK6kqs)rbG>@0wX&^yXO|ee9Mdrtv@73xT|tx|ntTH} zD|$#?T1?KA-nPM@>bYuEED5W!Pb>{WK1-sb8I4Bp(Unx~xE3psDW~Oy4sR(UHS0rp zkJhnQ&+J`$w!HEun)H^++Yp^_W|hufYrK4KL=YAYu)@1q!Hj8r_q_>tV|ABx{BtKV z)j_IN$8x_>s*<-}@4D&nwN3D*%8#qvwr=j!XYEEGzZc!){kYZEN(!`-4kATuB@D8{cZ(n^xrt7=$)f&<`qm7Y~A@_I}hKGo{3( z&y;+5)dDzd`U%i$g|4Ivqcd=6PIdGNGIgDlhs`zCPlRf^U3!j$#yCHauXu)Ye zUAQ2FkGt+cOfAb#oj4;VBm!YOu0>s@-PwRMgRQTjb80boQeVb(gM93u<$ro|)4_nY z2prp^N=NWoBxi8sRxY9OGid4V5q_pFASICPIdp4LX2~EIGKE0yNTkU$djNvcin9RL{l{^$FsNED+9>O0aC?S-4lE{=*cK-I3{H zj?~t-c#c({@9ir)@WzLAU&b4#etv)T2!Zg?)kht`PZn3s#nJ+A-fZZ^OTRU2=`BZ7 zy*wLLg9j}|qceVL-uk@L4?g-jEqf#%D6pTD>+QfYF620n9dL%pjxc$yUiw1l;XDom z%{rtfx?(Ff*TQAep^m0yVhJz%7xtu%^pEKbdYq%7Tf@QBbW&F+vXN)Rr%8@ZKbL=?5INq9u6%1})R+ zEAvD$^jA=T5e-YgYO&N9AR1eV_|1MJLrH@rz0!>}rM7xA#ZAU7f3!4`ckg))N*N-N zlS@HgI)_F}c2i&T-NQyC?{5sqqzz?R3+i2T7wThGxm)8}1+3flE~o)1$?AonbSL2m zcp0(}`RM1HuF)!+>rUKnpI1zS@h&#(FYnyPfRR;JA1-)BvWgT)ly_GLjeyY6Jr$0w zVs_}yBd{<$8Q-yUeNo;CZ0gad7g9*f=z)+gCvG7KBoZUsGl6Fjdt2-Pi$|kL=Ra%A zv}o;q5OH&0OWpH**~V*@hiFf0;;z#L{7G7;P2SILd3nW%C!BXj8^W;dx!V2m@rS$I zYEn48EGP1g<@DmMPG%L+=7< zL<=;?B_UbZo$)<|8ojohXq`N6%7GOld3bx4^%TH)eNA77- z-g?;A!%unAJY%i=0kSda0Wgd{A){Qk1gP^;XkGX+~9?m*9 zW7NxO;Oy@%(0SpivR9?KqhlgT>YY~v0n}mJnr1L%!dSZ(}A9?E1LHSQ-b$c45~YJd|zY zxz~Z95dO1~?`w9@{cQdH3>PN%I{Is}82BQ?3b#6T>5Rhg{Z#W<-gH!>f2bsLZR

6wX!Y^!NKC*Nt@~_AKwAmEd`QY3m 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

Mg-dbapGH)j> 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 kk&)wu`7v6h0jN3=~#Wx^-UI z%8C~vCUzXIa7+8U0Z-;L=kSG~k)X>yHUb9D4B83N8 z2mKLi4DmQ|BkHunU-^B}b4N?d4c?7(E^H=sltWN$DXzH_n z0!L~56F%&}=Q#ZT{-FQk6sq`N8vUPQq5oT<>;Frm|IJ7C|5fP6|I+Axj}QI775XH$ z)wHwK^j$Y?DrqV-l8BtN56IrxChus>MX{%%!lYBI+r88OIk!*wZqx>u^JRC`HYw_1 z%%rwkd*jYV_Rgg&0)qg{5Uq|}2vPq;2&BvXnktFf_GY9vvEFP@kvjt{_Ii`wNCcyM zvZ`s@=Tb=%dviLnKbyVs_WSywuJGld_VSV`OqO@*|NPR~key1>P~{D4J9=W)orRad zp@h`{o=}=tT+{Y~UpEc6UN@=Nv~ikI=(_!WV?rzH7i&zq$qUD3Wb0wJei5JldGyuo zaTUz2hMnb3ExnS4H3!B$4C_@YcSnmoUY-wM`aL1!+yA&pzWS~Ne4^*>hGiLrg66Wd z1S%ufZqFAJp?v58BG<|eYYHQ+B~N5qVm56V4YbITjkT(#;fOg$@{Pu&hkl1$cQ#3# zo4-koM{0-GN_I9&x|_BKn4)YVk6jC zsP@JNrm+RA#jQZD<2Rq$xm;&cG3>kzj>TNDEJO0f8Ai7st{gl{VQcLyYjxW-ZT3y7 zxo&*rPV_O_Ckm?4S?Mle?-0>{l-PR}csH#C^RU=^_q3?;zbG}Rc)wX2o+F^`!F07o z(p5aIy|T60A~<^N*bHoPheg~OV*SKypQ}MelNU7E*Xp)Rpb29Ba#jFA*%|9Vd8jv{ z8U(M$odz!Zm^QSZQ%d`vLrUBSkL~hD8-%oMj4wh$>u+Iq`L~}Vc$746w@JIICvJtU z54CUGquX_W$XqS}(>V&eE2K%mA0kH_;NO&$QM#m^NyLS0j{o8-r!I)!*;z`7 za;lFs^25uPu#r1U$j;5>^d=|Y)fLE{mUU3yty^PI(FDP|^ay?f4n&w_IVQIpsXEC! zG{tcz_xs#f8x#bQ0cZY;g^oh>;7~?Tq04+5&-BvbQq~fE=`|#x{sw?_tGq!*7y)~l z>okXc{!BT^xdevC_*d9MOJ*`5KE7P+YQ^K=6aU6k(9Sio^0pj(r2R3CsQE7)?LQ8* zLywwmeVXKBt&N|nw01$FxNN%X26OFT!Fxuke6$vcxH91!HA%{Y(H$!w33^*&eKbNr z?G8WPCBdyX*WBYe^d^5_^Z$fwnkr4IfpM*YPn8FD;ltf8r54-)a?Q+-NQlWkk+u4l29I1- z0(4qa(#d`4T2{{;k>@j1R7r)xGr{q!y5yf1wq22=Ge9mMV2meji1C#^!_u-BQehR` z_CqR)_!vaaL9Y{_H-v9G@yY+V?u(E4D3Q^~&zm95fYQb-ps%!Ez^yoOeYPiJ_y>U< zHg$0)I2vc?15DYx!8mv5UEA~dg+;#gcw6hwi9hOM`AL`KF^c+ttebVgZa?YLatE@MadeYFj?i~Y z>!y?cmCV(|UUZg5d@;=)FDZ(WS}Ow>yev&VP#3Ce0XD*;*E%O@zt?1Dq{diA>_ST z5VFZ*3Q;};t+n;o= zDkT-`1bLeu=eRzEWb)rJ+R{Iez5p5*`G#x&d+|3$N6ast25Rd!il5-g zkbI_sR1!QV8R!k&kr7I@DjoK|p_Vsh;$&F|zkClX?Y{f4rJGUSy~lq6Q^QGRH+yJ~ zGO)rV)ZF8I3i~45J)h|OH0nO-gA9NK_UDn?+*e8wm-0jjxglHGF z>)j*s^wYQ@GHU~?j4ixtUy~*j)e+w0eH_?43mvkvN+6(YQUPA6adlzI2V|A2sXXuY z|BEFr6kop*{zX#q7h0t@lygfyycFPvme(S)!vI&2ibDU>x`xfJP(%>vNBW zhh=i)xtVoFTg8XXPOG01U5RcQ34KW`3EXfYS_$6xh-ko_;}3ubWNLPJ!cC}w)beCF zg25=dKl&{H@ZVVDlb9^A;!_gX00Dj4+3~DY!cuQgBi{Vz0{d zweN16-evJo=6LfnQ|Mn9;S-SKI<+_#Sv%QA8b`%6%5Dg^i>^RKTQ~4&&{$&-H1!Dj9NMFaM+~^3 zKNd`&nUS30|9S2UzLh$MIl-B^%AmA3lM9<6cTY?l6Ujz=1mQisCxX_>NUzwckJU;E zuZ~`9KMBpvEZ!=c?QeLf0K_T^IFCe;7?-c$wWDrAlAf}IXlxWcMINUNjj4t`7#jle z1daihgTbt(g-3F+TfL45K7ap5Zm!{5WkUWZ|5N`T!=eCP=8I06B2XEYrE%xX=ax<$ zCfA1jm5V9wABM7OcZLbMBqW0>IuKcGuJCoH{ayHO0hYJ|0F5AZxW?mZZ*2weF`c)! zowK5DQqK*kh=BvM(imx1Ln){%JNOzlGm=tcvdkQsdxkfu6+CCW=PwlTNkli;3l?CZ3{s?0K*#0y23&Ya(nV9dOq zE@9A}bCA(d8IoT>7vpS4IcK>kI8!cHUjjIg(q$0n+(eJpl6cfcehpJ(u8V>LXP^Jg zSU%!0+uB#KrrX*R_%^1;~k`!^qCV*)bBBJxJE8ogQ(uBaBAL)&~_4LmI-5fCU zee#!QwoiYt^We~(L7(ogPt{&{W`*W&aPW?6E;b*^LI~Oh z-)8>E4C=qs{n#3PsRObh}60WF>D)#ST)X(th}pXU{&h#rKnokd^l@S`(&v<8dMDAR4sZt0y`9X|jz! zz-*(;s^}XnIF#uzGZC!8SYPehs(o0(O>vJ8yDJHi{dCpOX0_3ln+9v0?Dx2}u*vJ)vr5oP=w&CJU|N9F>uW1?g#h)by>zD$C3!Xn zHjPe>-b4B>)-%3cTN-QY)+IUpbh`CrZ#S2;lTCeiec0zs0x~KhaK4Oigs>;r3Bqa- zHvC{f$HQJICF|#gY^QSZs~e~&T7<1G8Is;Ar5*iKsyiw}5*`&eXN9}AZRa4{YY8KA z-mdYL78mEG2N`ntd2jvH(m`@MG21I6qP~ySa!h!iV%MRIDL7>F_wbSnd>YE|ArII3 zLhjot3w=3cNv;AzKv}d5>58A~r`Bj?@1^l*Wy`Vep;ul(H-m?R>;f6xdg=ab4%T%7 z*#&vY2VAxl?#Z2%T3=fEB@A&h0hli`cQ}Clml2yu?Urt0wkZ+d=s@0B7>n7i|^@q!0Z3#lNF{p_xPH|Ij2xO#3nd1AG{D757+>E4$_ zQdW>MApU(2xf13aA6wb#dn&*jk~Q$yHJo~}d+yhu2j>@+)lH#hM=uoxL|2{Z zdO%a-sBzg*a)J;o8)2joT0tpttSYXc+E!S~?|kgkRCDuFMT)RHlv0M=ETCYz$bcDC z_~>+w7$2qPHP_^~mxD%3O6;4j*|aAxP*LafA1L~%FJ>p_Vr}Dl&q6vCy*k$$_qhlC zlRSCMhu=&kv4_&rd7B0ffFnR>SH2)f=(B@B8RZe>QU{hH84 zYzDBj$jt?an##L7e_)f(1fKk~1$pdriSPnxYkJ1=zhV7@(mm4ZH)kF^9;%gK-k2FK zhBnGFSD!zGCI$DMTe!QwgDQ8!y5U{)+Ek}sJ>713mGBZ-(D|sBMJ-n&N<=cJ5?^5R&O85-Z*vrXP&>` zw@ib*A}Q0tuR9^2OGA%!$uGsTl%S}M0lf4q!V)VjCs=QXwqc4 za_gCJ`7y%~X1OQP_nYzh5VZZ`46GkKst{&``@9O)w1v+riBfdd`dU&52^+W{T;>7; z>9e>ik=G^18|mm}2m*U$zYOomp^&fIP(*3`nO`!$Mu*s5QurQtqI^+Szf z?=Gw~e7X*_-8m&>UYZgbS;$hNkZ=Dyz4wE)6%w1j>Pu@_*Gx1uHVSg217VBh-CrYH zHqLLB1GfgZcsF1x$Dm34tp$)2*W2GM;zJ_lJ&-k+U?x?=0M%XsnH)LV18jaE`a!W2iDj-aXX(8Zc5e#%cXOca}y zn|p6rUIB;Q4emRfk}l#u81r_$SQeSMH91=}l2R1$y(PFNdlf1tPI;S}dIp-HG<7Oq zzY8XjR{Z)1j^y$3#Jv9(iNEpK45)=iMs)Fo#jR^le*Wa4!07|~JTKJOZ0jq268^%7 zz{j)w_$$#HU#y?iYd|$v8J69wf+Cv7&BTMB9)Y~QG&rOnk2kU{Jg62m+n=KH7Nc$} z!>JRX?13QBxdZAejKE1F%=V0RIuyOKoHqC-TV9)cdhQJrX^y%$<@id3Nv$Dxff`X2 zn`LXm!Q@+Vp9m|_k~>Ccu0#g{teLrcf{((^cBjy^o^D43Z++gJZ(%=*FOp>a4RBoW z95pi80-)2og)FsdHIoV%OQNjHUYP_S0+cP0PqmzRcvQI-ed3e<_LEL$1-@P zJ!VhX9%v#SgI@NEvghjh>)^{bx^HwCT z72WDGEikD{m~0xhWZCoD(|S>5Mv#&45$j*)gQ{%sq)!iLo62Y=MrXm>af zoNDSCk(_s0VRw;wjegWEFgqFKGPgK`J6iQ_~hHmn6C@ap|T4^ z|AvJ-pz*!;BSAErO`WZ=OU1L11zF?Yy1BtNs$`@^v;65uAp6hlDw^gNgg;R& zRHL+IhJKhY$%E*W_?n#8sY=bXsd5b ztvt$wDg!AnW9yKRgqdUR$ilVIB*v|3;R{;`O;7@#Z;1qWC`xqMyHkGn-MYrP5Ww(# zq{L3Z$<94QPeZZB+mOtF_FeHZr6_=PS|XY{KrC_cQ|C`wz&(Px>~KzA>oWRJ`EZ=! ze_GW_cO0o=w}}zYyZP57NA6po`VH@c!_v7WZMSDH8a1rzUoT0qx39Dwd0g7)hE%EN z(?8Rb__5aZ45@L8H~G_i+l`1XF+e*tgc5`KQ38kn)`e1uE(?Z>)p_d6H37Thz(_tz zGu{L#D_#I96$fBrc{4OYUf{MlJb}CCG~m@Mz8&J1Rb>mJ#Y%N%Bg1IIjrZTho4n2w zo>-q?c<8tezZK!51Z^ZGJn`SQ8HH6tZX4Zbm{2S*{iA zj|PC{c|T1geKPcBiZX!Ji^rEKaLs%6nq0utL2BPfTjZljX|k zV*UZ<94J8!!Cul?kHN=Bt-PwT-uE7wwlx#(GR!g{I-|}=` z$`KBd4CnhIK0*lR@q%0c1|CEP($@OLi&Z3n0b-^>c@kys36LPtLw!h{m>VsRN|Fbr zfk+|N+Wa8FZ!g9o@)&G>V+sxDTDH{Sy>eIe*+PW#@PQ!sO%Lyze;Z1tW#~M7v|h}q z$kClmLbvHY953I(V7drh{I^OrGTIefob4`A+nBqo&)6($YU2LF>kk}2B@#rK(AJPS z5Rrpx5z>2-dMI%#6?oqT!AZs8FFcO6f-A$+&vK^%-n=MiD)0k7e*Zo{a5ta(gLo=0 zVppkGkJYhL*9G&A=u7b>z(MMX54HL9jj&H+ZO2}rZEsT^Ctb7Dg=%d!;=v(tn+qc9vq4pIZA-8TzUkUYbHcW>?N^a+2 zZ*MuQbEnb&P6J=SSsrW`E#t{q!VTRAlG~Gu*E^{^Ha&0siMb8MsR72~jU^2?5ugRC zyhkg>t&0YGHct9dMO`}g#ByL4qJ561Vu=GsKldb5`gh*iec~1<5<1bAD4n9o3)z^s z+WG9MhZVn~f}4dHND`PSb-^m)4Q!);U8#ryLpME0R{kpVfbg9+T(u5d1czhRmzkKb zo$rkFkX>v&XwC?F>McsdR-_oRTo*S9@iy{@U}mSO@zfgFxYW|C@7DI&T+>R6W&`Be zNGo{a)->QR(7})`GXv;6^wmv`6~?Of1SW{Rm*aiOBBF7v0mBOVED@_554c;;j{Dys z{pl0H<&cq{`otz5YuOc;WJ9FG3)P`>zS3IcwPO2H>9rEFKfa0yJDO7z*%l0|&}cc&6vL=+uB82lJ)*IiUW2%oWasCnz6Q--UOK zyLmee_z9H~x|Q6^hvhC1O%R17fSb^M-qs52O=&qA9`#iCv{r`8{q2pINQv#TffQm2 zN#!dvbTl%csGyoBY4szQliK{kJ02F~mg8!5eyUormT2tE&$rT-0emo|NfcNtAAW}Z z%ueMu!uc9VpM$Nf8h%bEd=S?ba^puO&rNJ1W*)>C4}J7WMMqs^sc=RjgX8(k&E7X>Va{~@?Bw=> z+`!AHjL4x~(4mod`7!LYs|^pHGooYpwhX2$L`<$h!k?wUD8dWxh=gZo!q%-$bf(Hw z$CPQ~D}jSB}lTe}jG*x=&;pt81JqjSRTHtG>Pk@r{n zRH-sl=K$ikiL07Int&Cy2+ga&nG-a2Yz1*c%)!ge`WdQc_9cCdab}3l$~9$6W|#Sd z7s%gQM99~BI4-OdYrLkSUG(s$8|D4)IRy;UHz5JMuq)tJ*p{XuV3d*oDx!z(>CU=z3^d=OI2nGvV z!TO=q?;{WpHun_|O(fQHw>+8%q5sk<=4B&90GCv0*0y07%UpS0JvEbFojB#MS+Cb< z*z4-Qz-*#Ky;$&%lcG5irDwCzkm1M_{fIa|}-ETMG1~=i` z#ZHX|EGxw26IewQ#nPsP539^`j3?ssm$>gx7ourZfiB`W;0CAHeh{Zb$_n9??5?Ih z0V*Nib|uI{zX}fO_UMY^zwu@9(9b>LwN*GTg8hBavkwi5l$t^TTQK{5WXUcPsgadY zK4m|?@k=i7z zRDM|@+aRLZFrUjwXGm+;^aJizALq1~;`1g++!=}>VgTKt5eKdpC@PqPpA8eRHx&+R zU{8P@yltt#(RYv=9MEe8R0jcK(ij@BfTPY$5o^WvgZzj2{tK2Zmnuea>mL`4!raTiw=CmGLcm< zdPRe@gD(+wz0#=?1EyA^sGOVL3MX%&L_uDI)Pw|1ihIg+NmyR-0EMm;zN)YXtT{p4W(_5wxrM>KV+j6QILdln>XloJ(eZp&*;V7YkEZM?8ZmU zAzSq#CP-`Y`4q1IIC*?83Gt{+H&*WZ?;CAsH8sYc7Rl)oVm+iE_ediCW8dj{)-p1F zB8Z37t8*L6&QK!{$(oWh7uBS>yudwkxTLO+>(K9Ie?dKu(^4E>iLwO24G|PD!aA`b9Y;5mrYYPBM6Hi zQuPr+=vb@Qx!iGA_{Cavm1Iq;1a|CRe>=}S`PT_&cma2|CKPlNaFLf>Voi&WSy*V^ zjZ%OiAe>QYAlakPg*-d^GezS{+3AuJwH!@mEU!)3x0nM7a!cu`6@F zNlT<419u)r1A>ZB_4^OA)LbgZ2?YR3YLMI6+$z(zBQP`tRL{AQmKmcT(*3Qz%2b}R zx5_WUC0f27R}7m{q)<&BKeKJmXfoh=t8%Lt0gR{-_g)4dlnl8P>e#B;VQxqh#V@5P z7dsSu5JeatsCO+!l9EZmUg9M6V;8DLAUW5dP=uwkCqL>>Xnpbk0CFT^4C>_ll8{pa z`?z6@c?Vv3Hz&0D{~B$uWO+mkEas1&U0 z&TwTuKV(`=<`G=~{lIgeQe@zs2kfpy10Ty)(2_2_vL`K(Cz;^K>s*N*(Idp2r;G}) zDij~xpoCA|wwM)T35&g>I4!k?qLq_8EH7Z1T}4qBSP~*LW zO6_}m3|M)02m}Cjs%~@kd7;6j_Z#x26qEo0at@N2ZHhjz&cBwtc|jb=bqhyjU#-7Z zZ+A~HpiwSe6%+-&4PHFikyoi;J9MAmr4TRiQ|iUv`tGcw@p)x2;CCavo(UP}$wV5~ zBl#zJ1=JKysLpYfICZL z?@BhR`heBvlE0+{p)hNFXs!YT1VZZp7 zfqJ>b^|mSeI-k}qdazrXSt1bGcyh>85cOXgK)Od2=aPQ7mSb6h$nhe`xu-3 zvIF^Fw(cb`8#i7MP<;GCCfwD2{P;!0+QV~us0fwDz}MY~&;L&DU31e(u(fIF3jGrt zhBJro;-;BP$`NxSwc=CL@7~&{PMc)%+KERyh@hkd+O?x3SToN>bL!PyFr&D7OKgh^ zj%Ssg=TnV=hCi8^;Pg$8Bqu!uTHo)W=}}dDSR~)HA}pp!-dAu(ZNDJ!TzGT{V%)+C zSrw+ZTj1^37Y_mu?et<95x1|ER9#3EfV5Gm5(yahL#z2-P&&Lr)FAJdhn-i*e7z5d zB1+PyR=ZXSzW^y2{+_b6=K6-vh;yb+o{8ccECb<^(e;r}J^J+fj(vMVGk3TY-76rn zY$7Y_Z=CmxU1|4*;!|GL*y19(N0;-yitHcRh3RF5JeJBi22N4a^5i`uu|kwec`Q82 zD5`HVbD!sd=C8P9p;2rHPbrv6r^+{wWyXTe%5~b58eCr#ncH5E-pNM+9%<2y2_S0v z<6QJQKb>k|IP*=XE^ccfQJQrrZmXNIJFKc&7%^$=IP|tU6-=>2PKj2(v;xlw>>p5; z1@^lkf9M0cv|k-?cs%KdUrC6~%GbRHlZ(#z1~)Y-zC{xUM^8QA>mzSDP`(@nO86jP zlH!wzD@~0@2LIM0=VAaG^@$XPsI6FD{r!i{LY^V9^+rYkKcMFD0uhvA4ld$@Xo50| zAG&KZ9WYNrCbFh2?s?H2KzIpJq)y?t!-W*2cl=dlh$zKl4=5kC!m4v%AJK!ze9}bS zfbz03rD>;M$zg{Tj4E1c^Fl8_cJ|aLhnZ-*x&w)FA$m*PKQlaoU-t7fwCDX&bR~gA3H(%)ngF(e(waB-x2!@ydEFqqHI4G!~zAi+^R(x$!81ip4f1QcQBVO+>h@G zZeUfzc+XD`9!=o!d*wzt1u(X4?Z6I*#oY=8sB*|%+j8>v`T(poGIegjQgoMDhjR{E zo$03u)m9b5dt^#yKQ?Bb!E*pGo-n8~?l;i1#=1Z}G)~l6!FMyn-xE4{Iy|z-wymu0 zbrbrOjv~}t0PuavuI1jp>vt7*JP|#)#1-)r#uW@9U)^#!B@%EG?V;rS3I4m$tD=+G zJyrd(sYV1s+4>sCnQr`{Lg&XB{MI|eYVo)S&^_#{&b7TETp=FDjP!GA*A5t?#abDl z-{nO#ro&sW<8+|-JFN-!2w+WR+`2e}@!2eiqT*#g?J3`+IYLDb<~>ozY~GxM(cPP) z&PhTJxE)RaszpkOTjg%TD7#AQoT^&#US_#mx3_D<_BMjgg-6Tj4b~U3lJS#=UZcgQ z&50TK5V~W%5lr6aR{QhlWJMV9cJf>iQ2YT-%PAwSLe>t?DxmG zS3=|j=|Rm%(d+>bdYWG@D^5XAsUpQ+{C5&8fmGMu?O%W)aErRqZqdX@m`oyyQ z&ENnJPW$?XqHNAxzycStWe&e7@LHy4CJ+!H=v+B@BZlFh%tBpg`f?1&)w>j1T{6+A z!}4>Efdkr92iQQx)XdD>>fk3&8qU=fV-9XlzvEf?mF}^;hf;^HB$TTVM52`*#rlgR zHt}tk(a(2MhgRPgm6Zm<>BWwWC%r*!`@ynQ;?<6(#jpfC^4`(o)yl|Y1rp1na`UpK zA2DJ@s;}hUif{h%7fOX(0}xoW*Y9hY?Z5ic9{+k?Wc#bSz~+N#x*U2-RZ7xwy0(jKiO|b*fkiajNPElS#H2K>ZBi@K zl~0tyZzl@%J#lkf)}LiF=vIvr5pACqUAPfCnuDD&NRP$Ao2*NGZU7;s+w%gK+@g#)XqE^i zj%1?O_piaGZw8lxXC>RFhj%MVuWUFe@DDlEl&t$jBez!Lm+R`c?00|HZLE=+o0*$0 zsM8tSN^ssAwv+an-qaj4D*G-dT2OoD!0bhru$ecL96Ff=V~f1g2;wTxyL`_<&4sH^ z|1Gkv^MNlR&PCB_Kx;?z!UZW_eiRThrYVs;8u}>kQ1iNSZ|N9suq8J5y#MO$(~3)kU}JvrMPlpeFr@I#Ww5WvROrD{`Bev zqx&5k&V1NrS%OHZUgoz4Md5eZ-8JRIuPh>;ZbfF{kjxYd&JCoob(}?0ir66SzNC^; z*Q=b$J`?-*cAWJbjK+81H*{%j>paB60sn01f3Ex<2x5h&=sDuHvGq1E$n9}*H|7%< zcNF@SupBD@L0zEq>f^tDJ`}X@77CgEdcm^v=T;IF4d~T`nQq;a5A#}DT z#U#kI@`6z>#1i6?0;d|5jn8++a7~{peenK`Mj?nU`f$4(%RO-BG~ODw{P?>UKylgK z3O)hVCSv~;>`-mN>R?f5W#61?bbL$zB2mE(8;5i~3p)mvQ&AJ8Jo5oX@j8-cfir1^ zErVs;;9Ra?@j?jjiQ*fb9UJz6;)z@|tRR$Ps=`=CDUqs7Dr0nW_kGdSy^3LJXV{vYqD*y062S8pyW=;gyXi&6>e3-SpKzooqP%jCg1F4qCL zJooTWF@z*6e=a*P{GL6%U^yyZ$!RhRFqtpT16#oInb}xnW<(v7If#xbt~$!LJ(zw~ zD?(ySbj2eGC-*)Nl{^yYr1Mt3B<*@i!ADX$w@jko?Py&3saxs?4{Nyll7)drOZBJ1 z`>~Pijj2Q#Nl>`MuuRNNdRnsdL5i8okfkCJz!{o|Vh<;ja*CQitw|2{?^Sj~Kytjg zzuYL}ElmWf$EfdF7K(1fPcf!olkrR@NV4MV(}+{VF~c3x&oIdg?jiT!Lcs$4xb67 zrhtb-4l1lJ2|YVt}T)+us8fPPp>U_6pBY15vDF_%Wyd{%k0{O zC^3TmYWAuUuk*v@&X0Ta%bBOr6cK3>y!3zye~HEW1~+Joj99;r6!5k*eXh?^%tjp2 zoP8KVdc5wfnnfCAItBV#K3VLTQL+#0+|;R6vs7CpANZz}9Tj;gQ3~=r@$07y29l2f zqYJ#K36werh|m^ut(-#HouCV4tKMVT0U;kUq-oe>nzfo7aZ)Bf*Kyje1mYp0IUC``Z(r|=-&Gu-9uB{kq zfRG$p6e?`;_pc+shnHeoV`_PUD1w!#oT1!t?7~x+)Wx@E+<=eke z#Ygqz zu4l_fnd~ktISx8QV>u+n#7)q3d)Dp^8uSAHY#!aRc^qxx61nGeD*W&I-R|u)5TIE2 zoPi>K@*e{}>`qYF&M2`P9KNjksjOr_d>vwy8%&E#*`4A%wZf&6$F=rk?%mNxb`a$I z#ixsHiJq%zz`ga}NY-n?1Udf&PT$^5!0|)7UewM-!@<*B%=BUZz`&LtFMe0nN6HbS zW~SA{jaa-a#uQP*d(jC9@89f$uFZ!kx$pdn+mSv}?pf(Q8MNR~fivNkdiETw37qml z)rvzRQWLBreI8baM0U>I1o?r@{%MvHCAl7~{`vbMBG+9OWs=H)$q3dn%f*pdD8vre2AIQ)0T>x0(a; zR*GG4AI4JpHvR6?Dq7u+&n;+O8d0xdx8Ko;^PKVePO%z^Z05!{y_&*&1XgN_)gk)`v)v=smvkeH9`TI4g`&SM_jBPs zE$^D-aOikJv=3-5s4qpBG`1%p+JfkdKJMpmB&Zc1-ti~Heu13m>m}t}RpET{L?!!k zJSo1vE_BWWw^l$RYFwcd72spevh<=xg1YN#62HnGhd7bDUN&4Azw>QOY!3)@Wi_}* zH3CS({mM6Nh4rPD|7$O3*^-*H(Dtm8++JC(W7cUdzfgr>p)%c354LNugLg2-OwPJl z8ZUOAs#wIvMEXew4lMJD<**Z(e~8`Cze~#tK5#tb@QYZ$JT+w@CiYoqBzVm4zrCe| zq53PRerRt?9Me!Nsn#2HcN60Oc@@BbB0YJ(XjUWo#ddw@gqRZ%a*jPb02MC>+W41L zkw&62Kk)RpR+VmtD{zI8O0<5|`5NaCT}65VkMOP&vy2%&aIhXt%wzho>)Yl?tKF=c zlfNr(U+H!{cy_mTu**A0X{pv%x$xl+&OLQi7S`|F-#l&Ov>!GJ) zGMmt^{S-##Z7C_83HT1#nRVoTz^MYK;VYekS+632 zooF6;)e|Y|ivp}qG@Py zCTwqipR;RKxx3-vORjI^k8mU}q>1**%=j z-Zo$yd$4&dkv<~KF2B}2;P#aIL=ig+6c2(x61XF@;NVaT9ODP38c)OUwStC{A;hor z*#*Zg9wuzl%D5be`m_|XvNk8x)R?)`eg`Pc!fnn>if1#;uXFX9rJRVODMJv0h`=ll5m#pA&rGw0m*bzk>&yo$ z(9B0=QUR0>9gfFSNw7PX+)gq)Ol~qPmN8*E_`2R;c`wLLVMC4fvjirg5sxXE4C8y? z7Kd*pLcO}yXgxL)7a6~>%$R8v@13eQE%CB-zBPY4IYX@9vzeD}Qg;n}kCuXR#F?!w zG}wxf$>vOn9X%D`QN*ZBd)k=j=ht(1Mo(>L(+$m!LRGfH*ZX_Z1ig4igs2`T>K?JQ zmi$FYg9Sm%aMrSxPCQmK>b@D-5rWQ{8i#YVp;To?kfC`THX@P7;~?oiLSwI#oiDdP z#QSpd#Yu^5RQ*a&1c=PhT68OZltgOVC_P$dn~}x~;6=xZA}D>@=nGShuOF-Cwv!16 zX|qkw_e_wzOl1at%(L(fXSPoT|H{~1RXW-jqkZJV;MZs?a_7$^;qoK6K*fd_9g~o# zsf@`ee<8HeGU24K3}zO_-A+y7#au%62eF2v(q7qkX;hb-uJs8H>bO%@;vHNy^ZK6T zwJ_f9%%0fxCm3KtuJIed5czvDTi-ht2YLXv;cZVp6u@J6ad#B?csK>D0A) z_j(i*YqXv>_#JU;8Nb{V9mU>`Bl82QU4q*y(;NK~U(4)F?tY5$PHu@0W2&FY4CO<+ zb5ie0mT9*D8H_CpBM#W!vI(Mu^&b0c0sEn~^E&-M`imn^6b+3TJaszt4)umrSDg-? zdODVpc1k=iM#``JJzfB!BdabUcfd+zu%H-Rcy*?7Y^86`N7l)um`68z>z)fGnN7F< z&9AudX`Q*p#zrm}M@*b5a64*#J5=C0f+s72_quK95BU89_v$Isg0?db(Wqq%DMN+! zc3bHo_kr%2wuXj$eaMx2l>7_#hM%nSA9F(O+7;d$S?zKQ zijd<<6mxMSv;Tf8@KLXxf4<`Q{4v$%`mt~Ne_kFtFqauV`Db+DVn>VLm)@}EuyHMg z*v_wyUNk;%_Q(%WmEUVY+L~~UvfT_w;71(jA!(q~Qg0yHtr)iwY}>ibTxSArkpa`e>yfDde8;7aSciA(U&QFG5GpNb(- za<^%I_cz~MU3pnth(*aBlb7(&m={L+^|34)(a-yglj?_I*Yxk6U&*GjFSrg8o7SK} zE<`9^_e)!po;uyzCUYiYY(WW>&Ng<}=8M(lJodjtif0T^ z&(ojjl) z?Aw$7jP||!f@#q5qoA~J>NTYmBSX1Q|A@PGr$=?KHSgS!*`6M-v9tO2jco(dmESU6 zct3u&>SY?edVx7})z6fYeWB0ys_JS;Z}j88jA*7zr*t4gt9dYDhBjT>H`tsJG3`{k zEwb%*vung`&uoz;??!~!JniC+=Qx9ul5gr&dr?2Ar5v{S?9rU{{>-3BL+)h33boTQbN{rLzIbGP2$T^|P>IjAeJ<^IHekRy^% zhk486cu0bm$D`^00^w%Y@qPX54v0F{eeLdZ)4MP4{97e94UrI&)r##P_bI1z=Xyq` zsHU`RQ-3$fEs1Yd^1jIO67EXS>U&I<_Z3w7`D48&mZN>D^-_Kf*K^JL9ph1Vi_Kh} z8d$(YA?8$m^()-BE;Y@gdvClQd@H6rr&1Bg#p4puoIW;`nD2EeB1$9er!#7@)jrki z?eD2Go^DiwteSGmbWazpLb#71eZd9rUtmaWrGXlHU2{Z;G6l2LBpqcIw0_Z3Tii9k zde6-FptKI#XD8Xl!%IbJds=m~_11HS(=dX%#Xr3ZqIjX+^N(G0NDvwtqKcaL_3bs7 zF5F*)2H6yK{@OYslwbEX_WI(CB%pT*qa6vqpInUnq~6Sv)zweqnhSZ3Wy1K1x`soGB61j63X=SX?O) z&MYIs1W?d8r7SzW7HH`DEjt_X7}a7`F1; z*gQtL{(Vz=uk&8kzblNMz37tfI8-k~R`z&R`t_0Cz zxOF1t)P#CpDZvKXeZFNbi>nmQYBP;BfL6gHW=c-UK`*%&GJi96iec%^GX{G|cZK(9 zXRX>DhOW~Wnq)QpXgNYkU}XHXmWgcQ;=V0}gf}te39#;Qt7h;E$Gm=RDD`)3(`Fr9 z2}(s}r&mpy0H#`W;7MW`B9L{3arJpMM#KB9+u z-Bg8C>2kBAk?R0QgHfk_^s#m>5pcn3F1IG>YD(Fy5mJOZwC?b-)qSXOiM%-RLQrRw zmb4lXvcP_<;nrO{9yisr!>t1~RIlN#w?4fZ&D$cbEuKy}9rVQlJ(i7fUt(>I&O7o> zN0iC1TwlmhKCqG@GAH?3l5)nz>5di^_tr4AxmbdJ#GILd1{e|Lx=h)0` z&hnUK=+f4MX}^C+ePikm-@b^3583wnF_<*gDyT^5WW8G3Qf{-fnDBIVtvh&rzYe*Qd+;e4*$BuoFRz8KsIB z(dcIF?|gjMbgS<0yRmW)J0Dxa-^CYxJsH;?&kVU3w6K)>^qa=BpYYoBQB1%P!E&pw%8dXbg?`MFex$5BzGcI&zxXGBz_C9#} z;;v!-OQ<*LW_}}Rti{+1$7#8bR``m7Xm4V_VwtsyKF%lM3bh**D*(C%HSo%bBGh0Xc6YdXI3eWDCt2^7+JQG~?{E0Cu zb_}I(_}jyBIw!kQ<~EM=Ea~1 zE^=gwFynT4VGFMF@c?;8{omc`6AvG>s#?SnuMH;|yh02WN7oy_J$mb zA6ZTLT(726u1iZjDI^m|I3L-s;UdsY0s;ip1l zI+8?BJ_%d`mX1R5CUdf7>uKF&C&ux`K2a15#N}aWrgrLGeEnu4OJ3SMH!CjM>4Ea* z5u*s4(B%9nO&{%*fUPQjalNT&Nhg@^N7dth^K+W?F@1`8P|j!=fBRHTNKBOY&Kz%W zc7$|5Q`dO>UBBjxzXEdAGl*6*bRWqeFMZ8VXgAXuUnfNa5i5nz1Bx(^z5Z|^NhwXHltKggI_WA=wqZk1VXW_mA-;QzUK2c=lEz5R9Sk`WGo)iBI04Pko$DI4#&UO=qtwm zAWWSSdX}Jwp0ZjmNxSgE{0x*^cPgGIxLKrEcnb!Nj!IDPL9})w?X<`x1fFAs5oOVl zVyeVNdbK>{UY9c_-WX=s9sg*3K#pBmq7lCFns3^bo}PDx%x_n-QQ|%4FB8UiKh|!U z;ZvV^kez~kSCQ?5Lc_Xa#xp7GistuCG6S*O2lu!x=Bv5O*Iu(~Ek#ey!cz1I#{()K zl&bANI%c_{v;8+-i02HXs;ytAjk%^XCZ?p-qHwZdwSfHjIMf{Uak`3qjkW;`*2GT1+{S?=s&#r z>Dy!Ul(lM*GcvO9wbj@=JZQnE$l{vMmr(<+oBhT;>2p&5Hixdwg|$W;WMrN+#Y5-NRPr9gj#nk~ zFw!bv<70Q@)Tw(~4Ue%kl3^|f$kuO49Z8k!?bHW>J^|DAsE||ZJpD@jW4GvvVxFVo zZAt>gN}`<2+6-LyNC+%0zK>E5|Do07X7^j9++*RHM|{_4(no5O2POL9N*;lHh_{y} zdxOc)PZsv%qyO_GW2O6C^}U0^aemILWf|g+ZgOw3@-W&_&!-B-OzyW`)J#V9SARh$_@)dXULldz_eXN?GK@+U|m*sEY zl+R9LY)yO}p9qn85P1s)5E}$alhT0-%_7s{l857?RNg5sgJ3H-hhy1J~i8{N2VyqH{ zW)1{I7K-2?w#2Wp-7a}dU9ph;kE$YW#mZJJ2d|p+8?)`7eB=(JmzREnR<5(YtOfB- zVA$$-Dw>V-!fQ`(se~_?+A|G52xwr;P5b639MCvA6Y-?$e)g1~s(X^9zY!<{t21Q- zE+C`n=hZKbr}mw4(JM-Ze_%rf1O1_}=eT6B#MLW!8I1(` z=#pBi)q45_Ht8npNVl&Ia;D^K(C!Hh6>)OL?RcpA(C3&p@NBLYHH7eEsq>hfwj0V| zwcO7>vQp-nR=G|Sqvp$5Xz|!T0M>BpHLL`|{Vt+NIshN#M!{VK>Ptl+#)1lchL`a| zK{9vOaaW%4c*VFcjhxmxrQu~T%{?FTQT0ryMeHQ&@RrUv%Ce}*I0k%;UxEJU)}Cw& z`RXDaCAB>5qQHFTJL?Zo23Ufn*x&zLj+m?Q{uYM0Fj7Zb%&7A(9ayPR8c7=0V2H43 zXSneVrE$t=wh_~8A@1@ccJ+I=LR}?l7GZatYTlW_nLhnrmsNX@=XVWx(@>Tu?`504 zVE#21vSFMRJ*~ClQHt4fLIQ7dx>f<7Bs@)E6@{t`fzo@%h+-jaZQP|3b>07LF1|Qk zJjlU~R++AInZ5q1@Dgc#HU~1dCIv>FAdfJ~>tHvTNzbpEb^J^o(4W|c#~dTcZN{Kg8^XHVE6;hzGJ7BH z00)3PR2V`dzPEYfj<^Na-ILQ(aQ73+z#`5?SvFo0g4^70u5Sd_kbRaD&qNzVqaJEX z4DI*c7jmrbs-(D!Z-4$QauqB+!{L^V%n6(L$C3vs=digCiUVJy6Wq2MuPt-o*drOD z)P$Zo8##d9$y~lXejt^-CApTlbI$NLwUSh)PHjY#79}CUssuXs-(ONeT{#Rh9{~rzPh#h18wW#C1av4N>#7DcKT*a#AO6EEbP$PkzvJ6U5h)n5H_zjA3Z-Q z#3hdl7`nM5W$sq6Y-G|OA~h{ro%$sy(k^wE)jwG-m`nI%9(PlqEb#I*GAF8tT&;BA zoA|ffFX$!wsjBWG#v7-~v$xXJ5j3LMzm*qFE zNcC=_BvTc+H^VIxYR~&_hqkygHS5_{HHNzH$#>-?%fN?7+uW#CP!`or4)}F%|BUWT@xjX_V%P4S&7m8SZYd^6@Gb(bP?GvXjCjM zJ^+qF?37S;O9RrrgkZh{px z58`xBl zGIEQ>F9fGMq=k7M`8sI4MdfSccfNA^Mj}rFhK+~N+Plt&>tGqZ7E~yM%3cAg$Tmc} z?NaE7P*ciQa0s;(OUz{s2YkQinbCm~6aO^-$<91dYv3F-xtnwD1oIaYX<}c)?N)Phg1rw9b zU`Yby|KuagP7KlPF}{r*pUo>o!m1MzB$+-R_8joJVQ(;U=2vl%BfX~3=o4;cb?nDV zDDN#l&V8kCj)I&|7uth+9uKmP+3MBs{XJ9O7ANl7?^@*a%e%C)=5FUR=kEKrj@iV} z!p4tKE{E+2X^Fkis8+TQ4ca@yC{)hK13R^CAkt(_b$(vX9hkU)C3a@SY{jSnfDqFB z&v|1tcr>EP*oq*6ll$1pROE60xWC~;#H&4sH++Q7a5h2Pl|e?LUb_$zl@|U4iJL%wL-y>o^1H`U3?h4P>M(_mcqV^W5+C3;mksN1a=<#=WX)H6iTW@AOGK}|Y zPgzz(&=ay%I8p}%Q)TZ5d{KJ*NVMVWBZd99#+se%GeUk{^ep~Jf4&k_{jXumVrV)6 z>3IFjg^H>)SC6ip_gi4gDWscFTUNp43lJ%D%iO&={5>Eq5xS@h33o~Cyxsp=wI00( zS5xx2o5ndq=<8Qmi#F{TGO53^3!x|imkz!>0@80UnsAn$V$b{El2<{^(}R?Uy>}`> z{PK(dm|oCanD_1a@NGx&oM9O6+EU?*CRvr$7dzN~BH*r#XzZ5yjKz_3D9Uems!u+l z=a6Vz0;+Nz)M^J#!+Z~H_(FY9D7)VZjYCb*m39S^AXA(7PF&piK-tRyUw39dYO-u# zc$Q{G?w8}~$aZt4auO8o?!rYI9xy-ivV|VMVh~^zlE3yev&wzODF@j;`xJ+&s{eMb(DgwKaN?{|ai~^sZ2kogRE+&rOV> zZRwK?lf7bCsPO>%2KPCTy7_{)qrkOY>^(SC78CAtoQYvTqBo|^+map(Rf0M$4tm0X zFa;siNznUx5b^N$-7{j`dTly@-wSubnVY02>K7gPp;S*Ei%bqSqxz7eWSPR(9_Yaz z1(4_#z41qVyy~g0IfKUEG{kG#^eFchlA!!`Y4ZZy^K1>BKqzGD3)#rI>7-FZtpu%QNnZ%j-aUI#}pEg|<8rs0&S*4haAV5K^_SeYySJ+2JI@S?RmC-PMKsjCDwXOjK4qXYvDY z4g<<(%*WqDi5fdIUj<75lgvG|6Wd|ow>#7z1T%)0y+=zjVk5?LaZT^oo-(MY?=5FI z$)xs*FmVgSFj@LXP}_~sAb!9S9%dCu!!Nn{A$PB2T8oi2G15tTuFC8VH6(N+ZvemLa88vZyB>P*7`zcMl<70GOXDz zTf#fPeww(gn$t>QFE)FkGZ4%!+2hkE)nfiTzBOU@+8!my{!UV1ZI)em>T@IRsnl-; zH5-mvM!#HgCZYKG-Yd`h@%(63Jn&0cj6beEFS6B8C#L#PR1qh z9l_KVM4B+v=`)yE{3v}i$UE9_h1o;a@2ZZX3A)cYgX(Cpm*X~W>qq4PpV^S{Q$S&S zkbPaO|KGb-)5Q^2k3dA&-Ilgd_B)XJKILcEp8S#(Z*mlqm{Ar!JN&kby)RCHEG;5^ zgX{gIEo30Bh`lNp>T=c*Q6|uYCY4C=CA<&XPHXHKOF^YAiuE2&u_>Q%$M?YUJ>mLX%4wAuq>F+ADOL4#Tfr`7v{7~5N z8K+=bi>tlyyry(r>`#_ne;eP(Ml8jtJfk9|6?hbBlWAyr66UYq#-kC|3b1Y z_>80R8b(Nc3COV=YLwOOQps&G2&3 zVbn3|E;YA^LX-Xv8~T?BkW53A;$cn=q*imc?!TXvZz2R)k!9yswyaoyZ7=&Y0uBO) zv`Q{=t8w_M>Wi(fu@1pl>MY`*7>97L8XOu=`a3B^;bP?ep4Ys|J^ z(+(4i7p2?|m|r6cazc0ijHV2CVUf}K=Q&5H?-TafS5epANPkAdyvgE|*4tyN(2}mA zrJi%W@k*1yg~!adqoy+ZdaUR-)jx0$1I2{mCKUB*FJ=zrvjylKnd~b+KWQ_T3n(r; z&}Ik3*A$C<9ZaHZ3@ZtKO?pLAPY|f;HG$_)ld0{>hmIS3g?Gjq7yp(Fy)^FojQ8#_ zGmc;P2Gf%DQjigfLl-3puy5uj5vz}3sl(ywsFkCWd>Dk<-WKRoY!EX`l&Xln-chj< zx;*h$>UGF3SL`JNLa%yTkp@{%FCi};=wEMW>iwi8Ium0*uX_#_t~UgY2r05tBVe}G znCY{4FDddRaKuJ^SbhJjK;&H4egO<4aI1E& zbP-tB$DnX`-UhO|R4Z`^vo(uHhMI3gml!JGWmZ;4neOfe=11F>LrTLEAzkvA+$_6Res}T#s^Usv^_~x1ALMZhrEQ%fPMKmRy2U}mh z>S%8!rtioIeGVu~{Zpey#zka zKGtI*9OL+_XG;g9UD%`<{=F#VmC$7PH59>q=(_T4&&K1J9sw;me9FPd>qG6rr0O}k zoYTVDN6~7#6(Q16fxF-`1{mu_-ECe?=!p&OZJb9b-Qr1^_9jStNZQJ9&F#Z3$`6T9CT!wr@=e<0TWp;b0FfzJ@t={O!k0>IPx%m3LkR9iVXU4@r4tw?S6)}WsqHDkZK5!o+_o&U@kqbvodtX%oJ?E=A7XI!3`=qZ47&eQgi3;aijN9B|S29L}JMKEW| zO3t~569J9HHeXf;Aig83EPDdW$|9y^s5xJ39fU1v2C znLfjTE1m;^O};bQH6_bqs7eWKfA)tC^PeBM(sAcJ+S|?B#aygr&PGhFgN-EPb+3i> zFAEq~Ae)tQNW(SI=VxC!)}6?(dk8)nQkED~$#ql>dec61WvPN`1>kJM10BZTH#Q4R zeP(#%Sm!#Gl4?agE(coh$@tE=>&rfnXPbiTp&nmQWT3l>M79#luIZ)_06%_TF-B z$U)Vqt{+}vU&GLR4MQ?Gjr5Up05|#E^cdE8Papo77Ky%kVx=c9=Gq1PAtjh-gci)} z3RI!NHWRwtXLLx(mzZyz_16URy=5pH?PG7UGkh{4W}kEqb9!?w%gPwThWLfTi6+mq zGl52vy^>{bP&fTrcvqI&>O_dqV3~BER3fvoffal=v&(|Vhn4u7QZM_D<_on=Ag(e* z*NJ2Pmn9P6tk9OM%`G>LrOG!k^n-irWK?|KQfF@QXx-n}&66slx!c_?Torpe7{2C+ zK}}TUtAh~-J}_a!#5!D_lYQ1e&jxU4nE^>!LyqHmfVFTH_|qM%4Y zsXY5*(PydzNn8Wq7R(4m7o!4jIcxeJZ=ZF_D7kx27uQs=sgJ@r22lw5f%0T-adl;& zHg%@UrE9@w=p);~YKpxP4iTNsb1Zot)v992yP5zKYn#$S(BTM}(ZH1*N&qTnW>kHR zPBQ#!zc^iFrz6XnxZzYNH@A_bW)+=>yLyYs_AREini}zJfNGzz9fO4EmaEmswi2!B|Czf!RyJJO5GmpkLL`%$4stK$q3&etN+nS< zo;^&v$5&XXj~@c^+PK?%L?MLlqo}F$fRhNAf?pqyBF$wl56w9aWH5czQfck|b+Z{4 z1~98B!E;gGsFq}3NM1$W>7dn_(S@$EJg<{^u191dmfE?~JToKQ7XP$HR^#%;pB6;1 zGSmE{n5fjbmU(BaipIQfnzlAuc579`tNYQSR;%m_m}kW260GT3;HD`%H~DvCYRe+a zX)#%hwbuY+aV{;muFAot}&%ENj9jyf@5E9N&x74swg(oH@6WT!s z`t*-t`5YZfeSUJ4z^}P45lbBccA0|-R-HG01+$Nru^&5Iv6^oNx(6wCL9}00yc4vN zcp_&TTID`rRli@bz#El|*N^@2%T^?O*`|I%e5khuoz z2h^d2{Z}fflxlPLe|exrq6soH7--Lb4tnpym)ASF-Z_O(7JG-2_SzY-&Ml&o(%voa zHtE&&&O5CBwc4imi$BxwP>v;E$g7=- zkT8sVNlGFsqo~lwVn# z6-|WHQO2$y^+{QX?=(GaLEzWV)SHnW_hOA>f9v%Zs z82aDc9$YuQmMA|zwa^3|crAj;Zn$EzIOrUXht`oO%(`v`}h8d3_jx~I{hYiV`|uPzRc*}md2ZvR*1+(xP&O)R>-B;Q-&e99JOYK&yCzhGrz5uY5#$8TaSvq#|G+t4*?!=Iv^FTlBOf zb*s>Ta33f_5*`-5G5Y%U8Yj4i7yH$PvLdJn$N*-U{Jiq1$yMR%6ZMpFuV}X@m_4R< zxBu00;-vpAD!?N+clag9oA}xNi}~U1x2Q6dpByC%NvI6ji+~-o*6@(#bCgpkCbWUx zWMv<3u?Ec0=E-7E(DRr_;`n?|4~;guCdk7?w=vaU4KzieLXFMb2h|e5nqrKmpk;|t z+);5**e5e_He#DzLM3im_89h%^6etLPft-UAUCCr@3WQKt3=($vj!rf=h0?-Tx_w! zck%4GonM^B8>Sk{@R$2-kEeT9)7@0K1enqa-0ce7$-|vS`8SUMUj8uul5xTLI#dGo z!bZOBk+A0Bp(%7&BF}2b31&|gZG5e&(vb4pNZlF?r^@kMfqM^bW{v+XHv$n@qs9bP zl$@1U*u4e87c%&)g;d>YBa1_c^6udPriL?q->`9@Iq|G9&WzuX(F6fLeN%sb;V#cM zJ=Y~5h-@P59j><%o0Z=yd-b53YFlDn_&rd_UwF5J8=dY}y&dI(_H-~&qKQ6@)-$Q2 z3gsAao`S-OCHG8Je-U=vO4a+nSLm}BO2wzz#fg$LL+xd$mO}EG3K!9VhF3_Jc*$5V zCB?(`;(})IJgRnz{;W2FQI@AmHO%tNRblhg=S;+?U38NpzU=qERzAT?3tty2>jpz* zAx(bj)L(X014o;&DACj9i0FPTSBKweLzPq$v2}~nH2iv?1zl$eb$_;H|E+WNf&#uV z8H<@5=V+7v{~FEt$vtn~R8WBDzl~bHL~F8|y7_U^fi0clBqMT$tS~tzvsB&C6u~Bo zd|W!~QSbOYvuAC#cTg;7X6|Y}MPgouLMscUEerQfu_MVpB~d&0(D8O%1;1Zwg*QfyQY>WqS` zY~t#B1F5AF7KO>l31Aym6go<`G{_VJWJ`aPQdiO=LjWYM!awbm{ypyLcecQiTqx5W zkqM>=e;n=F)5&*7AX z47&Xo=?de7Y$UQCM5Pxc1tqI}NhylE=95g6pOz=%ty9k1!&oz}7|k!LdOXD=B;uJf z1RDpnLN7w1`M#8qfR-1_HO#!pw;35>v?mp->2psq1iHEgPAnVh7=`ddbV=xp z;^mLS8{3QF%dB#IH#RFTk3bEU16wC$Ex_1irWkgzeQFtnn_U$+XH-AI5|xyfr1HU^ z!Ty^$BBWhe=+OXEUs*Z@b-`;^{o6}sUAA7PWlOpH)>6#D7ECCw6 zbwui=3W{F>Kz-}h9J0aNe`ODkemhZxFAZI<`nwW89klhRo8yZkRa<9ixDE9|jbQFE z9=Qjq??YWm*PBOIl;G2AbxPB2D(uIG96n|dDgHX=4w$b&YwAWF_F3D3udhzw9Yq7w z=9t$3T-Mg5RSe%Qi6@7B@A><9+>;S;swHwtpFhyyFMS-L%=~yzP{Cf>uvD?!S`fv~ zS)>x;tcb@{$n9B@oY32oOeYl(`bxqUcD*#1bS|vuHL1SP_IuFJcpccg`y@hJ{uLz; zN^vb)wmJsccL+{@5L2pqHOQ{mg?_Z`23q>K#=OY3bJoC0D$smK-T=+(q770Q>7UhJ5W6!j6PO1?3ugZof2N#F`1bbyFVF{$4qc_UNt2X zTDKHp`~Q`#6@$Y~Mo6!MizEuf`jkSYBwOos6~g-4zy1lUNcl`v_AN}oDt;dKJZN^G z`A<(>ZgySxdJxrwXH|p1nuaN2byZjt*1$A7c+D2sd}xQk1%jy(#u}>#PKakdI`>cM z$F1FdaDW7?`BsIl^@B)^c_&Uj1p?*t2|$L-lhs_y*!9uljNF<(2=vQfrE^bzk8ytd z3{ALKSCv4}8IB7UPz$ig>g$Yu2xKQG5ro-=Vbm>SEAHbv^^tZYU6P-e#fbQIg?f<( z*5HM5a5pNpW#-l*zhELNOCmzpxMaSQPQV@V0we?`VNe(yRTJ{J{rDP|UhOhw93lRRK1qi-tfKB7jiiw6$vbys6)=-zp|rn#v05(}>pAoeh zQi@-eAn0KZ1(A(!;X6gCj&NZ-cKRT%1HN2?-~e-!;KCDK{wj>)m`iOM}v_>raWAg z9c7C!6(^7@ z(+%aEp~OTT5AUJ{O5p}B(MgrxVu{tue?&M!j*VAqH@!ttxp|17IXHya6gD7-i2f~|NrrU;_sN&-s z!zZ{RSd^iE1n|IbxJf+7D!x3G=kv;5LQL-cm{*^vj%J10=QVq_>&jzo{%v?sO_|&( z!7iAIish&u$#gMdzi6-BxnOWUJ&o@2&86Oh7?O6{ zkNZH0EU-s=VuAEU&Y(Wu_N!Dg&*z`;VIYu=)zwLJ_d88YRg39_$#4Q!mI&1cvI24* zR7}7V1wddc1h^ej(Uiw9UlO{DdGhbcx(XXywgv~bux;ojr>1p!&^hcY=s;Cr;E5_Q z8EV#Z^BJ3}!|W-m%@3hs3;4cZWX7hRsWW8RA1JzS2*7<_28w>$^hFk<2ya84^2D6p z>yU_R4a#XfpAV&eV-_6Yz5d-4W*BwhLK{Rf0`BZ13j^}OHsSA=CMei>Z(go(E2^|y zuNg=Y#ag15W+0q~&StnOgd8a`u_>U~&hJQMJ6nUcP`b`&P3?S~hI7I_D*76pf^-Z7 z%A5Zb8Bsah(RA+Za25}#6+*{_n=BtQ(N-Izwe6;U*aw_SkM!Xz)ncA(ceo@zvd}?9 zrf}@>6IcgstXeS7$i&$WXcB!~N2L&bVAg~X26tp(tsr?}U` z)4Hg4n(Vc$L6T}q8qh{<^uae^ri(Xr#k*Tr&SAgUzh22S;iKGyLS-T~bfqZM2<1oN z3Lyk2Bj)q1VJmm@wa?lca36>ZvYCl<>V9e)tL<&wLv4)q-#M8J>adI_b0M#&c6kgt zdNw^Nu4gXxqbYEh9!61a3oi>#YWZG}JDuvlgkD1oj;yZN%!%;N%ea*0tMpGD51eYju0)RiIKM0HTJlFpT?NF5DI z5S^DGx73osXN6<-pWH5g>lbu5?;GS&HIp0TK>SR zMPs8uzM`oDk;SU`rWZ=lr}v>8^5)-vM{eg?@8zUDy(xg;hpbc?zq2S ziqsd5jyy9df%ly+L<_|P%2d!NC zR)lr03D4NCPlp6UsY_*7`A6`Mw{UN^eojCX8wl5GPsP8@Q|i5eo!$>xf?Vui`q#Ta zUgu?C8~S~K3rK|SV0B$=h3ymR(_%S~=3g{a=snxWo3cOm{NzgO@=9wQ)6(4pUKMH^ zN3&@jrfL{FdGCJC#z`WG)`>R318nSyr6csejIcZ&lw;2u1ylD!Tl?5RPKE6qO@mD= ze{|=d`*E8SchGC{SApyns_{&ujauwske`R6mz5NKI7_xha4`ZraHzD{Lw7gR_odZ$ z!hesSyIhtpdAiqA?c&P#uhE4$%m#rG+$;p@O=9ZuZ^LBJrq4i&>NNCnF>|0yZyQjT za4v-0m@9TR;1Ywz1YTq}L7`;O1|9ig=DYgMxwaj+Vi*rR4#b`m2AZQ&V^`pnt#f@? z_a^|oq47<;Bp-#6!FC*aIaR#41LJe)6dBhzxh)A_FTJzZbK5PecYl7PX}v--+r>5d z?%zBW=6ddUCN-&NZipf?ye}9K0UoQ*ow+%F8O@OgK2zP|knfz$I8-Ni5L}XTzrzE{ z!S%SaNO@z_*fKPss`#!0gY!iadrakf#lE2e&M%_Zu<}iO1^2l9;KEwGW*7DWR#(kF zn4EyTK@_1&o6Tu9ZsY=Dn3tNtEny50$o+qUGLFh>Ql3ac`4KT~Y{fLnz~3`*PRs_FQS&LXbDaIFFX~X=HCk6D#fP zC~Oaz{!4Hgnn5(u)&*!rYeF2fMRzV(GBk}m-hs1}tQ z05^H9+yo8({++v4NFv)NFdFi_fHD4roFDFzA$#yWfEorsR;fOIy&U{X z+6^1iIM7+`{i3!gKSF|23)9i$;U!6q65p@y>w4gy)l0W?Lx?zj<>SZ5VPP-W8e*{u zI^!bNjpHdfxa`> z0-vGr=Tomj9G;2Xsw`P|u|VMAb_Fzx;fcq}Dmv!*_d5AZ*Y}LnR6N4*A9dD0 z+SXXU#FL|iT2Lx-XTDTX!YA)Y^2(N&&_od5-SOnhFT#zoNW^SFFGd&W6TT(z-xjX8 zBRh70texe;jv8%7fVpJ_KA3Dv5k4DZu~HW15hug` z{}qyp*>I1v)orOPRGL06jdl-EMsPSs5RX2W1InkK`M&08_I=hqNx)B9L-!3M9D8BV zvBCXW&hR6siI;T@YoqA&o4?D&giBfjnK?rjU*(H=YPf_0#P?_5Lubbu61tSltD+}+ z!{{fsdMd$|3fAh+q~ zjIXm0%Bqnz!FwkP!|F+xeqPusRG1A``o?E^ z0h(+oXI6Sh5zYWEU>-}7eUVkY_1R4e=v(>kg>wCat}jzQ_h7hTsVORB5g3YH3PU^1 zDL4H+`;juBm-_!VMbRk9tfn6RV-@^%Xs2wPh5&I-^o?E|$mRaAC!#a&d74wo6eH!Y z_V5V4{N^ywgh8EzJOQPUv%F0`cnR5(P2v@K5% zJgaOai4pxN$&Il>-}T+U327noJxcPBi^eMS(bY{VPp)J0Q?hco!PaI*4sFR%5AMBB zYmhMw-z6OyqEjZ?TS@C&#qINMolOpV#nP39%N^lANx)866ZFxPjRc3~@uQ3=$&LH# z7bdF*lxhg!(iDlYJX>M)k`RqdH07_C-TYuP-y;0&7GyFz5?Zy==yPac?-G%wkEte$ zpF3$q?S&qpDCq9Fhhay91i;(Hz9RuSmnW268Ua1|7#(bjwEk&=j+&#&MKNH{xhDot zgNKP!(FM|u3(vObBo61DJF{LLRLw@tA;w~{Iqfm*Ew2CKgej~~e&K|FRk_%h?s>Op z8Tkcq3sGki<>#D(ML7rzbcff>Gn_!i7v&AQ31@l`*G%L8qasY8#TZUIq^Vq}SQP@8 zeauQ!63EfMe0CM=r?sPY%KuqXAi z3oxP!-dI(FfC`KZfM`&R*?RE^`eNA5*Y@Kt%43Ry!W>dmy1RUMJm&&BjjhX<*{HYe zE&J`BkJ()*oU_^|{&%xE7~WsVmi3&B7mw3eE&1{p9s;b0*>Z3XHDa8`KBh%F{aZfp z`Q?GpYbLxfuLATNT}KJY11Espg9n%Im;PQ_ZWV-bDQKaOFH2VrHjrnT&lH-IYcNM# z@o=vB3nkgEoV4W5CNh2aQH0nMck=%SpC|&UI6jafz8NM$s#E7O%C6G zL-IhiGA9-k1yU#@JZDyfP@83mLF&AfZhpdyhNy439v;D*uXAwnEWEM*zSfre2N@8n z%?bQ|w}EvW+y5#RJ#m8hIV&Yb7TZ>Y{dOms>L#PA7WpM!;G@YwK2Etl z(FZBn5>|CWz-A{9C^C>oTHOn4zzf*+fr~7H$$|nh7&%L%!Zn5TgF1}=>#E;wVVH<* zmIq568O;ER2r+vGZ2*fK%X9DM`@!9Xk|#ImN%@r+V%6S=Uz`(eB5ZhCG7BERqFw1# zNF01KxTQA_`?B)!J<^}cK`PgP6FT57)b=J9QFp>lMf{&sP#clanJby8K%~p7CY~=m zeu13R1EJ-ZC2J&kf2HG|;UhylX&X2^dbWB^*A93EG;}W=zXfK6Q~urvh|K#7>q|6= z5jT_W?uGX9n@a_OepXh#He@OIK&Y^XO=YZWlWZweL-{fBPl4`rXP)oK7Nld_{1~(H zeCM|p*V}+q8ehhhDh^G(m#KXn+Qyf$ZkOVEi2kMyOfN*- zCMs^2M(FD|wTs#_IVM&u4=G|Bbf%<@iIS zSJaG0$;7v8FYcONrt)|8$V&9;ac9q6TE!uRz+DbN%Gd=h+i=kZ3fH-)OW2ZWdm@3! z>zo!XW}_IK><)Wu{=29b3rx2B|^Je81M>PRgNV3!N*0TB0g0CV(h4sp0Sof zu)Abo*YiJVmCh3^ZH9s;CJ^+4m&GZZ*Bygf77;0)r5jB!L~xH26dURSo`k7Wg!pYx zk|`x#xDg;6hfWJaZPxe8>|q?rjBhg{^gUGbTB`dT`4ZH>|z zwU;?}0_U5@bCd3__lrhj%s)JZxp3a+9cP@D zM*fGJSLgs^OLwAb^}{#{fZz5t3gS> zFsTpd>6)p_p1Fk(wRh!_zH=vv2%NTu-@{S*tS6Tk$}+;u_m{RmksI?pOjn<(JfEV( zUD6DM3H<~w^^?yh|Nmhx0U>{obgm!3bC;>6Ee+0YEaNytLN0Sl884MTqe@P^yT(e) z7hZUpncRow!xmS1fsIU^1b{1Q7I7KJ?wq*O92cHG6ZN-!*0$xGBVJEhUTV=`=S~Bl z`QgFczz9yV(gdWbdb$CZ!AUWIW{zX2?|__wx%VX)I@{+jK%yWTbuEuqHo5^+1qtyK z<#siT)ho@O1^BW^w(T*ca4V2k4SWI>PKyVEXNa5aqU>VrP7rT2?*~j5QQzbK!WO@i zrZ(Y-A)xvF3rvBdx;X}4XJ(Sc{=9$(2#Zm4PB?RPr!%65Wx8jB-=u8|+ApmV1Spu@ zUdWq;DohY6G%HHSNKD^cpJ8Nw-3#zF04>z36mJsTno>SqA5a+^wOy4N zR#`wn=1~ot??NUY-+Ilv@Nk-U2KV2cASeQRcIEd7_AL?+^uX$|Le&o@WP1@Hm*trv z_d;4zf4zQcFKh|7hGBmwcmd}W+T7N1x4x#1K995Oua|=cF7UdwdTZPPc|eCuH9*;B z3g)7lAO6XHdweO#3odg6?pEW$maPDz*&nHb!W_{iYN~Q+9SKwQ4byd_6DU@gFJ{?) zIInCU*N|h#9iJYbSGeJohsyaN_=WkeT}?sM(ZpSUw*fCjJi3TiywBkz>P%+B_rgkJ zhN~{TDD@KcWMo!iQnC%O&Qwchx}+Z9`g0BCSk^H(fORW9%PQn4ZO6rlwdXJp=Q)8l z+tIXbf4936kRd5cIn!-!=_?uOBLPps8Mv>YgM|`OW}C?6>!Cyaj@Ej(3$thhh_61Q z?ZfructDH@+Ncb7NYGLK`jG5HE%CmUhFZTXQyJa?H#g47G!?DIZ~xVlZe~Z8JPPqW z;@&Wmc?V~&D6~LT=eYA#6qdM=2|x9(#Yk^_xfk??x6TGT_bDiDrU)lLhe;ThLWZa_ zn4>enx6;T17qJMYW;@+m@NI8Va(ZjNuIl_3cB%NwRy00z^Y_j0UMPwv3k+u=l5fy0 ztLz+k{np6NrFjeHo!QRX3fz=MB>^}8Tz+m-^Myv@GI%r8$URBoSQI0zff4?jTqCmvY%xO6 z{sfc@z!qnOuBPrthA1`iN4y<8sNvbTs`G8P#onF24LmUfzKS7SK(Pepp_wP9Mjukb zWBO(x(f0U>ur7`6Ohx{;@yZ{9AHB>Zx}>gCP&yiZA13F#JmyU3`QLLTTOgh!bmC5; zedYr3ABaBgu$m~oU!rz9a8a!4s@V55yLz#}lgu08=SOD16Dqyuupyfno56ylPVo>n z{g_w>W@3}$`Q$a~#CEbYP^tio;-E?hbdk@J|KyHEpSTK@*!rf1JEF}^%w|4$1O&#a zXC@ol(xb1zDQIqWCB>98+gOi3`00o%fR_tIhQAMG{O=5!A|R_|zDM5WG9#K)%-CLG z+~5j);C~d*mX*_RO|Cubl7h zIyc@`A=j1(&@V4tJ1r7gSl`{qo%hAw`ZHx(dtDD`) zErNvE=aDjznBCxsf2acPJ3|kB{A=Gz+lb8ErKH{S2$1(Mjn1d)(`x2@AUrEzElb$v zjMuVv1xEIOzLx+O$mtk>DcqxK|Us|}E+o^00@VBKTx(`Tul4C&Tb(2+_ogpVjviIu95?LX(jj2ADr=OTdL}ta0*otsMfFRj6x*_u?hC#9) zC<~r1Ewo`bJYT^Uu0a#(3Zng@MUilz@V|cr!Q-158e+Lx{H7i7I>X-SJYME3zgZLb z$-Y*6q3c3O#f^CjP0tH#EaTiyWSnuGwo0F1^m>f#MPm5qb>OAjfXuT4xvvk}`-onC zNlu>)tEbVZJYPN4u-EaVHi9W=<-wuq0m`Vaa)3D60YaO@Zb%6Y6kcTLbotZzZ&0b9 zhc=W4-4~+y*(J>NOhm_}hGEqN0ZC0H(L9N;{Jq%z2l8^tXwMW^Thu|+Fn;GBJj0I5hbYmbZd}G2~p>`C3xz%B_qyRm+ zwLLQzNM16TH|7QO0>7kt@jY-29E7nx;}Q<-kzU}rVm0i&=P~AAB9nN(4HbkF?8?HF z(GL?-uE1A?)>ygAxP@xfZ=>E2Q4=^1`-wA7K`!9_xT+ku{bdjOV=@pkP`y@#FnT|; zpf=`OgW$i{x{F|^%*Cl3bmVHz1={pdKPTN%BN<^>!dD8&{$NVKSep(yfhUjJmvc@- zYLzvYDw?IZ%K_`(C9vgFJI;XlyUf^?`eq?SytiU{-v+(7@WoBJ5fn-VdV04U@KSpE zDV@ZrB@HwrCy3NACC9{lpli6Q2x;xpL|Jz6KXMFeKO?Tg&61?hQyKO(ir|K3=_%OM?LOK)Xe%8umYS4i`G1^$<%#MOiD_tMd< z*p$)Ol|ta2IKpY96oLtS{=F-!@|CN^0EjcFLXUeDIn=07N^sPKLk3?qiyRimv5^i~ zpn@v+NxkDg!l?lR4#UpJQ+5JRR6Ms6+qHI_O$xru`(8r)v?>&*Ya=$X4d6dN+NQis z;&rg3=%t{{&+ zcrYK8VoF^^N>FiUgzBYRK8^<+VFFxU++=}c%!1Ld6el!sOxQbRIQBf*5Oewt4{(JQ znYSZtLg0h8#G5>@Yn|fe6VwL;D54bAZ<)=`e(RpP>gTM+Hr_7OozXmeq|HY_A9#~C zqy70iiubuDV?cCY;pNXMG2%>+0%n?5GDG*h0hEYm-2-l*fjxk45%^3sQZa=ZcEje1 zh036|Ti0hFiPtwRaEo0Ul!~5#h?69iM^)_fYSz+hBB!4C4R05b*xQ?7FIr++A`pp9 zB}Zfg(L$-rY}KpCRBiWgMqbn0qf3A)NS+Kp8-YOUGc6*Ng@Y@G_}uNqTZphK3*)#` z9H=P5D2l*V%~?s%g&hRZ4w7m(e@*~5#P(v$c-(8c+}owgqiy%U%XvP{!a6u%G7Oc3 z-NV12NO?d~U&-~=t`+fw33ix_pJ`RRa%3aT3!!p}p^Es|O$mL)A1kR_wCR#ukL|$7 z48IVf2Ugb-8WEs}IDp~I1^`0GQ0}#o+PG$${!?@BH>5mWIg0$w())Qi7YMr~TGi03 z{zSH2!fVN3vmkg{=rw|>D#vucnj0&};Bl-Pc`l}DD3bfuxO8Ec==Mx>?62r9G+&W}AAY?9;B0h^_#?DO!$#ZYm%l8A zmfTq!qV$VDAgd0z02Bkz3DsJ+SC2s=+BPp1joQCr4ibpLJ`T3g%`&~IS@$4Wg=*C4 zfSo3L!ie&;H)I9a8M(*$*GMs9Z+HP=;Bi;7GOFJQiGcb{2tzbX|FjWEio*;<20}I> zkhAK|IYj&%C$A8;a#Chk0LGl_i=#txOQ_|!zq(yZ{fkYpP||5(prTcK-AhOVuGWbs z_WZWvxuaV5ZPUY@pe_zV8}M4=Xxrh3FJ;=kq$Ge_{=nezop3?@`NVT$nmvaCsE*qr zeocW_mM^YRJx~%Y9wQY}MmvW;d_Js{u{E{XcBHweYT>pzfMxiUfM$IJXMo!@A?6~_ znBMvin=g5vx}~8h!YTzl7lnye-nxNpjl<6Gjp)!eo6~qIJ6?n`PeZ!9J0@{@l|EgpS76kT{iR;kl{3npunA>xT}$Ij?0VOAe=hHcR=m+{2E@4|;EZ5eT*of9^lNXiaM^lo)ncwB#&=?JYL64o;tIUg&uwI3Dcvz+3s|M zr_XZkWc6vvfG%;n2+=Ptf@2&G9!QU&{3{mDUOK~e@vlV|7!&nMx$h^HP1Gj#j+)Hh zIi3txCkV2@OXBa+!gnG=Nb|K?dQj0~SIt%BT6V%&mk-&U$>ZIxkn;+GI4TKcys|D*sy3r*XtdT${Vi#3yDaE$viao7 zqC?=-HWW8~!MJJZjY^Z5)KJ_2uitWhSePlACKSCk2$Z$DZ+)t+1d{ekr3M=^+~(== zJpXsKhy5l-6Mv4glhYeOT!Y=(#`!^z{FW=RaC!NA4Iyzc{$6340k|+&Hf2ceUBBN) z?3x(S$y+JJCPOD(wk?}@8D38Pj*DFFCwp`?84~2+SU%ZMur3hgh17u7Zm@w_lNOpR zHKv^gOw4ed?F4?m2)HF*P9DIq*`NDyHhAG#o|`GGtd86r^)KQVO_!FQcUJ`4%K>Yb zj7NA3ar?-*=Lz$cmE({I%;6-!4AsI444El6_5tOdGNM z=9eu|sjr8QXsUb>yt~wC58vAhJs+Ub(`T~#{zQM8hx#5bH@E!umd?duJJ3#spCoQu0``M)#swFoCS@(~QrR{RUt0>9IlM=8pb zPA2C7x{&Oui#U_>h;{P1p*gS-QDQ4X-|oA^X^tsJ=%ObJp+6qSt!v7AetV(T=^lHX z1Wes{iE$Cwzsd+S!!SM_WavW{)TYeP#@y=z(7(dt{M*G$0V(0jShOo9Ir>p^jWt{a!iv1ikFQ(krLqNlM(cAg3;2X=NIiVaz=x z{?-16i#MB+*8_p7b^CF{>xd6Z%YGz1uQhdiJ}<*E#1Vx9yMz{KBF%$QyG)(rSY7}R zdou*5)-a~YG||?ezPgg%sT{R9x2d!6ZB}Wqoi1KJ;}CPXC=9o3F6D`Vk>t(&a7oBU zFR%p|+~!lviZg1jMyz$15=P52a-G( z^692na4ygwWxm_MJb;w9#8>aEOy*Y?4;-|2XjB&dU2=t51-zstQCGu=#r51cAB8*$ZbRT(4oDz83|`kNWD;S*!i1Rx}=?K9^#V5Y9Zq=)MfAVZ?=d0>2t0g_gY>* z?c-!hMez_G9z*v+(c(J(UbM2lZZ#yW=#QseZb1N+>_43k7 z>?z2&gONQ+xl3_U>hnY7R9GfZM-nur|K#H98lP z$^*dJj8B=kjGrFVvXl)eDhqwjld-`0q+yQc_!R_wAv>XfgaF>@tq00w7_-Iek-1cI zsfQ$nsQ0#&Ow^lZ{*<=5EXKLJ1~>!(EFXv*K>jL`zxQ20z5D7;lB7^izG`GCoxcc* z*6}|p6K?Lv`#F>61u~uOHyvxaLW8=|v~VR*wyONaXyx_U5nYrk#>_%JOAajMPS5%L zIqNoX`m^cvV&=#95}$UqoX?TeBi_$jcQm8t!!u5V#O6KMHb?+0wkkM&c%Q@ zD$%W!^;k?#%G$*0QQ9@dDz{*9)yStagP&tjR{P%_P2N5k*}{IkIAZr$4tSvhrcako zS!Pn-!}4GUN_y3&5}29l(x$^$NI`6|e|pD{85St0_%GaHUe|xpiD``n1J^)R-Y7F? zU>$VEbO$(+Fw|9HaJmXJ=FAF;TAUK~jE33_Xt2hAZz#82k3oj!s$tBwGKTmba>D`r zGdFieJ(M8!KDrD5%N2FHjqMK``<$E<)(xYOjJE4t&a?|V{k=IIubO2Q+*974YDINP zh6n36#+|05&tV8u%U3Rv1z{3I12Ad_j1xV4SKeO>PKqaqL6t%?2)(>#-{?i) z>7BA%Q!AOe;8TJJR&^_{_XO$B7S{EY#q+(#Q5Pm({qZaz^XA(lR8 z&J6>}QbYAuHMkn~3Ilm6i5rgI(kgj>?dP|+bvyZOVIhh4Bmwf?mQV+6V@MZ*8_JV^ z>UjPD_P%JTfF4K%6Ms2NxXJ^U0>TFxaAxdx{=X}^GK;8`ZXtbm^xwG>w(jZV# zvq8+2+76&A&mAVw4&`e5|+L~tj4I;wNz4@`-X18={pStqWHeljVGEt z$DTf5dAO;V7HX;eYVkim6vJ>1+$*RYb$5gHE?&aP%HemBk0aI`c?m=`b~_)=o0t4~ zEn5?cie8;}4H!;DB(uibhMpp4r=q*ITNAQfhrX~Op4Xjzb%yq(#dWF47$hKhIqWG( z8S`&?cJ)iHTO4Tw=u6>EUSG2lIeaDAg0jkpZW225%D#W|yo-#Athv8TgTEH+z+l-S>zW@DFqD|KD`D0;=%ln`4&Y*TI$vh3 z1jApRtoXWyes?X|YT!zIT8!z`=UeEe;@-`>7@;cIyMA90_sV{^b6#b51eo@JaCT5$;oR7$~HQcY{;~d*j2p>$(e4(zX*|6?YgOSv*-xSc)I-}NM@j&Gf%{bxSRgJLTDY(}S19bb=f0yvs9 zkm#>4T6_cOUGIj&_bxp9G|*}-G5E#YcNwcCYo=zWh7|&q zzbY&4;~*avePRb3h9&x-y`{`%f20k@%frZpDZz+`MObdx-3S9fZ6ptk6&9iNv5xyv zhAdMKsiVK6X_I@L(9bSwdr&=9ekYr7jfbB{XQmu-KjE&}=)QsM_kQA|p4H=@R7`vt z9j){B(Vkv;_)VQT1^@bp0=EvC!tE{GFBAaIoHDM0(dBOZdVW{oU zt%3e7Qb7ygh?jWxG=-7bUpc$&o6k;S+Q8wHC=EGy>t}KX;C<@$Rp{z*s55P@0y&H> z{i;5|x0s9%JIxDYH0_(Yv+H9`Q-gi{wT}+F{oZ|gkbdb{;fsw!vWUp0UXe!f5xR)8 z{-Tx@8;sg!TSM)mZrfyBc>U4K0}t9`ukr8Xb7Te?)?Dw0DtD8eowRnutKZ7G}Du|F{;OYAeYrm?Zjpkhh=gX_Q z48f8gJnPkXWHk4(wB|E=vOcD@54d!W9#y38G)YlgZfe~|RQuVp4KPo#bB0Pi+wNl- z`#1y5WhBXE*M6bK*eF8!51Z;m-caQxDQ}X?cTR)Vx>}IFSse4*bnm?Me3LN{LborB zc|15uF3!*F_g!!DGa-)=*n9XH(>m&Q!ERUP=dZwqtR~-1%){C{Dp3VgI6(5ZlNY>O z?O_2DZJ;LG>bxtpOL@?4__m8f`utByllJ;&xcW%1KZ!P9e-9MPW$nn)dv;y_BQxDM z!?Ds|Fd~{9Ef!-mrAYFgD44yYteVKYhv<+c;%2T>&38a0a#>i<-Ep>ixTg%ydkeQr zxjL;g`B;AuP5zR24a*2DT~~P2*y|1^wc6CoAxWE4sZZ8siV!!RuiSurFlD{o6}1uO zLB^B9_WMsiq+>v0k;W*Z3+yfBFXt4b;6@&vn6ekYS(;ebRb)bHQW4*HJ}I_8esuUR zed$X?L1`crnbPfHSkYfxpsupUp-&;?#c@Si#Un}1ZR3b2d3qGX-v1|M10cD}xOVOS zwTcfr>9;|jtyZI`{d=?Si~QRoEYs|GPUs1neN#8+{563k+ze+-j6{W>A+1)xZ6+MR z{T`~j&MY3#W@^cE7~;A|&Wfdg;s<_d(D8VS?B(0}s zTF|J=I!?gpKSMrpW>>(UGFZk+j@m~rT?~2k8RVL|?-SkN??>7R-(K>GrTm?b4w#RT z2X-WotLFag{qiY42&OjJe@cQ0C?6Hu!YL|)v3TsySL-U^OBtUJ(h@! zKSn{-u0@B~iM#p$vVNV({21H%zF0Zw@cqM`X8JlMJF;y*p;`AR|)T@=bxORE_ zS9*qIjCZ8FZ0jwcAy^Z9063!XY8m7|oA!5)g?>@I^l)vVm2Wn1wPnU0%}{*pCkxkA z3DhO}U+p<=2{xofJE=Ab@2Y^2z4CyDLGJ@ZFj$V8>~gS)GOsU8v)w-D{^RrOttU4` z^BT3&KZWIx&ERHSN{?T`V#BE0{Sl40>|KdUjJ+2_j|GK5S$ke3wEtX_KbeB~qf`5n zeUygl)NXq0(K+VXJRlfJ{&jOJw4f7Uw7*x}Ks!T4*;e1YIRPhg3tnBR%@VJ=ga&$W zBH35XL$%l}#ELPgRh7ZWg)PuHoE)Ofa8&tj#OgNxQ+VX9(cx2LTNq_Tz{JxRs>PU0K zl=f3j7Uuws^BQ35p(M+|i$F?><@%|>b4y>=6_hp38Q*v!k1uGbOJWpo>|nR4{snvD z-8KT_q&NJ?olz3mmH--J?f-dYHWgL354`$kp?b>t$^l~Dc_9D!*OLe!TssBZ!6k1OtR} zaa$H>SU{-}8_A;j>*2j3&s6cQZxuFVFyBUGy**&w9PB(*^fmPzN)vdy^dqeKkRgt& z4_~IhcSm#Ns|?!s^uJ&#T^c*sXnuJ(!X`)HCb-}ZPIv%_%A(_Btqj6({JMGA$F=&IsX>GgJrdGpY^<#}Wp71OOixO#y5p|IF) z@|a;=lFUMD=--XEyF6fzWZ}eH=Jlaxoj^Ax%lf$8kBPsQI5HZceJVxsbbB2jEh$Dx z^;_*GyoJbAe)r!Y^bR3&3LMpo-1zX|>TLP-S^TCX?F`^%phoOT4N3m~Hs`0>l990w zD^D}9fCKua+e5}Q()wP-62)?My8sszH5AVCy7V8`Qt_cbc=5{Ml;kk4VipfTbIK7Z zJAER;nF0-<(ogSF|B1vWJVM@9RgmxUH$oDOtUu$>$ii&M|Byc#U5gx`w`5_jML^VB zQ7p7a&MbsiEUIaYZ5$7BUdjF{{%v!dQ~b$C>-)md4XLp;dOsA#%oSk&CwX!}7_>(; zFa=))LZ(SLvAS>xxc5`Dk7R3A+*hZ_H~7Wb02AX@OwK^p&DRsVttx8h$DkSib{TS% zcIHpE$2EY(Bne}c;j^jhuuo8_6`JyA!kP5&J4#8e&kJrSY_O5PRJgR+7YeE;Oj^k`b!{f$Y-ne4tpdbWjb(azrenqTttS#3|vI-x1 zXfukVDV6y%f1OP@*h|6@!Lb@J}tf|W??j)#pT;U7}L zyMx}>%1+;$Ps=vH9o@D=YE$RWZsXsd-$y-`Ug0lyi8
TU!9|1ecf2_OO&4m%_I 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�X-kIT4?Y>@PQa0s1$IKBsh1S)CQ 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 literal 0 HcmV?d00001 diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/AppHelpFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/AppHelpFragment.java deleted file mode 100644 index 6799f6c..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/AppHelpFragment.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.Dialog; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import androidx.appcompat.app.AlertDialog; - -public class AppHelpFragment extends DialogFragment { - private static final String ARG_TEXT = "ARG_TEXT"; - private static final String ARG_VERSION = "ARG_VERSION"; - - public static AppHelpFragment getInstance(final int aboutResId, final boolean appendVersion) { - final AppHelpFragment fragment = new AppHelpFragment(); - - final Bundle args = new Bundle(); - args.putInt(ARG_TEXT, aboutResId); - args.putBoolean(ARG_VERSION, appendVersion); - fragment.setArguments(args); - - return fragment; - } - - public static AppHelpFragment getInstance(final int aboutResId) { - final AppHelpFragment fragment = new AppHelpFragment(); - - final Bundle args = new Bundle(); - args.putInt(ARG_TEXT, aboutResId); - args.putBoolean(ARG_VERSION, false); - fragment.setArguments(args); - - return fragment; - } - - @Override - @NonNull - public Dialog onCreateDialog(final Bundle savedInstanceState) { - final Bundle args = getArguments(); - final StringBuilder text = new StringBuilder(getString(args.getInt(ARG_TEXT))); - - final boolean appendVersion = args.getBoolean(ARG_VERSION); - if (appendVersion) { - try { - final String version = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0).versionName; - text.append(getString(R.string.about_version, version)); - } catch (final NameNotFoundException e) { - // do nothing - } - } - return new AlertDialog.Builder(getActivity()).setTitle(R.string.about_title).setMessage(text) - .setPositiveButton(R.string.ok, null).create(); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/FeaturesActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/FeaturesActivity.java deleted file mode 100644 index 86709ee..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/FeaturesActivity.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * 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.content.ActivityNotFoundException; -import android.content.ComponentName; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.content.res.Configuration; -import android.graphics.Color; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; -import android.net.Uri; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.core.view.GravityCompat; -import androidx.drawerlayout.widget.DrawerLayout; -import androidx.appcompat.app.ActionBarDrawerToggle; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.GridView; -import android.widget.ImageView; -import android.widget.TextView; -import android.widget.Toast; - -import java.util.List; - -import no.nordicsemi.android.nrftoolbox.adapter.AppAdapter; -import no.nordicsemi.android.nrftoolbox.hrs.HRSActivity; - -public class FeaturesActivity extends AppCompatActivity { - private static final String NRF_CONNECT_CATEGORY = "no.nordicsemi.android.nrftoolbox.LAUNCHER"; - private static final String UTILS_CATEGORY = "no.nordicsemi.android.nrftoolbox.UTILS"; - private static final String NRF_CONNECT_PACKAGE = "no.nordicsemi.android.mcp"; - private static final String NRF_CONNECT_CLASS = NRF_CONNECT_PACKAGE + ".DeviceListActivity"; - private static final String NRF_CONNECT_MARKET_URI = "market://details?id=no.nordicsemi.android.mcp"; - - // Extras that can be passed from NFC (see SplashscreenActivity) - public static final String EXTRA_APP = "application/vnd.no.nordicsemi.type.app"; - public static final String EXTRA_ADDRESS = "application/vnd.no.nordicsemi.type.address"; - - private DrawerLayout mDrawerLayout; - private ActionBarDrawerToggle mDrawerToggle; - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_features); - - final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); - setSupportActionBar(toolbar); - - // ensure that Bluetooth exists - if (!ensureBLEExists()) - finish(); - - final DrawerLayout drawer = mDrawerLayout = findViewById(R.id.drawer_layout); - drawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); - - // Set the drawer toggle as the DrawerListener - mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) { - @Override - public void onDrawerSlide(final View drawerView, final float slideOffset) { - // Disable the Hamburger icon animation - super.onDrawerSlide(drawerView, 0); - } - }; - drawer.addDrawerListener(mDrawerToggle); - - // setup plug-ins in the drawer - //setupPluginsInDrawer(drawer.findViewById(R.id.plugin_container)); - - // configure the app grid - final GridView grid = findViewById(R.id.grid); - grid.setAdapter(new AppAdapter(this)); - grid.setEmptyView(findViewById(android.R.id.empty)); - - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - final Intent intent = getIntent(); - if (intent.hasExtra(EXTRA_APP) && intent.hasExtra(EXTRA_ADDRESS)) { - final String app = intent.getStringExtra(EXTRA_APP); - switch (app) { - case "HRM": - final Intent newIntent = new Intent(this, HRSActivity.class); - newIntent.putExtra(EXTRA_ADDRESS, intent.getByteArrayExtra(EXTRA_ADDRESS)); - newIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - startActivity(newIntent); - break; - default: - // other are not supported yet - break; - } - } - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.help, menu); - return true; - } - - @Override - protected void onPostCreate(final Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - // Sync the toggle state after onRestoreInstanceState has occurred. - mDrawerToggle.syncState(); - } - - @Override - public void onConfigurationChanged(@NonNull final Configuration newConfig) { - super.onConfigurationChanged(newConfig); - mDrawerToggle.onConfigurationChanged(newConfig); - } - - @Override - public boolean onOptionsItemSelected(final MenuItem item) { - // Pass the event to ActionBarDrawerToggle, if it returns - // true, then it has handled the app icon touch event - if (mDrawerToggle.onOptionsItemSelected(item)) { - return true; - } - - switch (item.getItemId()) { - case R.id.action_about: - final AppHelpFragment fragment = AppHelpFragment.getInstance(R.string.about_text, true); - fragment.show(getSupportFragmentManager(), null); - break; - } - return true; - } - - /* - private void setupPluginsInDrawer(final ViewGroup container) { - final LayoutInflater inflater = LayoutInflater.from(this); - final PackageManager pm = getPackageManager(); - - // look for nRF Connect - final Intent nrfConnectIntent = new Intent(Intent.ACTION_MAIN); - nrfConnectIntent.addCategory(NRF_CONNECT_CATEGORY); - nrfConnectIntent.setClassName(NRF_CONNECT_PACKAGE, NRF_CONNECT_CLASS); - final ResolveInfo nrfConnectInfo = pm.resolveActivity(nrfConnectIntent, 0); - - // configure link to nRF Connect - final TextView nrfConnectItem = container.findViewById(R.id.link_mcp); - if (nrfConnectInfo == null) { - nrfConnectItem.setTextColor(Color.GRAY); - final ColorMatrix grayscale = new ColorMatrix(); - grayscale.setSaturation(0.0f); - nrfConnectItem.getCompoundDrawables()[0].mutate().setColorFilter(new ColorMatrixColorFilter(grayscale)); - } - nrfConnectItem.setOnClickListener(v -> { - Intent action = nrfConnectIntent; - if (nrfConnectInfo == null) - action = new Intent(Intent.ACTION_VIEW, Uri.parse(NRF_CONNECT_MARKET_URI)); - action.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - action.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - startActivity(action); - } catch (final ActivityNotFoundException e) { - Toast.makeText(FeaturesActivity.this, R.string.no_application_play, Toast.LENGTH_SHORT).show(); - } - mDrawerLayout.closeDrawers(); - }); - - // look for other plug-ins - final Intent utilsIntent = new Intent(Intent.ACTION_MAIN); - utilsIntent.addCategory(UTILS_CATEGORY); - - final List appList = pm.queryIntentActivities(utilsIntent, 0); - for (final ResolveInfo info : appList) { - final View item = inflater.inflate(R.layout.drawer_plugin, container, false); - final ImageView icon = item.findViewById(android.R.id.icon); - final TextView label = item.findViewById(android.R.id.text1); - - label.setText(info.loadLabel(pm)); - icon.setImageDrawable(info.loadIcon(pm)); - item.setOnClickListener(v -> { - final Intent intent = new Intent(); - intent.setComponent(new ComponentName(info.activityInfo.packageName, info.activityInfo.name)); - intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - 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 deleted file mode 100644 index 5eaa1e9..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/SplashscreenActivity.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * 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.nfc.NdefMessage; -import android.nfc.NdefRecord; -import android.nfc.NfcAdapter; -import android.os.Bundle; -import android.os.Handler; -import android.os.Parcelable; - -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(() -> { - final Intent newIntent = new Intent(SplashscreenActivity.this, FeaturesActivity.class); - newIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - - // Handle NFC message, if app was opened using NFC AAR record - final Intent intent = getIntent(); - if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { - final Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); - if (rawMsgs != null) { - for (Parcelable rawMsg : rawMsgs) { - final NdefMessage msg = (NdefMessage) rawMsg; - final NdefRecord[] records = msg.getRecords(); - - for (NdefRecord record : records) { - if (record.getTnf() == NdefRecord.TNF_MIME_MEDIA) { - switch (record.toMimeType()) { - case FeaturesActivity.EXTRA_APP: - newIntent.putExtra(FeaturesActivity.EXTRA_APP, new String(record.getPayload())); - break; - case FeaturesActivity.EXTRA_ADDRESS: - newIntent.putExtra(FeaturesActivity.EXTRA_ADDRESS, invertEndianness(record.getPayload())); - break; - } - } - } - } - } - } - startActivity(newIntent); - finish(); - }, DELAY); - } - - @Override - public void onBackPressed() { - // do nothing. Protect from exiting the application when splash screen is shown - } - - /** - * Inverts endianness of the byte array. - * @param bytes input byte array - * @return byte array in opposite order - */ - private byte[] invertEndianness(final byte[] bytes) { - if (bytes == null) - return null; - final int length = bytes.length; - final byte[] result = new byte[length]; - for (int i = 0; i < length; i++) - result[i] = bytes[length - i - 1]; - return result; - } -} 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 deleted file mode 100644 index 8247c6d..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/app/ExpandableListActivity.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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 android.app.Activity; -import android.database.Cursor; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.appcompat.app.AppCompatActivity; -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; - -import java.util.List; -import java.util.Map; - -import no.nordicsemi.android.nrftoolbox.R; - -/** - * 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 AppCompatActivity 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(@NonNull Bundle state) { - ensureList(); - super.onRestoreInstanceState(state); - } - - /** - * Updates the screen state (current list and other views) when the content changes. - * - * @see androidx.appcompat.app.AppCompatActivity#onContentChanged() - */ - @Override - public void onContentChanged() { - super.onContentChanged(); - View emptyView = findViewById(R.id.empty); - mList = 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 deleted file mode 100644 index b38f59e..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMActivity.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.widget.TextView; - -import java.util.Calendar; -import java.util.UUID; - -import no.nordicsemi.android.ble.common.profile.bp.BloodPressureMeasurementCallback; -import no.nordicsemi.android.ble.common.profile.bp.IntermediateCuffPressureCallback; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileActivity; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; - -// TODO The BPMActivity should be rewritten to use the service approach, like other do. -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; - private TextView mBatteryLevelView; - - @Override - protected void onCreateView(final Bundle savedInstanceState) { - setContentView(R.layout.activity_feature_bpm); - setGUI(); - } - - private void setGUI() { - mSystolicView = findViewById(R.id.systolic); - mSystolicUnitView = findViewById(R.id.systolic_unit); - mDiastolicView = findViewById(R.id.diastolic); - mDiastolicUnitView = findViewById(R.id.diastolic_unit); - mMeanAPView = findViewById(R.id.mean_ap); - mMeanAPUnitView = findViewById(R.id.mean_ap_unit); - mPulseView = findViewById(R.id.pulse); - mTimestampView = findViewById(R.id.timestamp); - mBatteryLevelView = findViewById(R.id.battery); - } - - @Override - protected int getLoggerProfileTitle() { - return R.string.bpm_feature_title; - } - - @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 LoggableBleManager initializeManager() { - final BPMManager manager = BPMManager.getBPMManager(getApplicationContext()); - 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); - mBatteryLevelView.setText(R.string.not_available); - } - - @Override - public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) { - // this may notify user or show some views - } - - @Override - public void onDeviceReady(@NonNull final BluetoothDevice device) { - // this may notify user - } - - @Override - public void onDeviceDisconnected(@NonNull final BluetoothDevice device) { - super.onDeviceDisconnected(device); - runOnUiThread(() -> mBatteryLevelView.setText(R.string.not_available)); - } - - @Override - public void onBloodPressureMeasurementReceived(@NonNull final BluetoothDevice device, - final float systolic, final float diastolic, final float meanArterialPressure, final int unit, - @Nullable final Float pulseRate, @Nullable final Integer userID, - @Nullable final BPMStatus status, @Nullable final Calendar calendar) { - runOnUiThread(() -> { - mSystolicView.setText(String.valueOf(systolic)); - mDiastolicView.setText(String.valueOf(diastolic)); - mMeanAPView.setText(String.valueOf(meanArterialPressure)); - if (pulseRate != null) - mPulseView.setText(String.valueOf(pulseRate)); - else - mPulseView.setText(R.string.not_available_value); - if (calendar != null) - mTimestampView.setText(getString(R.string.bpm_timestamp, calendar)); - else - mTimestampView.setText(R.string.not_available); - - mSystolicUnitView.setText(unit == BloodPressureMeasurementCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa); - mDiastolicUnitView.setText(unit == BloodPressureMeasurementCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa); - mMeanAPUnitView.setText(unit == BloodPressureMeasurementCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa); - }); - } - - @Override - public void onIntermediateCuffPressureReceived(@NonNull final BluetoothDevice device, final float cuffPressure, final int unit, - @Nullable final Float pulseRate, @Nullable final Integer userID, - @Nullable final BPMStatus status, @Nullable final Calendar calendar) { - runOnUiThread(() -> { - mSystolicView.setText(String.valueOf(cuffPressure)); - mDiastolicView.setText(R.string.not_available_value); - mMeanAPView.setText(R.string.not_available_value); - if (pulseRate != null) - mPulseView.setText(String.valueOf(pulseRate)); - else - mPulseView.setText(R.string.not_available_value); - if (calendar != null) - mTimestampView.setText(getString(R.string.bpm_timestamp, calendar)); - else - mTimestampView.setText(R.string.not_available); - - mSystolicUnitView.setText(unit == IntermediateCuffPressureCallback.UNIT_mmHg ? R.string.bpm_unit_mmhg : R.string.bpm_unit_kpa); - mDiastolicUnitView.setText(null); - mMeanAPUnitView.setText(null); - }); - } - - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - runOnUiThread(() -> mBatteryLevelView.setText(getString(R.string.battery, batteryLevel))); - } -} 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 deleted file mode 100644 index 55c6458..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManager.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.util.Log; - -import java.util.Calendar; -import java.util.UUID; - -import no.nordicsemi.android.ble.common.callback.bps.BloodPressureMeasurementDataCallback; -import no.nordicsemi.android.ble.common.callback.bps.IntermediateCuffPressureDataCallback; -import no.nordicsemi.android.ble.data.Data; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; -import no.nordicsemi.android.nrftoolbox.parser.BloodPressureMeasurementParser; -import no.nordicsemi.android.nrftoolbox.parser.IntermediateCuffPressureParser; - -@SuppressWarnings({"unused", "WeakerAccess"}) -public class BPMManager extends BatteryManager { - /** Blood Pressure service UUID. */ - public final static UUID BP_SERVICE_UUID = UUID.fromString("00001810-0000-1000-8000-00805f9b34fb"); - /** Blood Pressure Measurement characteristic UUID. */ - private static final UUID BPM_CHARACTERISTIC_UUID = UUID.fromString("00002A35-0000-1000-8000-00805f9b34fb"); - /** Intermediate Cuff Pressure characteristic UUID. */ - private static final UUID ICP_CHARACTERISTIC_UUID = UUID.fromString("00002A36-0000-1000-8000-00805f9b34fb"); - - private BluetoothGattCharacteristic mBPMCharacteristic, mICPCharacteristic; - - private static BPMManager managerInstance = null; - - /** - * Returns the singleton implementation of BPMManager. - */ - public static synchronized BPMManager getBPMManager(final Context context) { - if (managerInstance == null) { - managerInstance = new BPMManager(context); - } - return managerInstance; - } - - private BPMManager(final Context context) { - super(context); - } - - @NonNull - @Override - protected BatteryManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving notification, etc. - */ - private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { - - @Override - protected void initialize() { - super.initialize(); - - setNotificationCallback(mICPCharacteristic) - .with(new IntermediateCuffPressureDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + IntermediateCuffPressureParser.parse(data) + "\" received"); - - // Pass through received data - super.onDataReceived(device, data); - } - - @Override - public void onIntermediateCuffPressureReceived(@NonNull final BluetoothDevice device, - final float cuffPressure, final int unit, - @Nullable final Float pulseRate, @Nullable final Integer userID, - @Nullable final BPMStatus status, @Nullable final Calendar calendar) { - mCallbacks.onIntermediateCuffPressureReceived(device, cuffPressure, unit, pulseRate, userID, status, calendar); - } - - @Override - public void onInvalidDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(Log.WARN, "Invalid ICP data received: " + data); - } - }); - setIndicationCallback(mBPMCharacteristic) - .with(new BloodPressureMeasurementDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + BloodPressureMeasurementParser.parse(data) + "\" received"); - - // Pass through received data - super.onDataReceived(device, data); - } - - @Override - public void onBloodPressureMeasurementReceived(@NonNull final BluetoothDevice device, - final float systolic, final float diastolic, final float meanArterialPressure, - final int unit, @Nullable final Float pulseRate, - @Nullable final Integer userID, @Nullable final BPMStatus status, - @Nullable final Calendar calendar) { - mCallbacks.onBloodPressureMeasurementReceived(device, systolic, diastolic, - meanArterialPressure, unit, pulseRate, userID, status, calendar); - } - - @Override - public void onInvalidDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(Log.WARN, "Invalid BPM data received: " + data); - } - }); - - enableNotifications(mICPCharacteristic) - .fail((device, status) -> log(Log.WARN, - "Intermediate Cuff Pressure characteristic not found")) - .enqueue(); - enableIndications(mBPMCharacteristic).enqueue(); - } - - @Override - protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - final BluetoothGattService service = gatt.getService(BP_SERVICE_UUID); - if (service != null) { - mBPMCharacteristic = service.getCharacteristic(BPM_CHARACTERISTIC_UUID); - mICPCharacteristic = service.getCharacteristic(ICP_CHARACTERISTIC_UUID); - } - return mBPMCharacteristic != null; - } - - @Override - protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { - super.isOptionalServiceSupported(gatt); // ignore the result of this - return mICPCharacteristic != null; - } - - @Override - protected void onDeviceDisconnected() { - mICPCharacteristic = null; - mBPMCharacteristic = 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 deleted file mode 100644 index 75f550b..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/bpm/BPMManagerCallbacks.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 no.nordicsemi.android.ble.common.profile.bp.BloodPressureMeasurementCallback; -import no.nordicsemi.android.ble.common.profile.bp.IntermediateCuffPressureCallback; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; - -interface BPMManagerCallbacks extends BatteryManagerCallbacks, - BloodPressureMeasurementCallback, IntermediateCuffPressureCallback { - -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSActivity.java deleted file mode 100644 index ce6864d..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSActivity.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (c) 2016, 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.cgms; - -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import android.util.SparseArray; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.ListView; -import android.widget.PopupMenu; -import android.widget.TextView; - -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.proximity.ProximityService; - -public class CGMSActivity extends BleProfileServiceReadyActivity implements PopupMenu.OnMenuItemClickListener { - private View mControlPanelStd; - private View mControlPanelAbort; - private ListView mRecordsListView; - private TextView mBatteryLevelView; - private CGMSRecordsAdapter mCgmsRecordsAdapter; - - private CGMService.CGMSBinder mBinder; - - @Override - protected void onCreateView(Bundle savedInstanceState) { - setContentView(R.layout.activity_feature_cgms); - setGUI(); - } - - @Override - protected void onInitialize(Bundle savedInstanceState) { - LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); - } - - private void setGUI() { - mRecordsListView = findViewById(R.id.list); - mControlPanelStd = findViewById(R.id.cgms_control_std); - mControlPanelAbort = findViewById(R.id.cgms_control_abort); - mBatteryLevelView = findViewById(R.id.battery); - - findViewById(R.id.action_last).setOnClickListener(v -> { - clearRecords(); - if (mBinder != null) { - mBinder.clear(); - mBinder.getLastRecord(); - } - }); - findViewById(R.id.action_all).setOnClickListener(v -> { - clearRecords(); - if (mBinder != null) { - clearRecords(); - mBinder.getAllRecords(); - } - }); - findViewById(R.id.action_abort).setOnClickListener(v -> { - if (mBinder != null) { - mBinder.abort(); - } - }); - - // create popup menu attached to the button More - findViewById(R.id.action_more).setOnClickListener(v -> { - PopupMenu menu = new PopupMenu(CGMSActivity.this, v); - menu.setOnMenuItemClickListener(CGMSActivity.this); - MenuInflater inflater = menu.getMenuInflater(); - inflater.inflate(R.menu.gls_more, menu.getMenu()); - menu.show(); - }); - } - - private void loadAdapter(SparseArray records) { - mCgmsRecordsAdapter.clear(); - for (int i = 0; i < records.size(); i++) { - mCgmsRecordsAdapter.addItem(records.valueAt(i)); - } - mCgmsRecordsAdapter.notifyDataSetChanged(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); - } - - @Override - protected void onServiceBound(final CGMService.CGMSBinder binder) { - mBinder = binder; - final SparseArray cgmsRecords = binder.getRecords(); - if (cgmsRecords != null && cgmsRecords.size() > 0) { - if (mCgmsRecordsAdapter == null) { - mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this); - mRecordsListView.setAdapter(mCgmsRecordsAdapter); - } - loadAdapter(cgmsRecords); - } - } - - @Override - protected void onServiceUnbound() { - mBinder = null; - } - - @Override - protected Class getServiceClass() { - return CGMService.class; - } - - @Override - protected int getLoggerProfileTitle() { - return R.string.cgms_feature_title; - } - - @Override - protected int getAboutTextId() { - return R.string.cgms_about_text; - } - - @Override - protected int getDefaultDeviceName() { - return R.string.cgms_default_name; - } - - @Override - protected UUID getFilterUUID() { - return CGMSManager.CGMS_UUID; - } - - @Override - public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { - // this may notify user or show some views - } - - private void setOperationInProgress(final boolean progress) { - runOnUiThread(() -> { - // setSupportProgressBarIndeterminateVisibility(progress); - mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE); - mControlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE); - }); - } - - public void onBatteryLevelChanged(final BluetoothDevice device, final int value) { - mBatteryLevelView.setText(getString(R.string.battery, value)); - } - - @Override - public void onDeviceDisconnected(final BluetoothDevice device) { - super.onDeviceDisconnected(device); - setOperationInProgress(false); - mBatteryLevelView.setText(R.string.not_available); - } - - @Override - public void onError(final BluetoothDevice device, final String message, final int errorCode) { - super.onError(device, message, errorCode); - setOperationInProgress(false); - } - - @Override - protected void setDefaultUI() { - clearRecords(); - mBatteryLevelView.setText(R.string.not_available); - } - - @Override - public boolean onMenuItemClick(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case R.id.action_refresh: - if(mBinder != null) - mBinder.refreshRecords(); - break; - case R.id.action_first: - if (mBinder != null) - mBinder.getFirstRecord(); - break; - case R.id.action_clear: - if (mBinder != null) - mBinder.clear(); - break; - case R.id.action_delete_all: - if (mBinder != null) - mBinder.deleteAllRecords(); - break; - } - return true; - } - - private void clearRecords() { - if (mCgmsRecordsAdapter != null) { - mCgmsRecordsAdapter.clear(); - mCgmsRecordsAdapter.notifyDataSetChanged(); - } - } - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(final Context context, final Intent intent) { - final String action = intent.getAction(); - final BluetoothDevice device = intent.getParcelableExtra(ProximityService.EXTRA_DEVICE); - - switch (action) { - case CGMService.BROADCAST_NEW_CGMS_VALUE: { - CGMSRecord cgmsRecord = intent.getExtras().getParcelable(CGMService.EXTRA_CGMS_RECORD); - if (mCgmsRecordsAdapter == null) { - mCgmsRecordsAdapter = new CGMSRecordsAdapter(CGMSActivity.this); - mRecordsListView.setAdapter(mCgmsRecordsAdapter); - } - mCgmsRecordsAdapter.addItem(cgmsRecord); - mCgmsRecordsAdapter.notifyDataSetChanged(); - break; - } - case CGMService.BROADCAST_DATA_SET_CLEAR: - // Update GUI - clearRecords(); - break; - case CGMService.OPERATION_STARTED: - // Update GUI - setOperationInProgress(true); - break; - case CGMService.BROADCAST_BATTERY_LEVEL: - final int batteryLevel = intent.getIntExtra(CGMService.EXTRA_BATTERY_LEVEL, 0); - // Update GUI - onBatteryLevelChanged(device, batteryLevel); - break; - case CGMService.OPERATION_FAILED: - // Update GUI - showToast(R.string.gls_operation_failed); - // breakthrough intended - default: - // Update GUI - setOperationInProgress(false); - } - } - }; - - private static IntentFilter makeIntentFilter() { - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CGMService.BROADCAST_NEW_CGMS_VALUE); - intentFilter.addAction(CGMService.BROADCAST_DATA_SET_CLEAR); - intentFilter.addAction(CGMService.OPERATION_STARTED); - intentFilter.addAction(CGMService.OPERATION_COMPLETED); - intentFilter.addAction(CGMService.OPERATION_SUPPORTED); - intentFilter.addAction(CGMService.OPERATION_NOT_SUPPORTED); - intentFilter.addAction(CGMService.OPERATION_ABORTED); - intentFilter.addAction(CGMService.OPERATION_FAILED); - intentFilter.addAction(CGMService.BROADCAST_BATTERY_LEVEL); - return intentFilter; - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManager.java deleted file mode 100644 index 6588b19..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManager.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Copyright (c) 2016, 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.cgms; - -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.util.Log; -import android.util.SparseArray; - -import java.util.UUID; - -import no.nordicsemi.android.ble.common.callback.RecordAccessControlPointDataCallback; -import no.nordicsemi.android.ble.common.callback.cgm.CGMFeatureDataCallback; -import no.nordicsemi.android.ble.common.callback.cgm.CGMSpecificOpsControlPointDataCallback; -import no.nordicsemi.android.ble.common.callback.cgm.CGMStatusDataCallback; -import no.nordicsemi.android.ble.common.callback.cgm.ContinuousGlucoseMeasurementDataCallback; -import no.nordicsemi.android.ble.common.data.RecordAccessControlPointData; -import no.nordicsemi.android.ble.common.data.cgm.CGMSpecificOpsControlPointData; -import no.nordicsemi.android.ble.data.Data; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; -import no.nordicsemi.android.nrftoolbox.parser.CGMMeasurementParser; -import no.nordicsemi.android.nrftoolbox.parser.CGMSpecificOpsControlPointParser; -import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser; - -public class CGMSManager extends BatteryManager { - /** Cycling Speed and Cadence service UUID. */ - public static final UUID CGMS_UUID = UUID.fromString("0000181F-0000-1000-8000-00805f9b34fb"); - private static final UUID CGM_STATUS_UUID = UUID.fromString("00002AA9-0000-1000-8000-00805f9b34fb"); - private static final UUID CGM_FEATURE_UUID = UUID.fromString("00002AA8-0000-1000-8000-00805f9b34fb"); - private static final UUID CGM_MEASUREMENT_UUID = UUID.fromString("00002AA7-0000-1000-8000-00805f9b34fb"); - private static final UUID CGM_OPS_CONTROL_POINT_UUID = UUID.fromString("00002AAC-0000-1000-8000-00805f9b34fb"); - /** Record Access Control Point characteristic UUID. */ - private static final UUID RACP_UUID = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb"); - - private BluetoothGattCharacteristic mCGMStatusCharacteristic; - private BluetoothGattCharacteristic mCGMFeatureCharacteristic; - private BluetoothGattCharacteristic mCGMMeasurementCharacteristic; - private BluetoothGattCharacteristic mCGMSpecificOpsControlPointCharacteristic; - private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic; - - private SparseArray mRecords = new SparseArray<>(); - - /** A flag set to true if the remote device supports E2E CRC. */ - private boolean mSecured; - /** - * A flag set when records has been requested using RACP. This is to distinguish CGM packets - * received as continuous measurements or requested. - */ - private boolean mRecordAccessRequestInProgress; - /** - * The timestamp when the session has started. This is needed to display the user facing - * times of samples. - */ - private long mSessionStartTime; - - CGMSManager(final Context context) { - super(context); - } - - @NonNull - @Override - protected BatteryManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving notification, etc. - */ - private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { - - @Override - protected void initialize() { - // Enable Battery service - super.initialize(); - - // Read CGM Feature characteristic, mainly to see if the device supports E2E CRC. - // This is not supported in the experimental CGMS from the SDK. - readCharacteristic(mCGMFeatureCharacteristic) - .with(new CGMFeatureDataCallback() { - @Override - public void onContinuousGlucoseMonitorFeaturesReceived(@NonNull final BluetoothDevice device, @NonNull final CGMFeatures features, - final int type, final int sampleLocation, final boolean secured) { - mSecured = features.e2eCrcSupported; - log(LogContract.Log.Level.APPLICATION, "E2E CRC feature " + (mSecured ? "supported" : "not supported")); - } - }) - .fail((device, status) -> log(Log.WARN, "Could not read CGM Feature characteristic")) - .enqueue(); - - // Check if the session is already started. This is not supported in the experimental CGMS from the SDK. - readCharacteristic(mCGMStatusCharacteristic) - .with(new CGMStatusDataCallback() { - @Override - public void onContinuousGlucoseMonitorStatusChanged(@NonNull final BluetoothDevice device, @NonNull final CGMStatus status, final int timeOffset, final boolean secured) { - if (!status.sessionStopped) { - mSessionStartTime = System.currentTimeMillis() - timeOffset * 60000L; - log(LogContract.Log.Level.APPLICATION, "Session already started"); - } - } - }) - .fail((device, status) -> log(Log.WARN, "Could not read CGM Status characteristic")) - .enqueue(); - - // Set notification and indication callbacks - setNotificationCallback(mCGMMeasurementCharacteristic) - .with(new ContinuousGlucoseMeasurementDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + CGMMeasurementParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onContinuousGlucoseMeasurementReceived(@NonNull final BluetoothDevice device, - final float glucoseConcentration, - @Nullable final Float cgmTrend, - @Nullable final Float cgmQuality, - final CGMStatus status, - final int timeOffset, - final boolean secured) { - // If the CGM Status characteristic has not been read and the session was already started before, - // estimate the Session Start Time by subtracting timeOffset minutes from the current timestamp. - if (mSessionStartTime == 0 && !mRecordAccessRequestInProgress) { - mSessionStartTime = System.currentTimeMillis() - timeOffset * 60000L; - } - - // Calculate the sample timestamp based on the Session Start Time - final long timestamp = mSessionStartTime + (timeOffset * 60000L); // Sequence number is in minutes since Start Session - - final CGMSRecord record = new CGMSRecord(timeOffset, glucoseConcentration, timestamp); - mRecords.put(record.sequenceNumber, record); - mCallbacks.onCGMValueReceived(device, record); - } - - @Override - public void onContinuousGlucoseMeasurementReceivedWithCrcError(@NonNull final BluetoothDevice device, - @NonNull final Data data) { - log(Log.WARN, "Continuous Glucose Measurement record received with CRC error"); - } - }); - - setIndicationCallback(mCGMSpecificOpsControlPointCharacteristic) - .with(new CGMSpecificOpsControlPointDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + CGMSpecificOpsControlPointParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onCGMSpecificOpsOperationCompleted(@NonNull final BluetoothDevice device, - final int requestCode, final boolean secured) { - switch (requestCode) { - case CGM_OP_CODE_START_SESSION: - mSessionStartTime = System.currentTimeMillis(); - break; - case CGM_OP_CODE_STOP_SESSION: - mSessionStartTime = 0; - break; - } - } - - @SuppressWarnings("StatementWithEmptyBody") - @Override - public void onCGMSpecificOpsOperationError(@NonNull final BluetoothDevice device, - final int requestCode, final int errorCode, - final boolean secured) { - switch (requestCode) { - case CGM_OP_CODE_START_SESSION: - if (errorCode == CGM_ERROR_PROCEDURE_NOT_COMPLETED) { - // Session was already started before. - // Looks like the CGM Status characteristic has not been read, - // otherwise we would have got the Session Start Time before. - // The Session Start Time will be calculated when a next CGM - // packet is received based on it's Time Offset. - } - case CGM_OP_CODE_STOP_SESSION: - mSessionStartTime = 0; - break; - } - } - - @Override - public void onCGMSpecificOpsResponseReceivedWithCrcError(@NonNull final BluetoothDevice device, - @NonNull final Data data) { - log(Log.ERROR, "Request failed: CRC error"); - } - }); - - setIndicationCallback(mRecordAccessControlPointCharacteristic) - .with(new RecordAccessControlPointDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onRecordAccessOperationCompleted(@NonNull final BluetoothDevice device, final int requestCode) { - switch (requestCode) { - case RACP_OP_CODE_ABORT_OPERATION: - mCallbacks.onOperationAborted(device); - break; - default: - mRecordAccessRequestInProgress = false; - mCallbacks.onOperationCompleted(device); - break; - } - } - - @Override - public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device, - final int requestCode) { - mRecordAccessRequestInProgress = false; - mCallbacks.onOperationCompleted(device); - } - - @Override - public void onNumberOfRecordsReceived(@NonNull final BluetoothDevice device, final int numberOfRecords) { - mCallbacks.onNumberOfRecordsRequested(device, numberOfRecords); - if (numberOfRecords > 0) { - if (mRecords.size() > 0) { - final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1; - writeCharacteristic(mRecordAccessControlPointCharacteristic, - RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber)) - .enqueue(); - } else { - writeCharacteristic(mRecordAccessControlPointCharacteristic, - RecordAccessControlPointData.reportAllStoredRecords()) - .enqueue(); - } - } else { - mRecordAccessRequestInProgress = false; - mCallbacks.onOperationCompleted(device); - } - } - - @Override - public void onRecordAccessOperationError(@NonNull final BluetoothDevice device, - final int requestCode, final int errorCode) { - log(Log.WARN, "Record Access operation failed (error " + errorCode + ")"); - if (errorCode == RACP_ERROR_OP_CODE_NOT_SUPPORTED) { - mCallbacks.onOperationNotSupported(device); - } else { - mCallbacks.onOperationFailed(device); - } - } - }); - - // Enable notifications and indications - enableNotifications(mCGMMeasurementCharacteristic) - .fail((device, status) -> log(Log.WARN, "Failed to enable Continuous Glucose Measurement notifications (" + status + ")")) - .enqueue(); - enableIndications(mCGMSpecificOpsControlPointCharacteristic) - .fail((device, status) -> log(Log.WARN, "Failed to enable CGM Specific Ops Control Point indications notifications (" + status + ")")) - .enqueue(); - enableIndications(mRecordAccessControlPointCharacteristic) - .fail((device, status) -> log(Log.WARN, "Failed to enabled Record Access Control Point indications (error " + status + ")")) - .enqueue(); - - // Start Continuous Glucose session if hasn't been started before - if (mSessionStartTime == 0L) { - writeCharacteristic(mCGMSpecificOpsControlPointCharacteristic, CGMSpecificOpsControlPointData.startSession(mSecured)) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + CGMSpecificOpsControlPointParser.parse(data) + "\" sent")) - .fail((device, status) -> log(LogContract.Log.Level.ERROR, "Failed to start session (error " + status + ")")) - .enqueue(); - } - } - - @Override - protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - final BluetoothGattService service = gatt.getService(CGMS_UUID); - if (service != null) { - mCGMStatusCharacteristic = service.getCharacteristic(CGM_STATUS_UUID); - mCGMFeatureCharacteristic = service.getCharacteristic(CGM_FEATURE_UUID); - mCGMMeasurementCharacteristic = service.getCharacteristic(CGM_MEASUREMENT_UUID); - mCGMSpecificOpsControlPointCharacteristic = service.getCharacteristic(CGM_OPS_CONTROL_POINT_UUID); - mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_UUID); - } - return mCGMMeasurementCharacteristic != null - && mCGMSpecificOpsControlPointCharacteristic != null - && mRecordAccessControlPointCharacteristic != null; - } - - @Override - protected void onDeviceDisconnected() { - super.onDeviceDisconnected(); - mCGMStatusCharacteristic = null; - mCGMFeatureCharacteristic = null; - mCGMMeasurementCharacteristic = null; - mCGMSpecificOpsControlPointCharacteristic = null; - mRecordAccessControlPointCharacteristic = null; - } - }; - - /** - * Returns a list of CGM records obtained from this device. The key in the array is the - */ - public SparseArray getRecords() { - return mRecords; - } - - /** - * Clears the records list locally - */ - public void clear() { - mRecords.clear(); - mCallbacks.onDatasetCleared(getBluetoothDevice()); - } - - /** - * 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 Success or other in case of error. - */ - public void getLastRecord() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - clear(); - mCallbacks.onOperationStarted(getBluetoothDevice()); - mRecordAccessRequestInProgress = true; - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } - - /** - * 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 Success or other in case of error. - */ - public void getFirstRecord() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - clear(); - mCallbacks.onOperationStarted(getBluetoothDevice()); - mRecordAccessRequestInProgress = true; - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } - - /** - * Sends abort operation signal to the device. - */ - public void abort() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } - - /** - * Sends the request to obtain all records from glucose device. Initially we want to notify the - * user about the number of the records so the Report Number of Stored Records request is send. - * The data will be returned to Glucose Measurement characteristic as a notification followed by - * Record Access Control Point indication with status code Success or other in case of error. - */ - public void getAllRecords() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - clear(); - mCallbacks.onOperationStarted(getBluetoothDevice()); - mRecordAccessRequestInProgress = true; - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } - - /** - * Sends the request to obtain all records from glucose device. Initially we want to notify the - * user about the number of the records so the Report Number of Stored Records request is send. - * The data will be returned to Glucose Measurement characteristic as a notification followed by - * Record Access Control Point indication with status code Success or other in case of error. - */ - public void refreshRecords() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - if (mRecords.size() == 0) { - getAllRecords(); - } else { - mCallbacks.onOperationStarted(getBluetoothDevice()); - - // Obtain the last sequence number - final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1; - mRecordAccessRequestInProgress = true; - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber)) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - // Info: - // Operators OPERATOR_GREATER_THEN_OR_EQUAL, OPERATOR_LESS_THEN_OR_EQUAL and OPERATOR_RANGE are not supported by the CGMS sample from SDK - // The "Operation not supported" response will be received - } - } - - /** - * Sends the request to remove all stored records from the Continuous Glucose Monitor device. - * This feature is not supported by the CGMS sample from the SDK, so monitor will answer with - * the Op Code Not Supported error. - */ - public void deleteAllRecords() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - clear(); - mCallbacks.onOperationStarted(getBluetoothDevice()); - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } -} - diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManagerCallbacks.java deleted file mode 100644 index 8ba33af..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSManagerCallbacks.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2016, 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.cgms; - -import android.bluetooth.BluetoothDevice; -import androidx.annotation.NonNull; - -import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; - -public interface CGMSManagerCallbacks extends BatteryManagerCallbacks { - - void onCGMValueReceived(@NonNull final BluetoothDevice device, final CGMSRecord record); - - void onOperationStarted(final @NonNull BluetoothDevice device); - - void onOperationCompleted(final @NonNull BluetoothDevice device); - - void onOperationFailed(final @NonNull BluetoothDevice device); - - void onOperationAborted(final @NonNull BluetoothDevice device); - - void onOperationNotSupported(final @NonNull BluetoothDevice device); - - void onDatasetCleared(final @NonNull BluetoothDevice device); - - void onNumberOfRecordsRequested(final @NonNull BluetoothDevice device, final int value); - -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSRecord.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSRecord.java deleted file mode 100644 index ced03f2..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSRecord.java +++ /dev/null @@ -1,49 +0,0 @@ -package no.nordicsemi.android.nrftoolbox.cgms; - -import android.os.Parcel; -import android.os.Parcelable; - -class CGMSRecord implements Parcelable{ - /** Record sequence number. */ - protected int sequenceNumber; - /** The base time of the measurement (start time + sequenceNumber of minutes). */ - protected long timestamp; - /** The glucose concentration in mg/dL. */ - protected float glucoseConcentration; - - CGMSRecord(final int sequenceNumber, final float glucoseConcentration, final long timestamp) { - this.sequenceNumber = sequenceNumber; - this.glucoseConcentration = glucoseConcentration; - this.timestamp = timestamp; - } - - private CGMSRecord(final Parcel in) { - this.sequenceNumber = in.readInt(); - this.glucoseConcentration = in.readFloat(); - this.timestamp = in.readLong(); - } - - public static final Creator CREATOR = new Creator() { - @Override - public CGMSRecord createFromParcel(final Parcel in) { - return new CGMSRecord(in); - } - - @Override - public CGMSRecord[] newArray(final int size) { - return new CGMSRecord[size]; - } - }; - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(final Parcel parcel, final int flags) { - parcel.writeInt(sequenceNumber); - parcel.writeFloat(glucoseConcentration); - parcel.writeLong(timestamp); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSRecordsAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSRecordsAdapter.java deleted file mode 100644 index 0fb1359..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMSRecordsAdapter.java +++ /dev/null @@ -1,79 +0,0 @@ -package no.nordicsemi.android.nrftoolbox.cgms; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.TextView; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Locale; - -import no.nordicsemi.android.nrftoolbox.R; - -public class CGMSRecordsAdapter extends BaseAdapter { - private final static SimpleDateFormat mTimeFormat = new SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.US); - - private List mRecords; - private LayoutInflater mInflater; - - public CGMSRecordsAdapter(final Context context) { - mRecords = new ArrayList<>(); - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - - @Override - public int getCount() { - return mRecords.size(); - } - - @Override - public Object getItem(int i) { - return null; - } - - @Override - public long getItemId(int i) { - return i; - } - - @Override - public View getView(final int position, View convertView, ViewGroup parent) { - ViewHolder viewHolder; - if (convertView == null) { - convertView = mInflater.inflate(R.layout.activity_feature_cgms_item, parent, false); - viewHolder = new ViewHolder(); - viewHolder.concentration = convertView.findViewById(R.id.cgms_concentration); - viewHolder.time = convertView.findViewById(R.id.time); - viewHolder.details = convertView.findViewById(R.id.details); - convertView.setTag(viewHolder); - } else { - viewHolder = (ViewHolder) convertView.getTag(); - } - - final CGMSRecord cgmsRecord = mRecords.get(position); - viewHolder.concentration.setText(String.valueOf(cgmsRecord.glucoseConcentration)); - viewHolder.details.setText(viewHolder.details.getResources().getString(R.string.cgms_details, cgmsRecord.sequenceNumber)); - viewHolder.time.setText(mTimeFormat.format(new Date(cgmsRecord.timestamp))); - - return convertView; - } - - public void addItem(final CGMSRecord record) { - mRecords.add(record); - } - - public void clear() { - mRecords.clear(); - } - - private static class ViewHolder { - TextView time; - TextView details; - TextView concentration; - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMService.java deleted file mode 100644 index 8f2f81a..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/cgms/CGMService.java +++ /dev/null @@ -1,290 +0,0 @@ -package no.nordicsemi.android.nrftoolbox.cgms; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import android.util.SparseArray; - -import no.nordicsemi.android.log.Logger; -import no.nordicsemi.android.nrftoolbox.FeaturesActivity; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; - -public class CGMService extends BleProfileService implements CGMSManagerCallbacks { - private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.cgms.ACTION_DISCONNECT"; - - public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL"; - public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL"; - - public static final String BROADCAST_NEW_CGMS_VALUE = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_NEW_CGMS_VALUE"; - public static final String BROADCAST_DATA_SET_CLEAR = "no.nordicsemi.android.nrftoolbox.cgms.BROADCAST_DATA_SET_CLEAR"; - public static final String OPERATION_STARTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_STARTED"; - public static final String OPERATION_COMPLETED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_COMPLETED"; - public static final String OPERATION_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_SUPPORTED"; - public static final String OPERATION_NOT_SUPPORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_NOT_SUPPORTED"; - public static final String OPERATION_FAILED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_FAILED"; - public static final String OPERATION_ABORTED = "no.nordicsemi.android.nrftoolbox.cgms.OPERATION_ABORTED"; - public static final String EXTRA_CGMS_RECORD = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_CGMS_RECORD"; - public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.cgms.EXTRA_DATA"; - - private final static int NOTIFICATION_ID = 229; - private final static int OPEN_ACTIVITY_REQ = 0; - private final static int DISCONNECT_REQ = 1; - - private CGMSManager mManager; - private final LocalBinder mBinder = new CGMSBinder(); - - /** - * This local binder is an interface for the bonded activity to operate with the RSC sensor - */ - - public class CGMSBinder extends LocalBinder { - /** - * Returns all records as a sparse array where sequence number is the key. - * - * @return the records list - */ - public SparseArray getRecords() { - return mManager.getRecords(); - } - - /** - * Clears the records list locally - */ - public void clear() { - if (mManager != null) - mManager.clear(); - } - - /** - * 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 CGMSManager# RESPONSE_SUCCESS} or other in case of error. - */ - public void getFirstRecord() { - if (mManager != null) - mManager.getFirstRecord(); - } - - /** - * 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 Success or other in case of error. - */ - public void getLastRecord() { - if (mManager != null) - mManager.getLastRecord(); - } - - /** - * Sends the request to obtain all records from glucose device. - * Initially we want to notify user about the number of the records so the Report Number of Stored Records is send. - * The data will be returned to Glucose Measurement characteristic as a series of notifications followed - * by Record Access Control Point indication with status code Success or other in case of error. - */ - public void getAllRecords() { - if (mManager != null) - mManager.getAllRecords(); - } - - /** - * Sends the request to obtain all records from glucose device with sequence number greater - * than the last one already obtained. The data will be returned to Glucose Measurement - * characteristic as a series of notifications followed by Record Access Control Point - * indication with status code Success or other in case of error. - */ - public void refreshRecords() { - if (mManager != null) - mManager.refreshRecords(); - } - - /** - * Sends abort operation signal to the device - */ - public void abort() { - if (mManager != null) - mManager.abort(); - } - - /** - * Sends Delete op code with All stored records parameter. This method may not be supported by the SDK sample. - */ - public void deleteAllRecords() { - if (mManager != null) - mManager.deleteAllRecords(); - } - } - - @Override - protected LocalBinder getBinder() { - return mBinder; - } - - @Override - protected LoggableBleManager initializeManager() { - return mManager = new CGMSManager(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 - protected void onRebind() { - // when the activity rebinds to the service, remove the notification - cancelNotification(); - } - - @Override - protected void onUnbind() { - // 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); - } - - /** - * 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, CGMSActivity.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 AndroidManifest.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 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL); - builder.setContentIntent(pendingIntent); - builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); - builder.setSmallIcon(R.drawable.ic_stat_notify_cgms); - builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); - builder.addAction(new NotificationCompat.Action(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(), "[Notification] Disconnect action pressed"); - if (isConnected()) - getBinder().disconnect(); - else - stopSelf(); - } - }; - - @Override - public void onCGMValueReceived(@NonNull final BluetoothDevice device, final CGMSRecord record) { - final Intent broadcast = new Intent(BROADCAST_NEW_CGMS_VALUE); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_CGMS_RECORD, record); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - @Override - public void onOperationStarted(@NonNull final BluetoothDevice device) { - final Intent broadcast = new Intent(OPERATION_STARTED); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_DATA, true); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - @Override - public void onOperationCompleted(@NonNull final BluetoothDevice device) { - final Intent broadcast = new Intent(OPERATION_COMPLETED); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_DATA, true); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - @Override - public void onOperationFailed(@NonNull final BluetoothDevice device) { - final Intent broadcast = new Intent(OPERATION_FAILED); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_DATA, true); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - @Override - public void onOperationAborted(@NonNull final BluetoothDevice device) { - final Intent broadcast = new Intent(OPERATION_ABORTED); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_DATA, true); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - @Override - public void onOperationNotSupported(@NonNull final BluetoothDevice device) { - final Intent broadcast = new Intent(OPERATION_NOT_SUPPORTED); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_DATA, false); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - @Override - public void onDatasetCleared(@NonNull final BluetoothDevice device) { - final Intent broadcast = new Intent(BROADCAST_DATA_SET_CLEAR); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - @Override - public void onNumberOfRecordsRequested(@NonNull final BluetoothDevice device, final int value) { - if (value == 0) - showToast(R.string.gls_progress_zero); - else - showToast(getResources().getQuantityString(R.plurals.gls_progress, value, value)); - - } - - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); - broadcast.putExtra(EXTRA_DEVICE, device); - broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } -} 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 deleted file mode 100644 index 399fb06..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCActivity.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.PreferenceManager; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import android.view.Menu; -import android.widget.TextView; - -import java.util.Locale; -import java.util.UUID; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.csc.settings.SettingsActivity; -import no.nordicsemi.android.nrftoolbox.csc.settings.SettingsFragment; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; - -public class CSCActivity extends BleProfileServiceReadyActivity { - private TextView mSpeedView; - private TextView mSpeedUnitView; - private TextView mCadenceView; - private TextView mDistanceView; - private TextView mDistanceUnitView; - private TextView mTotalDistanceView; - private TextView mTotalDistanceUnitView; - private TextView mGearRatioView; - private TextView mBatteryLevelView; - - @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 = findViewById(R.id.speed); - mSpeedUnitView = findViewById(R.id.speed_unit); - mCadenceView = findViewById(R.id.cadence); - mDistanceView = findViewById(R.id.distance); - mDistanceUnitView = findViewById(R.id.distance_unit); - mTotalDistanceView = findViewById(R.id.distance_total); - mTotalDistanceUnitView = findViewById(R.id.distance_total_unit); - mGearRatioView = findViewById(R.id.ratio); - mBatteryLevelView = findViewById(R.id.battery); - } - - @Override - protected void onResume() { - super.onResume(); - setDefaultUI(); - } - - @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); - mTotalDistanceView.setText(R.string.not_available_value); - mGearRatioView.setText(R.string.not_available_value); - mBatteryLevelView.setText(R.string.not_available); - - setUnits(); - } - - private void setUnits() { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT))); - - switch (unit) { - case SettingsFragment.SETTINGS_UNIT_M_S: // [m/s] - mSpeedUnitView.setText(R.string.csc_speed_unit_m_s); - mDistanceUnitView.setText(R.string.csc_distance_unit_m); - mTotalDistanceUnitView.setText(R.string.csc_total_distance_unit_km); - break; - case SettingsFragment.SETTINGS_UNIT_KM_H: // [km/h] - mSpeedUnitView.setText(R.string.csc_speed_unit_km_h); - mDistanceUnitView.setText(R.string.csc_distance_unit_m); - mTotalDistanceUnitView.setText(R.string.csc_total_distance_unit_km); - break; - case SettingsFragment.SETTINGS_UNIT_MPH: // [mph] - mSpeedUnitView.setText(R.string.csc_speed_unit_mph); - mDistanceUnitView.setText(R.string.csc_distance_unit_yd); - mTotalDistanceUnitView.setText(R.string.csc_total_distance_unit_mile); - break; - } - } - - @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.settings_and_about, 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 onServiceBound(final CSCService.CSCBinder binder) { - // not used - } - - @Override - protected void onServiceUnbound() { - // not used - } - - @Override - public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { - // not used - } - - @Override - public void onDeviceDisconnected(final BluetoothDevice device) { - super.onDeviceDisconnected(device); - mBatteryLevelView.setText(R.string.not_available); - } - - private void onMeasurementReceived(final BluetoothDevice device, float speed, float distance, float totalDistance) { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT))); - - switch (unit) { - case SettingsFragment.SETTINGS_UNIT_KM_H: - speed = speed * 3.6f; - // pass through intended - case SettingsFragment.SETTINGS_UNIT_M_S: - if (distance < 1000) { // 1 km in m - mDistanceView.setText(String.format(Locale.US, "%.0f", distance)); - mDistanceUnitView.setText(R.string.csc_distance_unit_m); - } else { - mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 1000.0f)); - mDistanceUnitView.setText(R.string.csc_distance_unit_km); - } - - mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f)); - break; - case SettingsFragment.SETTINGS_UNIT_MPH: - speed = speed * 2.2369f; - if (distance < 1760) { // 1 mile in yrs - mDistanceView.setText(String.format(Locale.US, "%.0f", distance)); - mDistanceUnitView.setText(R.string.csc_distance_unit_yd); - } else { - mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 1760.0f)); - mDistanceUnitView.setText(R.string.csc_distance_unit_mile); - } - - mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f)); - break; - } - - mSpeedView.setText(String.format(Locale.US, "%.1f", speed)); - } - - private void onGearRatioUpdate(final BluetoothDevice device, final int cadence, final float ratio) { - mCadenceView.setText(String.format(Locale.US, "%d", cadence)); - mGearRatioView.setText(String.format(Locale.US, "%.1f", ratio)); - } - - public void onBatteryLevelChanged(final BluetoothDevice device, final int value) { - mBatteryLevelView.setText(getString(R.string.battery, value)); - } - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(final Context context, final Intent intent) { - final String action = intent.getAction(); - final BluetoothDevice device = intent.getParcelableExtra(CSCService.EXTRA_DEVICE); - - if (CSCService.BROADCAST_WHEEL_DATA.equals(action)) { - final float speed = intent.getFloatExtra(CSCService.EXTRA_SPEED, 0.0f); // [m/s] - final float distance = intent.getFloatExtra(CSCService.EXTRA_DISTANCE, 0); - final float totalDistance = intent.getFloatExtra(CSCService.EXTRA_TOTAL_DISTANCE, 0); - // Update GUI - onMeasurementReceived(device, 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(device, cadence, ratio); - } else if (CSCService.BROADCAST_BATTERY_LEVEL.equals(action)) { - final int batteryLevel = intent.getIntExtra(CSCService.EXTRA_BATTERY_LEVEL, 0); - // Update GUI - onBatteryLevelChanged(device, batteryLevel); - } - } - }; - - private static IntentFilter makeIntentFilter() { - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(CSCService.BROADCAST_WHEEL_DATA); - intentFilter.addAction(CSCService.BROADCAST_CRANK_DATA); - intentFilter.addAction(CSCService.BROADCAST_BATTERY_LEVEL); - 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 deleted file mode 100644 index c4feef5..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManager.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; -import androidx.annotation.NonNull; -import android.util.Log; - -import java.util.UUID; - -import no.nordicsemi.android.ble.common.callback.csc.CyclingSpeedAndCadenceMeasurementDataCallback; -import no.nordicsemi.android.ble.data.Data; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; -import no.nordicsemi.android.nrftoolbox.csc.settings.SettingsFragment; -import no.nordicsemi.android.nrftoolbox.parser.CSCMeasurementParser; - -public class CSCManager extends BatteryManager { - /** Cycling Speed and Cadence service UUID. */ - public final static UUID CYCLING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001816-0000-1000-8000-00805f9b34fb"); - /** Cycling Speed and Cadence Measurement characteristic UUID. */ - private final static UUID CSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A5B-0000-1000-8000-00805f9b34fb"); - - private final SharedPreferences preferences; - private BluetoothGattCharacteristic mCSCMeasurementCharacteristic; - - CSCManager(final Context context) { - super(context); - preferences = PreferenceManager.getDefaultSharedPreferences(context); - } - - @NonNull - @Override - protected BatteryManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving indication, etc. - */ - private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { - - @Override - protected void initialize() { - super.initialize(); - - // CSC characteristic is required - setNotificationCallback(mCSCMeasurementCharacteristic) - .with(new CyclingSpeedAndCadenceMeasurementDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, final @NonNull Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + CSCMeasurementParser.parse(data) + "\" received"); - - // Pass through received data - super.onDataReceived(device, data); - } - - @Override - public float getWheelCircumference() { - return Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_WHEEL_SIZE, - String.valueOf(SettingsFragment.SETTINGS_WHEEL_SIZE_DEFAULT))); - } - - @Override - public void onDistanceChanged(@NonNull final BluetoothDevice device, - final float totalDistance, final float distance, final float speed) { - mCallbacks.onDistanceChanged(device, totalDistance, distance, speed); - } - - @Override - public void onCrankDataChanged(@NonNull final BluetoothDevice device, - final float crankCadence, final float gearRatio) { - mCallbacks.onCrankDataChanged(device, crankCadence, gearRatio); - } - - @Override - public void onInvalidDataReceived(@NonNull final BluetoothDevice device, - final @NonNull Data data) { - log(Log.WARN, "Invalid CSC Measurement data received: " + data); - } - }); - enableNotifications(mCSCMeasurementCharacteristic).enqueue(); - } - - @Override - public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - final BluetoothGattService service = gatt.getService(CYCLING_SPEED_AND_CADENCE_SERVICE_UUID); - if (service != null) { - mCSCMeasurementCharacteristic = service.getCharacteristic(CSC_MEASUREMENT_CHARACTERISTIC_UUID); - } - return mCSCMeasurementCharacteristic != null; - } - - @Override - protected void onDeviceDisconnected() { - super.onDeviceDisconnected(); - mCSCMeasurementCharacteristic = 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 deleted file mode 100644 index 12035da..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCManagerCallbacks.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.ble.common.profile.csc.CyclingSpeedAndCadenceCallback; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; - -interface CSCManagerCallbacks extends BatteryManagerCallbacks, CyclingSpeedAndCadenceCallback { -} 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 deleted file mode 100644 index 2a99f0c..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/CSCService.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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 android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; - -import no.nordicsemi.android.log.Logger; -import no.nordicsemi.android.nrftoolbox.FeaturesActivity; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; - -public class CSCService extends BleProfileService implements CSCManagerCallbacks { - @SuppressWarnings("unused") - private static final String TAG = "CSCService"; - - public static final String BROADCAST_WHEEL_DATA = "no.nordicsemi.android.nrftoolbox.csc.BROADCAST_WHEEL_DATA"; - /** Speed in meters per second. */ - 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"; - - public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL"; - public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL"; - - private static final String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.csc.ACTION_DISCONNECT"; - - 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(); - private CSCManager mManager; - - /** - * This local binder is an interface for the bonded activity to operate with the RSC sensor - */ - class CSCBinder extends LocalBinder { - // empty - } - - @Override - protected LocalBinder getBinder() { - return mBinder; - } - - @Override - protected LoggableBleManager 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 - protected void onRebind() { - // when the activity rebinds to the service, remove the notification - cancelNotification(); - - if (isConnected()) { - // This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property). - // If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications. - mManager.readBatteryLevelCharacteristic(); - } - } - - @Override - protected void onUnbind() { - // When we are connected, but the application is not open, we are not really interested in battery level notifications. - // But we will still be receiving other values, if enabled. - if (isConnected()) - mManager.disableBatteryLevelCharacteristicNotifications(); - - // 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); - } - - @Override - public void onDistanceChanged(@NonNull final BluetoothDevice device, final float totalDistance, final float distance, final float speed) { - final Intent broadcast = new Intent(BROADCAST_WHEEL_DATA); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_SPEED, speed); - broadcast.putExtra(EXTRA_DISTANCE, distance); - broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - @Override - public void onCrankDataChanged(@NonNull final BluetoothDevice device, final float crankCadence, final float gearRatio) { - final Intent broadcast = new Intent(BROADCAST_CRANK_DATA); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_GEAR_RATIO, gearRatio); - broadcast.putExtra(EXTRA_CADENCE, (int) crankCadence); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - /** - * 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 AndroidManifest.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 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL); - builder.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(new NotificationCompat.Action(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(), "[Notification] 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 deleted file mode 100644 index ebbf512..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsActivity.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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 androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import android.view.MenuItem; - -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsActivity extends AppCompatActivity { - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_settings); - - final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - // Display the fragment as the main content. - getSupportFragmentManager().beginTransaction().replace(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 deleted file mode 100644 index 2a3b41b..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/csc/settings/SettingsFragment.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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.content.SharedPreferences; -import android.os.Bundle; -import androidx.preference.PreferenceScreen; - -import androidx.preference.PreferenceFragmentCompat; -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { - public static final String SETTINGS_WHEEL_SIZE = "settings_wheel_size"; - public static final int SETTINGS_WHEEL_SIZE_DEFAULT = 2340; - public static final String SETTINGS_UNIT = "settings_csc_unit"; - public static final int SETTINGS_UNIT_M_S = 0; // [m/s] - public static final int SETTINGS_UNIT_KM_H = 1; // [m/s] - public static final int SETTINGS_UNIT_MPH = 2; // [m/s] - public static final int SETTINGS_UNIT_DEFAULT = SETTINGS_UNIT_KM_H; - - @Override - public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { - 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 deleted file mode 100644 index 8851727..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuActivity.java +++ /dev/null @@ -1,862 +0,0 @@ -/* - * 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.Manifest; -import android.app.ActivityManager; -import android.app.ActivityManager.RunningServiceInfo; -import android.app.LoaderManager.LoaderCallbacks; -import android.app.NotificationManager; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothManager; -import android.content.Context; -import android.content.CursorLoader; -import android.content.Intent; -import android.content.Loader; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.provider.MediaStore; -import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; -import androidx.fragment.app.DialogFragment; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -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 no.nordicsemi.android.dfu.DfuProgressListener; -import no.nordicsemi.android.dfu.DfuProgressListenerAdapter; -import no.nordicsemi.android.dfu.DfuServiceInitiator; -import no.nordicsemi.android.dfu.DfuServiceListenerHelper; -import no.nordicsemi.android.nrftoolbox.AppHelpFragment; -import no.nordicsemi.android.nrftoolbox.PermissionRationaleFragment; -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.dfu.settings.SettingsFragment; -import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; -import no.nordicsemi.android.nrftoolbox.utility.FileHelper; - -/** - * 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 AppCompatActivity implements LoaderCallbacks, ScannerFragment.OnDeviceSelectedListener, - UploadCancelFragment.CancelFragmentListener, PermissionRationaleFragment.PermissionDialogListener { - private static final String TAG = "DfuActivity"; - - 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_SCOPE = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_FILE_SCOPE"; - 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 DATA_SCOPE = "scope"; - private static final String DATA_DFU_COMPLETED = "dfu_completed"; - private static final String DATA_DFU_ERROR = "dfu_error"; - - private static final String EXTRA_URI = "uri"; - - private static final int PERMISSION_REQ = 25; - 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 mFileScopeView; - 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 Integer mScope; - private boolean mStatusOk; - /** Flag set to true in {@link #onRestart()} and to false in {@link #onPause()}. */ - private boolean mResumed; - /** Flag set to true if DFU operation was completed while {@link #mResumed} was false. */ - private boolean mDfuCompleted; - /** The error message received from DFU service while {@link #mResumed} was false. */ - private String mDfuError; - - /** - * The progress listener receives events from the DFU Service. - * If is registered in onCreate() and unregistered in onDestroy() so methods here may also be called - * when the screen is locked or the app went to the background. This is because the UI needs to have the - * correct information after user comes back to the activity and this information can't be read from the service - * as it might have been killed already (DFU completed or finished with error). - */ - private final DfuProgressListener mDfuProgressListener = new DfuProgressListenerAdapter() { - @Override - public void onDeviceConnecting(final String deviceAddress) { - mProgressBar.setIndeterminate(true); - mTextPercentage.setText(R.string.dfu_status_connecting); - } - - @Override - public void onDfuProcessStarting(final String deviceAddress) { - mProgressBar.setIndeterminate(true); - mTextPercentage.setText(R.string.dfu_status_starting); - } - - @Override - public void onEnablingDfuMode(final String deviceAddress) { - mProgressBar.setIndeterminate(true); - mTextPercentage.setText(R.string.dfu_status_switching_to_dfu); - } - - @Override - public void onFirmwareValidating(final String deviceAddress) { - mProgressBar.setIndeterminate(true); - mTextPercentage.setText(R.string.dfu_status_validating); - } - - @Override - public void onDeviceDisconnecting(final String deviceAddress) { - mProgressBar.setIndeterminate(true); - mTextPercentage.setText(R.string.dfu_status_disconnecting); - } - - @Override - public void onDfuCompleted(final String deviceAddress) { - mTextPercentage.setText(R.string.dfu_status_completed); - if (mResumed) { - // let's wait a bit until we cancel the notification. When canceled immediately it will be recreated by service again. - new Handler().postDelayed(() -> { - 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); - } else { - // Save that the DFU process has finished - mDfuCompleted = true; - } - } - - @Override - public void onDfuAborted(final String deviceAddress) { - 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(() -> { - 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); - } - - @Override - public void onProgressChanged(final String deviceAddress, final int percent, final float speed, final float avgSpeed, final int currentPart, final int partsTotal) { - mProgressBar.setIndeterminate(false); - mProgressBar.setProgress(percent); - mTextPercentage.setText(getString(R.string.dfu_uploading_percentage, percent)); - if (partsTotal > 1) - mTextUploading.setText(getString(R.string.dfu_status_uploading_part, currentPart, partsTotal)); - else - mTextUploading.setText(R.string.dfu_status_uploading); - } - - @Override - public void onError(final String deviceAddress, final int error, final int errorType, final String message) { - if (mResumed) { - showErrorMessage(message); - - // We have to wait a bit before canceling notification. This is called before DfuService creates the last notification. - new Handler().postDelayed(() -> { - // 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); - } else { - mDfuError = message; - } - } - }; - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_feature_dfu); - isBLESupported(); - if (!isBLEEnabled()) { - showBLEDialog(); - } - setGUI(); - - // Try to create sample files - if (FileHelper.newSamplesAvailable(this)) { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - FileHelper.createSamples(this); - } else { - final DialogFragment dialog = PermissionRationaleFragment.getInstance(R.string.permission_sd_text, Manifest.permission.WRITE_EXTERNAL_STORAGE); - dialog.show(getSupportFragmentManager(), null); - } - } - - // restore saved state - mFileType = DfuService.TYPE_AUTO; // 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); - mScope = savedInstanceState.containsKey(DATA_SCOPE) ? savedInstanceState.getInt(DATA_SCOPE) : null; - mUploadButton.setEnabled(mSelectedDevice != null && mStatusOk); - mDfuCompleted = savedInstanceState.getBoolean(DATA_DFU_COMPLETED); - mDfuError = savedInstanceState.getString(DATA_DFU_ERROR); - } - - DfuServiceListenerHelper.registerProgressListener(this, mDfuProgressListener); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - DfuServiceListenerHelper.unregisterProgressListener(this, mDfuProgressListener); - } - - @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); - if (mScope != null) outState.putInt(DATA_SCOPE, mScope); - outState.putBoolean(DATA_DFU_COMPLETED, mDfuCompleted); - outState.putString(DATA_DFU_ERROR, mDfuError); - } - - private void setGUI() { - final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - mDeviceNameView = findViewById(R.id.device_name); - mFileNameView = findViewById(R.id.file_name); - mFileTypeView = findViewById(R.id.file_type); - mFileScopeView = findViewById(R.id.file_scope); - mFileSizeView = findViewById(R.id.file_size); - mFileStatusView = findViewById(R.id.file_status); - mSelectFileButton = findViewById(R.id.action_select_file); - mUploadButton = findViewById(R.id.action_upload); - mConnectButton = findViewById(R.id.action_connect); - mTextPercentage = findViewById(R.id.textviewProgress); - mTextUploading = findViewById(R.id.textviewUploading); - mProgressBar = 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, "")); - mFileScopeView.setText(preferences.getString(PREFS_FILE_SCOPE, "")); - mFileSizeView.setText(preferences.getString(PREFS_FILE_SIZE, "")); - mFileStatusView.setText(R.string.dfu_file_status_ok); - mStatusOk = true; - showProgressBar(); - } - } - - @Override - protected void onResume() { - super.onResume(); - mResumed = true; - if (mDfuCompleted) - onTransferCompleted(); - if (mDfuError != null) - showErrorMessage(mDfuError); - if (mDfuCompleted || mDfuError != null) { - // 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); - mDfuCompleted = false; - mDfuError = null; - } - } - - @Override - protected void onPause() { - super.onPause(); - mResumed = false; - } - - @Override - public void onRequestPermission(final String permission) { - ActivityCompat.requestPermissions(this, new String[] { permission }, PERMISSION_REQ); - } - - @Override - public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - switch (requestCode) { - case PERMISSION_REQ: { - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // We have been granted the Manifest.permission.WRITE_EXTERNAL_STORAGE permission. Now we may proceed with exporting. - FileHelper.createSamples(this); - } else { - Toast.makeText(this, R.string.no_required_permission, Toast.LENGTH_SHORT).show(); - } - break; - } - } - } - - 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 ScannerFragment dialog = ScannerFragment.getInstance(null); // Device that is advertising directly does not have the GENERAL_DISCOVERABLE nor LIMITED_DISCOVERABLE flag set. - dialog.show(getSupportFragmentManager(), "scan_fragment"); - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.settings_and_about, 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(getSupportFragmentManager(), "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_AUTO: - mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[0]); - break; - case DfuService.TYPE_SOFT_DEVICE: - mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[1]); - break; - case DfuService.TYPE_BOOTLOADER: - mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[2]); - break; - case DfuService.TYPE_APPLICATION: - mFileTypeView.setText(getResources().getStringArray(R.array.dfu_file_type)[3]); - break; - } - mFileSizeView.setText(getString(R.string.dfu_file_size_text, fileSize)); - mFileScopeView.setText(getString(R.string.not_available)); - 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) { - if (fileType != DfuService.TYPE_AUTO) { - mScope = null; - mFileScopeView.setText(getString(R.string.not_available)); - new AlertDialog.Builder(this).setTitle(R.string.dfu_file_init_title).setMessage(R.string.dfu_file_init_message) - .setNegativeButton(R.string.no, (dialog, which) -> { - mInitFilePath = null; - mInitFileStreamUri = null; - }).setPositiveButton(R.string.yes, (dialog, 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(); - } else { - new AlertDialog.Builder(this).setTitle(R.string.dfu_file_scope_title).setCancelable(false) - .setSingleChoiceItems(R.array.dfu_file_scope, 0, (dialog, which) -> { - switch (which) { - case 0: - mScope = null; - break; - case 1: - mScope = DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS; - break; - case 2: - mScope = DfuServiceInitiator.SCOPE_APPLICATION; - break; - } - }).setPositiveButton(R.string.ok, (dialogInterface, i) -> { - int index; - if (mScope == null) { - index = 0; - } else if (mScope == DfuServiceInitiator.SCOPE_SYSTEM_COMPONENTS) { - index = 1; - } else { - index = 2; - } - mFileScopeView.setText(getResources().getStringArray(R.array.dfu_file_scope)[index]); - }).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 = 0; - switch (mFileType) { - case DfuService.TYPE_AUTO: - index = 0; - break; - case DfuService.TYPE_SOFT_DEVICE: - index = 1; - break; - case DfuService.TYPE_BOOTLOADER: - index = 2; - break; - case DfuService.TYPE_APPLICATION: - 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, (dialog, which) -> { - switch (which) { - case 0: - mFileTypeTmp = DfuService.TYPE_AUTO; - break; - case 1: - mFileTypeTmp = DfuService.TYPE_SOFT_DEVICE; - break; - case 2: - mFileTypeTmp = DfuService.TYPE_BOOTLOADER; - break; - case 3: - mFileTypeTmp = DfuService.TYPE_APPLICATION; - break; - } - }).setPositiveButton(R.string.ok, (dialog, which) -> openFileChooser()).setNeutralButton(R.string.dfu_file_info, (dialog, which) -> { - final ZipInfoFragment fragment = new ZipInfoFragment(); - fragment.show(getSupportFragmentManager(), "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 = 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, (dialog, which) -> dialog.dismiss()).setPositiveButton(R.string.ok, (dialog, 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_SCOPE, mFileScopeView.getText().toString()); - editor.putString(PREFS_FILE_SIZE, mFileSizeView.getText().toString()); - editor.apply(); - - showProgressBar(); - - final boolean keepBond = preferences.getBoolean(SettingsFragment.SETTINGS_KEEP_BOND, false); - final boolean forceDfu = preferences.getBoolean(SettingsFragment.SETTINGS_ASSUME_DFU_NODE, false); - final boolean enablePRNs = preferences.getBoolean(SettingsFragment.SETTINGS_PACKET_RECEIPT_NOTIFICATION_ENABLED, Build.VERSION.SDK_INT < Build.VERSION_CODES.M); - String value = preferences.getString(SettingsFragment.SETTINGS_NUMBER_OF_PACKETS, String.valueOf(DfuServiceInitiator.DEFAULT_PRN_VALUE)); - int numberOfPackets; - try { - numberOfPackets = Integer.parseInt(value); - } catch (final NumberFormatException e) { - numberOfPackets = DfuServiceInitiator.DEFAULT_PRN_VALUE; - } - - final DfuServiceInitiator starter = new DfuServiceInitiator(mSelectedDevice.getAddress()) - .setDeviceName(mSelectedDevice.getName()) - .setKeepBond(keepBond) - .setForceDfu(forceDfu) - .setPacketsReceiptNotificationsEnabled(enablePRNs) - .setPacketsReceiptNotificationsValue(numberOfPackets) - .setUnsafeExperimentalButtonlessServiceInSecureDfuEnabled(true); - if (mFileType == DfuService.TYPE_AUTO) { - starter.setZip(mFileStreamUri, mFilePath); - if (mScope != null) - starter.setScope(mScope); - } else { - starter.setBinOrHex(mFileType, mFileStreamUri, mFilePath).setInitFile(mInitFileStreamUri, mInitFilePath); - } - starter.start(this, DfuService.class); - } - - 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(getSupportFragmentManager(), 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 != null ? name : getString(R.string.not_available)); - } - - @Override - public void onDialogCanceled() { - // do nothing - } - - 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 String message) { - clearUI(false); - showToast("Upload failed: " + message); - } - - 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); - mFileScopeView.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() { - final 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 deleted file mode 100644 index b236ec6..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuInitiatorActivity.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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.bluetooth.BluetoothDevice; -import android.content.Intent; -import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; - -/** - * 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 AppCompatActivity 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(null); // Device that is advertising directly does not have the GENERAL_DISCOVERABLE nor LIMITED_DISCOVERABLE flag set. - fragment.show(getSupportFragmentManager(), 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 != null ? name : getString(R.string.not_available)) : overwrittenName; - final int type = intent.getIntExtra(DfuService.EXTRA_FILE_TYPE, DfuService.TYPE_AUTO); - final boolean keepBond = intent.getBooleanExtra(DfuService.EXTRA_KEEP_BOND, false); - - // 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); - service.putExtra(DfuService.EXTRA_KEEP_BOND, keepBond); - service.putExtra(DfuService.EXTRA_UNSAFE_EXPERIMENTAL_BUTTONLESS_DFU, true); - 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 deleted file mode 100644 index 2b16b59..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/DfuService.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.Activity; - -import no.nordicsemi.android.dfu.DfuBaseService; - -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; - } - - @Override - protected boolean isDebug() { - // return BuildConfig.DEBUG; - return true; - } -} 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 deleted file mode 100644 index 1b02671..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/NotificationActivity.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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.Activity; -import android.content.Intent; -import android.os.Bundle; - -import no.nordicsemi.android.nrftoolbox.FeaturesActivity; - -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 deleted file mode 100644 index b21a28b..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/adapter/FileBrowserAppsAdapter.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 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; - -import no.nordicsemi.android.nrftoolbox.R; - -/** - * 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 deleted file mode 100644 index 0fac518..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/UploadCancelFragment.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * 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 android.app.Activity; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import androidx.appcompat.app.AlertDialog; -import android.util.Log; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.dfu.DfuService; - -/** - * 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 { - 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"); - } - } - - @NonNull - @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, (dialog, 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, (dialog, 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 deleted file mode 100644 index 154cd38..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/fragment/ZipInfoFragment.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 android.app.Dialog; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import androidx.appcompat.app.AlertDialog; -import android.view.LayoutInflater; -import android.view.View; - -import no.nordicsemi.android.nrftoolbox.R; - -public class ZipInfoFragment extends DialogFragment { - - @Override - @NonNull - 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 deleted file mode 100644 index fc04998..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/AboutDfuPreference.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.util.AttributeSet; -import android.widget.Toast; - -import androidx.preference.Preference; -import no.nordicsemi.android.nrftoolbox.R; - -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("https://www.nordicsemi.com/DocLib/Content/SDK_Doc/nRF5_SDK/v15-3-0/ble_sdk_app_dfu_bootloader")); - 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 deleted file mode 100644 index a957f33..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsActivity.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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 androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import android.view.MenuItem; - -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsActivity extends AppCompatActivity { - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_settings); - - final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - // Display the fragment as the main content. - getSupportFragmentManager().beginTransaction().replace(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 deleted file mode 100644 index aaaf5de..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/dfu/settings/SettingsFragment.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * 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.content.SharedPreferences; -import android.os.Build; -import android.os.Bundle; -import androidx.appcompat.app.AlertDialog; -import android.text.TextUtils; - -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceScreen; -import no.nordicsemi.android.dfu.DfuServiceInitiator; -import no.nordicsemi.android.dfu.DfuSettingsConstants; -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsFragment extends PreferenceFragmentCompat implements DfuSettingsConstants, SharedPreferences.OnSharedPreferenceChangeListener { - public static final String SETTINGS_KEEP_BOND = "settings_keep_bond"; - - @Override - public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { - 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 && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - new AlertDialog.Builder(requireContext()).setMessage(R.string.dfu_settings_dfu_number_of_packets_info).setTitle(R.string.dfu_settings_dfu_information) - .setPositiveButton(R.string.ok, null).show(); - } - } else if (SETTINGS_NUMBER_OF_PACKETS.equals(key)) { - updateNumberOfPacketsSummary(); - } else if (SETTINGS_MBR_SIZE.equals(key)) { - updateMBRSize(); - } else if (SETTINGS_ASSUME_DFU_NODE.equals(key) && sharedPreferences.getBoolean(key, false)) { - new AlertDialog.Builder(requireContext()).setMessage(R.string.dfu_settings_dfu_assume_dfu_mode_info).setTitle(R.string.dfu_settings_dfu_information) - .setPositiveButton(R.string.ok, null) - .show(); - } - } - - private void updateNumberOfPacketsSummary() { - final PreferenceScreen screen = getPreferenceScreen(); - final SharedPreferences preferences = getPreferenceManager().getSharedPreferences(); - - String value = preferences.getString(SETTINGS_NUMBER_OF_PACKETS, String.valueOf(SETTINGS_NUMBER_OF_PACKETS_DEFAULT)); - // Security check - if (TextUtils.isEmpty(value)) { - value = String.valueOf(SETTINGS_NUMBER_OF_PACKETS_DEFAULT); - preferences.edit().putString(SETTINGS_NUMBER_OF_PACKETS, value).apply(); - } - screen.findPreference(SETTINGS_NUMBER_OF_PACKETS).setSummary(value); - - final int valueInt = Integer.parseInt(value); - if (valueInt > 200 && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { - new AlertDialog.Builder(requireContext()).setMessage(R.string.dfu_settings_dfu_number_of_packets_info).setTitle(R.string.dfu_settings_dfu_information) - .setPositiveButton(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(DfuServiceInitiator.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 deleted file mode 100644 index 85712de..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/ExpandableRecordAdapter.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * 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 android.content.Context; -import android.content.res.Resources; -import android.util.Pair; -import android.util.SparseArray; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseExpandableListAdapter; -import android.widget.TextView; - -import no.nordicsemi.android.nrftoolbox.R; - -public class ExpandableRecordAdapter extends BaseExpandableListAdapter {; - private final GlucoseManager mGlucoseManager; - private final LayoutInflater mInflater; - private final Context mContext; - private SparseArray mRecords; - - public ExpandableRecordAdapter(final Context context, final GlucoseManager manager) { - mGlucoseManager = manager; - mContext = context; - mInflater = LayoutInflater.from(context); - mRecords = manager.getRecords().clone(); - } - - @Override - public void notifyDataSetChanged() { - mRecords = mGlucoseManager.getRecords().clone(); - super.notifyDataSetChanged(); - } - - @Override - public int getGroupCount() { - return mRecords.size(); - } - - @Override - public Object getGroup(final int groupPosition) { - return mRecords.valueAt(groupPosition); - } - - @Override - public long getGroupId(final int groupPosition) { - return mRecords.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 = view.findViewById(R.id.time); - holder.details = view.findViewById(R.id.details); - holder.concentration = 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 optional 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); - String tmp; - switch (childIdToItemId(childPosition, record)) { - case 0: - try { - tmp = resources.getStringArray(R.array.gls_location)[record.sampleLocation]; - } catch (final ArrayIndexOutOfBoundsException e) { - tmp = resources.getStringArray(R.array.gls_location)[0]; - } - return new Pair<>(resources.getString(R.string.gls_location_title), tmp); - 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_annunciation)[i]).append("\n"); - builder.setLength(builder.length() - 1); - return new Pair<>(resources.getString(R.string.gls_status_annunciation_title), builder.toString()); - } - case 2: { // carbohydrate id and unit - try { - tmp = resources.getStringArray(R.array.gls_context_carbohydrare)[record.context.carbohydrateId]; - } catch (final ArrayIndexOutOfBoundsException e) { - tmp = resources.getStringArray(R.array.gls_context_carbohydrare)[0]; - } - return new Pair<>(resources.getString(R.string.gls_context_carbohydrare_title), tmp + " (" + record.context.carbohydrateUnits + " g)"); - } - case 3: { // meal - try { - tmp = resources.getStringArray(R.array.gls_context_meal)[record.context.meal]; - } catch (final ArrayIndexOutOfBoundsException e) { - tmp = resources.getStringArray(R.array.gls_context_meal)[0]; - } - return new Pair<>(resources.getString(R.string.gls_context_meal_title), tmp); - } - case 4: { // tester - try { - tmp = resources.getStringArray(R.array.gls_context_tester)[record.context.tester]; - } catch (final ArrayIndexOutOfBoundsException e) { - tmp = resources.getStringArray(R.array.gls_context_tester)[0]; - } - return new Pair<>(resources.getString(R.string.gls_context_tester_title), tmp); - } - case 5: { // health - try { - tmp = resources.getStringArray(R.array.gls_context_health)[record.context.health]; - } catch (final ArrayIndexOutOfBoundsException e) { - tmp = resources.getStringArray(R.array.gls_context_health)[0]; - } - return new Pair<>(resources.getString(R.string.gls_context_health_title), tmp); - } - case 6: { // exercise duration and intensity - return new Pair<>(resources.getString(R.string.gls_context_exercise_title), resources.getString(R.string.gls_context_exercise, record.context.exerciseDuration, record.context.exerciseIntensity)); - } - case 7: { // medication ID and quantity - try { - tmp = resources.getStringArray(R.array.gls_context_medication_id)[record.context.medicationId]; - } catch (final ArrayIndexOutOfBoundsException e) { - tmp = resources.getStringArray(R.array.gls_context_medication_id)[0]; - } - final int resId = record.context.medicationUnit == GlucoseRecord.UNIT_kgpl ? R.string.gls_context_medication_kg : R.string.gls_context_medication_l; - return new Pair<>(resources.getString(R.string.gls_context_medication_title), resources.getString(resId, tmp, record.context.medicationQuantity)); - } - case 8: { // HbA1c value - return new Pair<>(resources.getString(R.string.gls_context_hba1c_title), resources.getString(R.string.gls_context_hba1c, record.context.HbA1c)); - } - default: - return new Pair<>("Not implemented", "The value exists but is not shown"); - } - } - - private int childIdToItemId(final int childPosition, final GlucoseRecord record) { - int itemId = 0; - int child = childPosition; - - // Location is required - if (itemId == childPosition) - return itemId; - - if (++itemId > 0 && record.status != 0 && --child == 0) return itemId; - if (record.context != null) { - if (++itemId > 0 && record.context.carbohydrateId != 0 && --child == 0) return itemId; - if (++itemId > 0 && record.context.meal != 0 && --child == 0) return itemId; - if (++itemId > 0 && record.context.tester != 0 && --child == 0) return itemId; - if (++itemId > 0 && record.context.health != 0 && --child == 0) return itemId; - if (++itemId > 0 && record.context.exerciseDuration != 0 && --child == 0) return itemId; - if (++itemId > 0 && record.context.medicationId != 0 && --child == 0) return itemId; - if (++itemId > 0 && record.context.HbA1c != 0 && --child == 0) return itemId; - } - throw new IllegalArgumentException("No item ID for position " + childPosition); - } - - @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 = view.findViewById(android.R.id.text1); - holder.details = 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 deleted file mode 100644 index 2528a37..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseActivity.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.os.Bundle; -import androidx.annotation.NonNull; -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; - -import java.util.UUID; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileExpandableListActivity; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; - -// TODO The GlucoseActivity should be rewritten to use the service approach, like other do. -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; - private TextView mBatteryLevelView; - - @Override - protected void onCreateView(final Bundle savedInstanceState) { - setContentView(R.layout.activity_feature_gls); - setGUI(); - } - - private void setGUI() { - mUnitView = findViewById(R.id.unit); - mControlPanelStd = findViewById(R.id.gls_control_std); - mControlPanelAbort = findViewById(R.id.gls_control_abort); - mBatteryLevelView = findViewById(R.id.battery); - - findViewById(R.id.action_last).setOnClickListener(v -> mGlucoseManager.getLastRecord()); - findViewById(R.id.action_all).setOnClickListener(v -> mGlucoseManager.getAllRecords()); - findViewById(R.id.action_abort).setOnClickListener(v -> mGlucoseManager.abort()); - - // create popup menu attached to the button More - findViewById(R.id.action_more).setOnClickListener(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 LoggableBleManager initializeManager() { - GlucoseManager manager = mGlucoseManager = GlucoseManager.getGlucoseManager(getApplicationContext()); - 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 getLoggerProfileTitle() { - return R.string.gls_feature_title; - } - - @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(); - mBatteryLevelView.setText(R.string.not_available); - } - - private void setOperationInProgress(final boolean progress) { - runOnUiThread(() -> { - mControlPanelStd.setVisibility(!progress ? View.VISIBLE : View.GONE); - mControlPanelAbort.setVisibility(progress ? View.VISIBLE : View.GONE); - }); - } - - @Override - public void onDeviceDisconnected(@NonNull final BluetoothDevice device) { - super.onDeviceDisconnected(device); - setOperationInProgress(false); - runOnUiThread(() -> mBatteryLevelView.setText(R.string.not_available)); - } - - @Override - public void onOperationStarted(final BluetoothDevice device) { - setOperationInProgress(true); - } - - @Override - public void onOperationCompleted(final BluetoothDevice device) { - setOperationInProgress(false); - - runOnUiThread(() -> { - 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 onOperationAborted(final BluetoothDevice device) { - setOperationInProgress(false); - } - - @Override - public void onOperationNotSupported(final BluetoothDevice device) { - setOperationInProgress(false); - showToast(R.string.gls_operation_not_supported); - } - - @Override - public void onOperationFailed(final BluetoothDevice device) { - setOperationInProgress(false); - showToast(R.string.gls_operation_failed); - } - - @Override - public void onDatasetChanged(final BluetoothDevice device) { - // Do nothing. Refreshing the list is done in onOperationCompleted - } - - @Override - public void onNumberOfRecordsRequested(final BluetoothDevice device, final int value) { - if (value == 0) - showToast(R.string.gls_progress_zero); - else - showToast(getResources().getQuantityString(R.plurals.gls_progress, value, value)); - } - - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - runOnUiThread(() -> mBatteryLevelView.setText(getString(R.string.battery, batteryLevel))); - } -} 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 deleted file mode 100644 index 6c8ad25..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManager.java +++ /dev/null @@ -1,407 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import android.os.Handler; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.util.Log; -import android.util.SparseArray; - -import java.util.Calendar; -import java.util.UUID; - -import no.nordicsemi.android.ble.common.callback.RecordAccessControlPointDataCallback; -import no.nordicsemi.android.ble.common.callback.glucose.GlucoseMeasurementContextDataCallback; -import no.nordicsemi.android.ble.common.callback.glucose.GlucoseMeasurementDataCallback; -import no.nordicsemi.android.ble.common.data.RecordAccessControlPointData; -import no.nordicsemi.android.ble.data.Data; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; -import no.nordicsemi.android.nrftoolbox.parser.GlucoseMeasurementContextParser; -import no.nordicsemi.android.nrftoolbox.parser.GlucoseMeasurementParser; -import no.nordicsemi.android.nrftoolbox.parser.RecordAccessControlPointParser; -import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; - -@SuppressWarnings("unused") -public class GlucoseManager extends BatteryManager { - private static final String TAG = "GlucoseManager"; - - /** Glucose service UUID */ - public final static UUID GLS_SERVICE_UUID = UUID.fromString("00001808-0000-1000-8000-00805f9b34fb"); - /** Glucose Measurement characteristic UUID */ - private final static UUID GM_CHARACTERISTIC = UUID.fromString("00002A18-0000-1000-8000-00805f9b34fb"); - /** Glucose Measurement Context characteristic UUID */ - private final static UUID GM_CONTEXT_CHARACTERISTIC = UUID.fromString("00002A34-0000-1000-8000-00805f9b34fb"); - /** Glucose Feature characteristic UUID */ - private final static UUID GF_CHARACTERISTIC = UUID.fromString("00002A51-0000-1000-8000-00805f9b34fb"); - /** Record Access Control Point characteristic UUID */ - private final static UUID RACP_CHARACTERISTIC = UUID.fromString("00002A52-0000-1000-8000-00805f9b34fb"); - - private BluetoothGattCharacteristic mGlucoseMeasurementCharacteristic; - private BluetoothGattCharacteristic mGlucoseMeasurementContextCharacteristic; - private BluetoothGattCharacteristic mRecordAccessControlPointCharacteristic; - - private final SparseArray mRecords = new SparseArray<>(); - private Handler mHandler; - private static GlucoseManager mInstance; - - /** - * Returns the singleton implementation of GlucoseManager. - */ - public static GlucoseManager getGlucoseManager(final Context context) { - if (mInstance == null) - mInstance = new GlucoseManager(context); - return mInstance; - } - - private GlucoseManager(final Context context) { - super(context); - mHandler = new Handler(); - } - - @NonNull - @Override - protected BatteryManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving notification, etc. - */ - private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { - - @Override - protected void initialize() { - super.initialize(); - - // The gatt.setCharacteristicNotification(...) method is called in BleManager during - // enabling notifications or indications - // (see BleManager#internalEnableNotifications/Indications). - // However, on Samsung S3 with Android 4.3 it looks like the 2 gatt calls - // (gatt.setCharacteristicNotification(...) and gatt.writeDescriptor(...)) are called - // too quickly, or from a wrong thread, and in result the notification listener is not - // set, causing onCharacteristicChanged(...) callback never being called when a - // notification comes. Enabling them here, like below, solves the problem. - // However... the original approach works for the Battery Level CCCD, which makes it - // even weirder. - /* - gatt.setCharacteristicNotification(mGlucoseMeasurementCharacteristic, true); - if (mGlucoseMeasurementContextCharacteristic != null) { - device.setCharacteristicNotification(mGlucoseMeasurementContextCharacteristic, true); - } - device.setCharacteristicNotification(mRecordAccessControlPointCharacteristic, true); - */ - setNotificationCallback(mGlucoseMeasurementCharacteristic) - .with(new GlucoseMeasurementDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + GlucoseMeasurementParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onGlucoseMeasurementReceived(@NonNull final BluetoothDevice device, final int sequenceNumber, - @NonNull final Calendar time, @Nullable final Float glucoseConcentration, - @Nullable final Integer unit, @Nullable final Integer type, - @Nullable final Integer sampleLocation, @Nullable final GlucoseStatus status, - final boolean contextInformationFollows) { - final GlucoseRecord record = new GlucoseRecord(); - record.sequenceNumber = sequenceNumber; - record.time = time; - record.glucoseConcentration = glucoseConcentration != null ? glucoseConcentration : 0; - record.unit = unit != null ? unit : UNIT_kg_L; - record.type = type != null ? type : 0; - record.sampleLocation = sampleLocation != null ? sampleLocation : 0; - record.status = status != null ? status.value : 0; - - // insert the new record to storage - mRecords.put(record.sequenceNumber, record); - mHandler.post(() -> { - // if there is no context information following the measurement data, - // notify callback about the new record - if (!contextInformationFollows) - mCallbacks.onDatasetChanged(device); - }); - } - }); - - setNotificationCallback(mGlucoseMeasurementContextCharacteristic) - .with(new GlucoseMeasurementContextDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + GlucoseMeasurementContextParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onGlucoseMeasurementContextReceived(@NonNull final BluetoothDevice device, final int sequenceNumber, - @Nullable final Carbohydrate carbohydrate, @Nullable final Float carbohydrateAmount, - @Nullable final Meal meal, @Nullable final Tester tester, - @Nullable final Health health, @Nullable final Integer exerciseDuration, - @Nullable final Integer exerciseIntensity, @Nullable final Medication medication, - @Nullable final Float medicationAmount, @Nullable final Integer medicationUnit, - @Nullable final Float HbA1c) { - 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; - context.carbohydrateId = carbohydrate != null ? carbohydrate.value : 0; - context.carbohydrateUnits = carbohydrateAmount != null ? carbohydrateAmount : 0; - context.meal = meal != null ? meal.value : 0; - context.tester = tester != null ? tester.value : 0; - context.health = health != null ? health.value : 0; - context.exerciseDuration = exerciseDuration != null ? exerciseDuration : 0; - context.exerciseIntensity = exerciseIntensity != null ? exerciseIntensity : 0; - context.medicationId = medication != null ? medication.value : 0; - context.medicationQuantity = medicationAmount != null ? medicationAmount : 0; - context.medicationUnit = medicationUnit != null ? medicationUnit : UNIT_mg; - context.HbA1c = HbA1c != null ? HbA1c : 0; - - mHandler.post(() -> { - // notify callback about the new record - mCallbacks.onDatasetChanged(device); - }); - } - }); - - setIndicationCallback(mRecordAccessControlPointCharacteristic) - .with(new RecordAccessControlPointDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onRecordAccessOperationCompleted(@NonNull final BluetoothDevice device, final int requestCode) { - switch (requestCode) { - case RACP_OP_CODE_ABORT_OPERATION: - mCallbacks.onOperationAborted(device); - break; - default: - mCallbacks.onOperationCompleted(device); - break; - } - } - - @Override - public void onRecordAccessOperationCompletedWithNoRecordsFound(@NonNull final BluetoothDevice device, final int requestCode) { - mCallbacks.onOperationCompleted(device); - } - - @Override - public void onNumberOfRecordsReceived(@NonNull final BluetoothDevice device, final int numberOfRecords) { - mCallbacks.onNumberOfRecordsRequested(device, numberOfRecords); - if (numberOfRecords > 0) { - if (mRecords.size() > 0) { - final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1; - writeCharacteristic(mRecordAccessControlPointCharacteristic, - RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber)) - .enqueue(); - } else { - writeCharacteristic(mRecordAccessControlPointCharacteristic, - RecordAccessControlPointData.reportAllStoredRecords()) - .enqueue(); - } - } else { - mCallbacks.onOperationCompleted(device); - } - } - - @Override - public void onRecordAccessOperationError(@NonNull final BluetoothDevice device, - final int requestCode, final int errorCode) { - log(Log.WARN, "Record Access operation failed (error " + errorCode + ")"); - if (errorCode == RACP_ERROR_OP_CODE_NOT_SUPPORTED) { - mCallbacks.onOperationNotSupported(device); - } else { - mCallbacks.onOperationFailed(device); - } - } - }); - - enableNotifications(mGlucoseMeasurementCharacteristic).enqueue(); - enableNotifications(mGlucoseMeasurementContextCharacteristic).enqueue(); - enableIndications(mRecordAccessControlPointCharacteristic) - .fail((device, status) -> log(Log.WARN, "Failed to enabled Record Access Control Point indications (error " + status + ")")) - .enqueue(); - } - - @Override - public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - final BluetoothGattService service = gatt.getService(GLS_SERVICE_UUID); - if (service != null) { - mGlucoseMeasurementCharacteristic = service.getCharacteristic(GM_CHARACTERISTIC); - mGlucoseMeasurementContextCharacteristic = service.getCharacteristic(GM_CONTEXT_CHARACTERISTIC); - mRecordAccessControlPointCharacteristic = service.getCharacteristic(RACP_CHARACTERISTIC); - } - return mGlucoseMeasurementCharacteristic != null && mRecordAccessControlPointCharacteristic != null; - } - - @Override - protected boolean isOptionalServiceSupported(@NonNull BluetoothGatt gatt) { - super.isOptionalServiceSupported(gatt); - return mGlucoseMeasurementContextCharacteristic != null; - } - - @Override - protected void onDeviceDisconnected() { - mGlucoseMeasurementCharacteristic = null; - mGlucoseMeasurementContextCharacteristic = null; - mRecordAccessControlPointCharacteristic = null; - } - }; - - /** - * Returns all records as a sparse array where sequence number is the key. - * - * @return the records list. - */ - public SparseArray getRecords() { - return mRecords; - } - - /** - * Clears the records list locally. - */ - public void clear() { - mRecords.clear(); - mCallbacks.onOperationCompleted(getBluetoothDevice()); - } - - /** - * 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 Success or other in case of error. - */ - public void getLastRecord() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - clear(); - mCallbacks.onOperationStarted(getBluetoothDevice()); - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportLastStoredRecord()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } - - /** - * 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 Success or other in case of error. - */ - public void getFirstRecord() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - clear(); - mCallbacks.onOperationStarted(getBluetoothDevice()); - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportFirstStoredRecord()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } - - /** - * Sends the request to obtain all records from glucose device. Initially we want to notify user - * about the number of the records so the 'Report Number of Stored 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 Success or other in case of error. - */ - public void getAllRecords() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - clear(); - mCallbacks.onOperationStarted(getBluetoothDevice()); - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.reportNumberOfAllStoredRecords()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } - - /** - * 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 Success - * or other in case of error. - *

- * Refresh button will not download records older than the oldest in the local memory. - * E.g. 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 (mRecordAccessControlPointCharacteristic == null) - return; - - if (mRecords.size() == 0) { - getAllRecords(); - } else { - mCallbacks.onOperationStarted(getBluetoothDevice()); - - // obtain the last sequence number - final int sequenceNumber = mRecords.keyAt(mRecords.size() - 1) + 1; - - writeCharacteristic(mRecordAccessControlPointCharacteristic, - RecordAccessControlPointData.reportStoredRecordsGreaterThenOrEqualTo(sequenceNumber)) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - // 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 (mRecordAccessControlPointCharacteristic == null) - return; - - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.abortOperation()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } - - /** - * Sends the request to delete all data from the device. A Record Access Control Point - * indication with status code Success (or other in case of error) will be send. - */ - public void deleteAllRecords() { - if (mRecordAccessControlPointCharacteristic == null) - return; - - clear(); - mCallbacks.onOperationStarted(getBluetoothDevice()); - writeCharacteristic(mRecordAccessControlPointCharacteristic, RecordAccessControlPointData.deleteAllStoredRecords()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, "\"" + RecordAccessControlPointParser.parse(data) + "\" sent")) - .enqueue(); - } -} 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 deleted file mode 100644 index dff848f..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseManagerCallbacks.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; - -import no.nordicsemi.android.ble.BleManagerCallbacks; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; - -public interface GlucoseManagerCallbacks extends BatteryManagerCallbacks { - - void onOperationStarted(final BluetoothDevice device); - - void onOperationCompleted(final BluetoothDevice device); - - void onOperationFailed(final BluetoothDevice device); - - void onOperationAborted(final BluetoothDevice device); - - void onOperationNotSupported(final BluetoothDevice device); - - void onDatasetChanged(final BluetoothDevice device); - - void onNumberOfRecordsRequested(final BluetoothDevice device, 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 deleted file mode 100644 index f83c173..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/gls/GlucoseRecord.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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 deleted file mode 100644 index da5ec71..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSActivity.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.content.Intent; -import android.graphics.Point; -import android.os.Bundle; -import android.os.Handler; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.achartengine.GraphicalView; - -import java.util.List; -import java.util.UUID; - -import no.nordicsemi.android.nrftoolbox.FeaturesActivity; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileActivity; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; - -/** - * 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. - */ -// TODO The HRSActivity should be rewritten to use the service approach, like other do. -public class HRSActivity extends BleProfileActivity implements HRSManagerCallbacks { - @SuppressWarnings("unused") - private final String TAG = "HRSActivity"; - - private final static String GRAPH_STATUS = "graph_status"; - private final static String GRAPH_COUNTER = "graph_counter"; - private final static String HR_VALUE = "hr_value"; - - private final static 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 TextView mBatteryLevelView; - - private int mHrmValue = 0; - private int mCounter = 0; - - @Override - protected void onCreateView(final Bundle savedInstanceState) { - setContentView(R.layout.activity_feature_hrs); - setGUI(); - } - - private void setGUI() { - mLineGraph = LineGraphView.getLineGraphView(); - mHRSValue = findViewById(R.id.text_hrs_value); - mHRSPosition = findViewById(R.id.text_hrs_position); - mBatteryLevelView = findViewById(R.id.battery); - showGraph(); - } - - private void showGraph() { - mGraphView = mLineGraph.getView(this); - ViewGroup layout = findViewById(R.id.graph_hrs); - layout.addView(mGraphView); - } - - @Override - protected void onStart() { - super.onStart(); - - final Intent intent = getIntent(); - if (!isDeviceConnected() && intent.hasExtra(FeaturesActivity.EXTRA_ADDRESS)) { - final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); - final BluetoothDevice device = bluetoothAdapter.getRemoteDevice(getIntent().getByteArrayExtra(FeaturesActivity.EXTRA_ADDRESS)); - onDeviceSelected(device, device.getName()); - - intent.removeExtra(FeaturesActivity.EXTRA_APP); - intent.removeExtra(FeaturesActivity.EXTRA_ADDRESS); - } - } - - @Override - protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - - isGraphInProgress = savedInstanceState.getBoolean(GRAPH_STATUS); - mCounter = savedInstanceState.getInt(GRAPH_COUNTER); - mHrmValue = savedInstanceState.getInt(HR_VALUE); - - if (isGraphInProgress) - startShowGraph(); - } - - @Override - protected void onSaveInstanceState(final 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 getLoggerProfileTitle() { - return R.string.hrs_feature_title; - } - - @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 LoggableBleManager initializeManager() { - final HRSManager manager = HRSManager.getInstance(getApplicationContext()); - manager.setGattCallbacks(this); - return manager; - } - - @Override - public void onServicesDiscovered(@NonNull final BluetoothDevice device, final boolean optionalServicesFound) { - // this may notify user or show some views - } - - @Override - public void onDeviceReady(@NonNull final BluetoothDevice device) { - startShowGraph(); - } - - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - runOnUiThread(() -> mBatteryLevelView.setText(getString(R.string.battery, batteryLevel))); - } - - @Override - public void onBodySensorLocationReceived(@NonNull final BluetoothDevice device, final int sensorLocation) { - runOnUiThread(() -> { - if (sensorLocation >= SENSOR_LOCATION_FIRST && sensorLocation <= SENSOR_LOCATION_LAST) { - mHRSPosition.setText(getResources().getStringArray(R.array.hrs_locations)[sensorLocation]); - } else { - mHRSPosition.setText(R.string.hrs_location_other); - } - }); - } - - @Override - public void onHeartRateMeasurementReceived(@NonNull final BluetoothDevice device, final int heartRate, - @Nullable final Boolean contactDetected, - @Nullable final Integer energyExpanded, - @Nullable final List rrIntervals) { - mHrmValue = heartRate; - runOnUiThread(() -> mHRSValue.setText(getString(R.string.hrs_value, heartRate))); - } - - @Override - public void onDeviceDisconnected(@NonNull final BluetoothDevice device) { - super.onDeviceDisconnected(device); - runOnUiThread(() -> { - mHRSValue.setText(R.string.not_available_value); - mHRSPosition.setText(R.string.not_available); - mBatteryLevelView.setText(R.string.not_available); - stopShowGraph(); - }); - } - - @Override - protected void setDefaultUI() { - mHRSValue.setText(R.string.not_available_value); - mHRSPosition.setText(R.string.not_available); - mBatteryLevelView.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 deleted file mode 100644 index 861d640..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManager.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import android.util.Log; - -import java.util.List; -import java.util.UUID; - -import no.nordicsemi.android.ble.common.callback.hr.BodySensorLocationDataCallback; -import no.nordicsemi.android.ble.common.callback.hr.HeartRateMeasurementDataCallback; -import no.nordicsemi.android.ble.data.Data; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; -import no.nordicsemi.android.nrftoolbox.parser.BodySensorLocationParser; -import no.nordicsemi.android.nrftoolbox.parser.HeartRateMeasurementParser; - -/** - * HRSManager class performs BluetoothGatt operations for connection, service discovery, - * enabling notification and reading characteristics. - * All operations required to connect to device with BLE Heart Rate Service and reading - * heart rate values are performed here. - */ -public class HRSManager extends BatteryManager { - static final UUID HR_SERVICE_UUID = UUID.fromString("0000180D-0000-1000-8000-00805f9b34fb"); - private static final UUID BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID = UUID.fromString("00002A38-0000-1000-8000-00805f9b34fb"); - private static final UUID HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A37-0000-1000-8000-00805f9b34fb"); - - private BluetoothGattCharacteristic mHeartRateCharacteristic, mBodySensorLocationCharacteristic; - - private static HRSManager managerInstance = null; - - /** - * Singleton implementation of HRSManager class. - */ - public static synchronized HRSManager getInstance(final Context context) { - if (managerInstance == null) { - managerInstance = new HRSManager(context); - } - return managerInstance; - } - - private HRSManager(final Context context) { - super(context); - } - - @NonNull - @Override - protected BatteryManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving notification, etc. - */ - private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { - - @Override - protected void initialize() { - super.initialize(); - readCharacteristic(mBodySensorLocationCharacteristic) - .with(new BodySensorLocationDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + BodySensorLocationParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onBodySensorLocationReceived(@NonNull final BluetoothDevice device, - final int sensorLocation) { - mCallbacks.onBodySensorLocationReceived(device, sensorLocation); - } - }) - .fail((device, status) -> log(Log.WARN, "Body Sensor Location characteristic not found")) - .enqueue(); - setNotificationCallback(mHeartRateCharacteristic) - .with(new HeartRateMeasurementDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + HeartRateMeasurementParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onHeartRateMeasurementReceived(@NonNull final BluetoothDevice device, - final int heartRate, - @Nullable final Boolean contactDetected, - @Nullable final Integer energyExpanded, - @Nullable final List rrIntervals) { - mCallbacks.onHeartRateMeasurementReceived(device, heartRate, contactDetected, energyExpanded, rrIntervals); - } - }); - enableNotifications(mHeartRateCharacteristic).enqueue(); - } - - @Override - protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - final BluetoothGattService service = gatt.getService(HR_SERVICE_UUID); - if (service != null) { - mHeartRateCharacteristic = service.getCharacteristic(HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID); - } - return mHeartRateCharacteristic != null; - } - - @Override - protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { - super.isOptionalServiceSupported(gatt); - final BluetoothGattService service = gatt.getService(HR_SERVICE_UUID); - if (service != null) { - mBodySensorLocationCharacteristic = service.getCharacteristic(BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID); - } - return mBodySensorLocationCharacteristic != null; - } - - @Override - protected void onDeviceDisconnected() { - super.onDeviceDisconnected(); - mBodySensorLocationCharacteristic = null; - mHeartRateCharacteristic = 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 deleted file mode 100644 index 79f1870..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/HRSManagerCallbacks.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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.ble.common.profile.hr.BodySensorLocationCallback; -import no.nordicsemi.android.ble.common.profile.hr.HeartRateMeasurementCallback; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; - -interface HRSManagerCallbacks extends BatteryManagerCallbacks, BodySensorLocationCallback, HeartRateMeasurementCallback { - -} 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 deleted file mode 100644 index b3844c6..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hrs/LineGraphView.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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 android.content.Context; -import android.graphics.Color; -import android.graphics.Paint.Align; -import android.graphics.Point; - -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; - -/** - * 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 deleted file mode 100644 index 59626cb..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSActivity.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.PreferenceManager; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import android.view.Menu; -import android.widget.TextView; - -import java.util.UUID; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.hts.settings.SettingsActivity; -import no.nordicsemi.android.nrftoolbox.hts.settings.SettingsFragment; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; - -/** - * 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 mTempValue; - private TextView mUnit; - private TextView mBatteryLevelView; - - @Override - protected void onCreateView(final 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() { - mTempValue = findViewById(R.id.text_hts_value); - mUnit = findViewById(R.id.text_hts_unit); - mBatteryLevelView = findViewById(R.id.battery); - } - - @Override - protected void onResume() { - super.onResume(); - setUnits(); - } - - @Override - protected void setDefaultUI() { - mTempValue.setText(R.string.not_available_value); - mBatteryLevelView.setText(R.string.not_available); - - setUnits(); - } - - private void setUnits() { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT))); - - switch (unit) { - case SettingsFragment.SETTINGS_UNIT_C: - mUnit.setText(R.string.hts_unit_celsius); - break; - case SettingsFragment.SETTINGS_UNIT_F: - mUnit.setText(R.string.hts_unit_fahrenheit); - break; - case SettingsFragment.SETTINGS_UNIT_K: - mUnit.setText(R.string.hts_unit_kelvin); - break; - } - } - - @Override - protected void onServiceBound(final HTSService.HTSBinder binder) { - onTemperatureMeasurementReceived(binder.getTemperature()); - } - - @Override - protected void onServiceUnbound() { - // not used - } - - @Override - protected int getLoggerProfileTitle() { - return R.string.hts_feature_title; - } - - @Override - protected int getAboutTextId() { - return R.string.hts_about_text; - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.settings_and_about, 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 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(final BluetoothDevice device, boolean optionalServicesFound) { - // this may notify user or show some views - } - - @Override - public void onDeviceDisconnected(final BluetoothDevice device) { - super.onDeviceDisconnected(device); - mBatteryLevelView.setText(R.string.not_available); - } - - private void onTemperatureMeasurementReceived(Float value) { - if (value != null) { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, - String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT))); - - switch (unit) { - case SettingsFragment.SETTINGS_UNIT_F: - value = value * 1.8f + 32f; - break; - case SettingsFragment.SETTINGS_UNIT_K: - value += 273.15f; - break; - case SettingsFragment.SETTINGS_UNIT_C: - break; - } - mTempValue.setText(getString(R.string.hts_value, value)); - } else { - mTempValue.setText(R.string.not_available_value); - } - } - - public void onBatteryLevelChanged(final int value) { - mBatteryLevelView.setText(getString(R.string.battery, 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 float value = intent.getFloatExtra(HTSService.EXTRA_TEMPERATURE, 0.0f); - // Update GUI - onTemperatureMeasurementReceived(value); - } else if (HTSService.BROADCAST_BATTERY_LEVEL.equals(action)) { - final int batteryLevel = intent.getIntExtra(HTSService.EXTRA_BATTERY_LEVEL, 0); - // Update GUI - onBatteryLevelChanged(batteryLevel); - } - } - }; - - private static IntentFilter makeIntentFilter() { - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(HTSService.BROADCAST_HTS_MEASUREMENT); - intentFilter.addAction(HTSService.BROADCAST_BATTERY_LEVEL); - 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 deleted file mode 100644 index 732d616..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManager.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.Calendar; -import java.util.UUID; - -import no.nordicsemi.android.ble.common.callback.ht.TemperatureMeasurementDataCallback; -import no.nordicsemi.android.ble.data.Data; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; -import no.nordicsemi.android.nrftoolbox.parser.TemperatureMeasurementParser; - -/** - * 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 extends BatteryManager { - /** Health Thermometer service UUID */ - public final static UUID HT_SERVICE_UUID = UUID.fromString("00001809-0000-1000-8000-00805f9b34fb"); - /** Health Thermometer Measurement characteristic UUID */ - private static final UUID HT_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A1C-0000-1000-8000-00805f9b34fb"); - - private BluetoothGattCharacteristic mHTCharacteristic; - - HTSManager(final Context context) { - super(context); - } - - @NonNull - @Override - protected BatteryManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving indication, etc.. - */ - private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { - @Override - protected void initialize() { - super.initialize(); - setIndicationCallback(mHTCharacteristic) - .with(new TemperatureMeasurementDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + TemperatureMeasurementParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onTemperatureMeasurementReceived(@NonNull final BluetoothDevice device, - final float temperature, final int unit, - @Nullable final Calendar calendar, - @Nullable final Integer type) { - mCallbacks.onTemperatureMeasurementReceived(device, temperature, unit, calendar, type); - } - }); - enableIndications(mHTCharacteristic).enqueue(); - } - - @Override - protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - final BluetoothGattService service = gatt.getService(HT_SERVICE_UUID); - if (service != null) { - mHTCharacteristic = service.getCharacteristic(HT_MEASUREMENT_CHARACTERISTIC_UUID); - } - return mHTCharacteristic != null; - } - - @Override - protected void onDeviceDisconnected() { - super.onDeviceDisconnected(); - 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 deleted file mode 100644 index c8053b0..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSManagerCallbacks.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.ble.common.profile.ht.TemperatureMeasurementCallback; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; - -/** - * Interface {@link HTSManagerCallbacks} must be implemented by {@link HTSActivity} in order - * to receive callbacks from {@link HTSManager}. - */ -interface HTSManagerCallbacks extends BatteryManagerCallbacks, TemperatureMeasurementCallback { - -} 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 deleted file mode 100644 index 811740e..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/HTSService.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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 android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.app.NotificationCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; - -import java.util.Calendar; - -import no.nordicsemi.android.ble.common.profile.ht.TemperatureMeasurementCallback; -import no.nordicsemi.android.log.Logger; -import no.nordicsemi.android.nrftoolbox.FeaturesActivity; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; - -@SuppressWarnings("FieldCanBeLocal") -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"; - - public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL"; - public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL"; - - 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; - /** The last received temperature value in Celsius degrees. */ - private Float mTemp; - - @SuppressWarnings("unused") - private HTSManager mManager; - - private final LocalBinder mBinder = new HTSBinder(); - - /** - * This local binder is an interface for the bonded activity to operate with the HTS sensor - */ - class HTSBinder extends LocalBinder { - /** - * Returns the last received temperature value. - * - * @return Temperature value in Celsius. - */ - Float getTemperature() { - return mTemp; - } - } - - @Override - protected LocalBinder getBinder() { - return mBinder; - } - - @Override - protected LoggableBleManager initializeManager() { - return mManager = new HTSManager(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 - protected void onRebind() { - // when the activity rebinds to the service, remove the notification - cancelNotification(); - } - - @Override - protected void onUnbind() { - // when the activity closes we need to show the notification that user is connected to the sensor - createNotification(R.string.hts_notification_connected_message, 0); - } - - @Override - public void onDeviceDisconnected(final BluetoothDevice device) { - super.onDeviceDisconnected(device); - mTemp = null; - } - - @Override - public void onTemperatureMeasurementReceived(@NonNull final BluetoothDevice device, - final float temperature, final int unit, - @Nullable final Calendar calendar, - @Nullable final Integer type) { - mTemp = TemperatureMeasurementCallback.toCelsius(temperature, unit); - - final Intent broadcast = new Intent(BROADCAST_HTS_MEASUREMENT); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_TEMPERATURE, mTemp); - // ignore the rest - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - - if (!mBound) { - // Here we may update the notification to display the current temperature. - // TODO modify the notification here - } - } - - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel); - 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 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, 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 AndroidManifest.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 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL); - builder.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(new NotificationCompat.Action(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(), "[Notification] Disconnect action pressed"); - if (isConnected()) - getBinder().disconnect(); - else - stopSelf(); - } - }; -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/settings/SettingsActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/settings/SettingsActivity.java deleted file mode 100644 index 30065d7..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/settings/SettingsActivity.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.settings; - -import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import android.view.MenuItem; - -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsActivity extends AppCompatActivity { - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_settings); - - final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - // Display the fragment as the main content. - getSupportFragmentManager().beginTransaction().replace(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/hts/settings/SettingsFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/settings/SettingsFragment.java deleted file mode 100644 index 27bd3d7..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/hts/settings/SettingsFragment.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.settings; - -import android.os.Bundle; -import android.preference.PreferenceFragment; - -import androidx.preference.PreferenceFragmentCompat; -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsFragment extends PreferenceFragmentCompat { - public static final String SETTINGS_UNIT = "settings_hts_unit"; - public static final int SETTINGS_UNIT_C = 0; // [C] - public static final int SETTINGS_UNIT_F = 1; // [F] - public static final int SETTINGS_UNIT_K = 2; // [K] - public static final int SETTINGS_UNIT_DEFAULT = SETTINGS_UNIT_C; - - @Override - public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { - addPreferencesFromResource(R.xml.settings_hts); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/AlertLevelParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/AlertLevelParser.java deleted file mode 100644 index 68ff78b..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/AlertLevelParser.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.parser; - -import android.bluetooth.BluetoothGattCharacteristic; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class AlertLevelParser { - public static String parse(final BluetoothGattCharacteristic characteristic) { - return parse(Data.from(characteristic)); - } - - /** - * Parses the alert level. - * - * @param data - * @return alert level in human readable format - */ - public static String parse(final Data data) { - final int value = data.getIntValue(Data.FORMAT_UINT8, 0); - - switch (value) { - case 0: - return "No Alert"; - case 1: - return "Mild Alert"; - case 2: - return "High Alert"; - default: - return "Reserved value (" + value + ")"; - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/BloodPressureMeasurementParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/BloodPressureMeasurementParser.java deleted file mode 100644 index 9351730..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/BloodPressureMeasurementParser.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class BloodPressureMeasurementParser { - - public static String parse(final Data data) { - final StringBuilder builder = new StringBuilder(); - - // first byte - flags - int offset = 0; - final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); - - final int unitType = flags & 0x01; - final boolean timestampPresent = (flags & 0x02) > 0; - final boolean pulseRatePresent = (flags & 0x04) > 0; - final boolean userIdPresent = (flags & 0x08) > 0; - final boolean statusPresent = (flags & 0x10) > 0; - - // following bytes - systolic, diastolic and mean arterial pressure - final float systolic = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - final float diastolic = data.getFloatValue(Data.FORMAT_SFLOAT, offset + 2); - final float meanArterialPressure = data.getFloatValue(Data.FORMAT_SFLOAT, offset + 4); - final String unit = unitType == 0 ? " mmHg" : " kPa"; - offset += 6; - builder.append("Systolic: ").append(systolic).append(unit); - builder.append("\nDiastolic: ").append(diastolic).append(unit); - builder.append("\nMean AP: ").append(meanArterialPressure).append(unit); - - // parse timestamp if present - if (timestampPresent) { - builder.append("\nTimestamp: ").append(DateTimeParser.parse(data, offset)); - offset += 7; - } - - // parse pulse rate if present - if (pulseRatePresent) { - final float pulseRate = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - offset += 2; - builder.append("\nPulse: ").append(pulseRate).append(" bpm"); - } - - if (userIdPresent) { - final int userId = data.getIntValue(Data.FORMAT_UINT8, offset); - offset += 1; - builder.append("\nUser ID: ").append(userId); - } - - if (statusPresent) { - final int status = data.getIntValue(Data.FORMAT_UINT16, offset); - // offset += 2; - if ((status & 0x0001) > 0) - builder.append("\nBody movement detected"); - if ((status & 0x0002) > 0) - builder.append("\nCuff too lose"); - if ((status & 0x0004) > 0) - builder.append("\nIrregular pulse detected"); - if ((status & 0x0018) == 0x0008) - builder.append("\nPulse rate exceeds upper limit"); - if ((status & 0x0018) == 0x0010) - builder.append("\nPulse rate is less than lower limit"); - if ((status & 0x0018) == 0x0018) - builder.append("\nPulse rate range: Reserved for future use "); - if ((status & 0x0020) > 0) - builder.append("\nImproper measurement position"); - } - - return builder.toString(); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/BodySensorLocationParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/BodySensorLocationParser.java deleted file mode 100644 index 22d1731..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/BodySensorLocationParser.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class BodySensorLocationParser { - - public static String parse(final Data data) { - final int value = data.getIntValue(Data.FORMAT_UINT8, 0); - - switch (value) { - case 6: return "Foot"; - case 5: return "Ear Lobe"; - case 4: return "Hand"; - case 3: return "Finger"; - case 2: return "Wrist"; - case 1: return "Chest"; - case 0: - default: return "Other"; - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CGMMeasurementParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CGMMeasurementParser.java deleted file mode 100644 index 6c9c807..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CGMMeasurementParser.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * 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.parser; - -import java.util.Locale; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class CGMMeasurementParser { - private static final int FLAGS_CGM_TREND_INFO_PRESENT = 1; - private static final int FLAGS_CGM_QUALITY_PRESENT = 1 << 1; - private static final int FLAGS_SENSOR_STATUS_ANNUNCIATION_WARNING_OCTET_PRESENT = 1 << 2; - private static final int FLAGS_SENSOR_STATUS_ANNUNCIATION_CAL_TEMP_OCTET_PRESENT = 1 << 3; - private static final int FLAGS_SENSOR_STATUS_ANNUNCIATION_STATUS_OCTET_PRESENT = 1 << 4; - - private static final int SSA_SESSION_STOPPED = 1; - private static final int SSA_DEVICE_BATTERY_LOW = 1 << 1; - private static final int SSA_SENSOR_TYPE_INCORRECT = 1 << 2; - private static final int SSA_SENSOR_MALFUNCTION = 1 << 3; - private static final int SSA_DEVICE_SPEC_ALERT = 1 << 4; - private static final int SSA_GENERAL_DEVICE_FAULT = 1 << 5; - - private static final int SSA_TIME_SYNC_REQUIRED = 1 << 8; - private static final int SSA_CALIBRATION_NOT_ALLOWED = 1 << 9; - private static final int SSA_CALIBRATION_RECOMMENDED = 1 << 10; - private static final int SSA_CALIBRATION_REQUIRED = 1 << 11; - private static final int SSA_SENSOR_TEMP_TOO_HIGH = 1 << 12; - private static final int SSA_SENSOR_TEMP_TOO_LOW = 1 << 13; - - private static final int SSA_RESULT_LOWER_THAN_PATIENT_LOW_LEVEL = 1 << 16; - private static final int SSA_RESULT_HIGHER_THAN_PATIENT_HIGH_LEVEL = 1 << 17; - private static final int SSA_RESULT_LOWER_THAN_HYPO_LEVEL = 1 << 18; - private static final int SSA_RESULT_HIGHER_THAN_HYPER_LEVEL = 1 << 19; - private static final int SSA_SENSOR_RATE_OF_DECREASE_EXCEEDED = 1 << 20; - private static final int SSA_SENSOR_RATE_OF_INCREASE_EXCEEDED = 1 << 21; - private static final int SSA_RESULT_LOWER_THAN_DEVICE_CAN_PROCESS = 1 << 22; - private static final int SSA_RESULT_HIGHER_THAN_DEVICE_CAN_PROCESS = 1 << 23; - - public static String parse(final Data data) { - // The CGM Measurement characteristic is a variable length structure containing one or more CGM Measurement records - int totalSize = data.getValue().length; - - final StringBuilder builder = new StringBuilder(); - int offset = 0; - while (offset < totalSize) { - offset += parseRecord(builder, data, offset); - if (offset < totalSize) - builder.append("\n\n"); - } - return builder.toString(); - } - - private static int parseRecord(final StringBuilder builder, final Data data, int offset) { - // Read size and flags bytes - final int size = data.getIntValue(Data.FORMAT_UINT8, offset++); - final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); - - /* - * false CGM Trend Information is not preset - * true CGM Trend Information is preset - */ - final boolean cgmTrendInformationPresent = (flags & FLAGS_CGM_TREND_INFO_PRESENT) > 0; - - /* - * false CGM Quality is not preset - * true CGM Quality is preset - */ - final boolean cgmQualityPresent = (flags & FLAGS_CGM_QUALITY_PRESENT) > 0; - - /* - * false Sensor Status Annunciation - Warning-Octet is not preset - * true Sensor Status Annunciation - Warning-Octet is preset - */ - final boolean ssaWarningOctetPresent = (flags & FLAGS_SENSOR_STATUS_ANNUNCIATION_WARNING_OCTET_PRESENT) > 0; - - /* - * false Sensor Status Annunciation - Calibration/Temp-Octet is not preset - * true Sensor Status Annunciation - Calibration/Temp-Octet is preset - */ - final boolean ssaCalTempOctetPresent = (flags & FLAGS_SENSOR_STATUS_ANNUNCIATION_CAL_TEMP_OCTET_PRESENT) > 0; - - /* - * false Sensor Status Annunciation - Status-Octet is not preset - * true Sensor Status Annunciation - Status-Octet is preset - */ - final boolean ssaStatusOctetPresent = (flags & FLAGS_SENSOR_STATUS_ANNUNCIATION_STATUS_OCTET_PRESENT) > 0; - - // Read CGM Glucose Concentration - final float glucoseConcentration = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - offset += 2; - - // Read time offset - final int timeOffset = data.getIntValue(Data.FORMAT_UINT16, offset); - offset += 2; - - builder.append("Glucose concentration: ").append(glucoseConcentration).append(" mg/dL\n"); - builder.append("Sequence number: ").append(timeOffset).append(" (Time Offset in min)\n"); - - if (ssaWarningOctetPresent) { - final int ssaWarningOctet = data.getIntValue(Data.FORMAT_UINT8, offset++); - builder.append("Warnings:\n"); - if ((ssaWarningOctet & SSA_SESSION_STOPPED) > 0) - builder.append("- Session Stopped\n"); - if ((ssaWarningOctet & SSA_DEVICE_BATTERY_LOW) > 0) - builder.append("- Device Battery Low\n"); - if ((ssaWarningOctet & SSA_SENSOR_TYPE_INCORRECT) > 0) - builder.append("- Sensor Type Incorrect\n"); - if ((ssaWarningOctet & SSA_SENSOR_MALFUNCTION) > 0) - builder.append("- Sensor Malfunction\n"); - if ((ssaWarningOctet & SSA_DEVICE_SPEC_ALERT) > 0) - builder.append("- Device Specific Alert\n"); - if ((ssaWarningOctet & SSA_GENERAL_DEVICE_FAULT) > 0) - builder.append("- General Device Fault\n"); - } - - if (ssaCalTempOctetPresent) { - final int ssaCalTempOctet = data.getIntValue(Data.FORMAT_UINT8, offset++); - builder.append("Cal/Temp Info:\n"); - if ((ssaCalTempOctet & SSA_TIME_SYNC_REQUIRED) > 0) - builder.append("- Time Synchronization Required\n"); - if ((ssaCalTempOctet & SSA_CALIBRATION_NOT_ALLOWED) > 0) - builder.append("- Calibration Not Allowed\n"); - if ((ssaCalTempOctet & SSA_CALIBRATION_RECOMMENDED) > 0) - builder.append("- Calibration Recommended\n"); - if ((ssaCalTempOctet & SSA_CALIBRATION_REQUIRED) > 0) - builder.append("- Calibration Required\n"); - if ((ssaCalTempOctet & SSA_SENSOR_TEMP_TOO_HIGH) > 0) - builder.append("- Sensor Temp Too High\n"); - if ((ssaCalTempOctet & SSA_SENSOR_TEMP_TOO_LOW) > 0) - builder.append("- Sensor Temp Too Low\n"); - } - - if (ssaStatusOctetPresent) { - final int ssaStatusOctet = data.getIntValue(Data.FORMAT_UINT8, offset++); - builder.append("Status:\n"); - if ((ssaStatusOctet & SSA_RESULT_LOWER_THAN_PATIENT_LOW_LEVEL) > 0) - builder.append("- Result Lower then Patient Low Level\n"); - if ((ssaStatusOctet & SSA_RESULT_HIGHER_THAN_PATIENT_HIGH_LEVEL) > 0) - builder.append("- Result Higher then Patient High Level\n"); - if ((ssaStatusOctet & SSA_RESULT_LOWER_THAN_HYPO_LEVEL) > 0) - builder.append("- Result Lower then Hypo Level\n"); - if ((ssaStatusOctet & SSA_RESULT_HIGHER_THAN_HYPER_LEVEL) > 0) - builder.append("- Result Higher then Hyper Level\n"); - if ((ssaStatusOctet & SSA_SENSOR_RATE_OF_DECREASE_EXCEEDED) > 0) - builder.append("- Sensor Rate of Decrease Exceeded\n"); - if ((ssaStatusOctet & SSA_SENSOR_RATE_OF_INCREASE_EXCEEDED) > 0) - builder.append("- Sensor Rate of Increase Exceeded\n"); - if ((ssaStatusOctet & SSA_RESULT_LOWER_THAN_DEVICE_CAN_PROCESS) > 0) - builder.append("- Result Lower then Device Can Process\n"); - if ((ssaStatusOctet & SSA_RESULT_HIGHER_THAN_DEVICE_CAN_PROCESS) > 0) - builder.append("- Result Higher then Device Can Process\n"); - } - - if (cgmTrendInformationPresent) { - final float trend = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - offset += 2; - builder.append("Trend: ").append(trend).append(" mg/dL/min\n"); - } - - if (cgmQualityPresent) { - final float quality = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - offset += 2; - builder.append("Quality: ").append(quality).append("%\n"); - } - - if (size > offset + 1) { - final int crc = data.getIntValue(Data.FORMAT_UINT16, offset); - // offset += 2; - builder.append(String.format(Locale.US, "E2E-CRC: 0x%04X\n", crc)); - } - builder.setLength(builder.length() - 1); // Remove last \n - return size; - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CGMSpecificOpsControlPointParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CGMSpecificOpsControlPointParser.java deleted file mode 100644 index c8afc88..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CGMSpecificOpsControlPointParser.java +++ /dev/null @@ -1,295 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class CGMSpecificOpsControlPointParser { - private final static int OP_SET_CGM_COMMUNICATION_INTERVAL = 1; - private final static int OP_GET_CGM_COMMUNICATION_INTERVAL = 2; - private final static int OP_CGM_COMMUNICATION_INTERVAL_RESPONSE = 3; - private final static int OP_SET_GLUCOSE_CALIBRATION_VALUE = 4; - private final static int OP_GET_GLUCOSE_CALIBRATION_VALUE = 5; - private final static int OP_GLUCOSE_CALIBRATION_VALUE_RESPONSE = 6; - private final static int OP_SET_PATIENT_HIGH_ALERT_LEVEL = 7; - private final static int OP_GET_PATIENT_HIGH_ALERT_LEVEL = 8; - private final static int OP_PATIENT_HIGH_ALERT_LEVEL_RESPONSE = 9; - private final static int OP_SET_PATIENT_LOW_ALERT_LEVEL = 10; - private final static int OP_GET_PATIENT_LOW_ALERT_LEVEL = 11; - private final static int OP_PATIENT_LOW_ALERT_LEVEL_RESPONSE = 12; - private final static int OP_SET_HYPO_ALERT_LEVEL = 13; - private final static int OP_GET_HYPO_ALERT_LEVEL = 14; - private final static int OP_HYPO_ALERT_LEVEL_RESPONSE = 15; - private final static int OP_SET_HYPER_ALERT_LEVEL = 16; - private final static int OP_GET_HYPER_ALERT_LEVEL = 17; - private final static int OP_HYPER_ALERT_LEVEL_RESPONSE = 18; - private final static int OP_SET_RATE_OF_DECREASE_ALERT_LEVEL = 19; - private final static int OP_GET_RATE_OF_DECREASE_ALERT_LEVEL = 20; - private final static int OP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE = 21; - private final static int OP_SET_RATE_OF_INCREASE_ALERT_LEVEL = 22; - private final static int OP_GET_RATE_OF_INCREASE_ALERT_LEVEL = 23; - private final static int OP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE = 24; - private final static int OP_RESET_DEVICE_SPECIFIC_ALERT = 25; - private final static int OP_CODE_START_SESSION = 26; - private final static int OP_CODE_STOP_SESSION = 27; - private final static int OP_CODE_RESPONSE_CODE = 28; - - // TODO this parser does not support E2E-CRC! - - public static String parse(final Data data) { - int offset = 0; - final int opCode = data.getIntValue(Data.FORMAT_UINT8, offset++); - - final StringBuilder builder = new StringBuilder(); - builder.append(parseOpCode(opCode)); - switch (opCode) { - case OP_SET_CGM_COMMUNICATION_INTERVAL: - case OP_CGM_COMMUNICATION_INTERVAL_RESPONSE: { - final int interval = data.getIntValue(Data.FORMAT_UINT8, offset); - builder.append(" to ").append(interval).append(" min"); - break; - } - case OP_SET_GLUCOSE_CALIBRATION_VALUE: { - final float calConcentration = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - offset += 2; - final int calTime = data.getIntValue(Data.FORMAT_UINT16, offset); - offset += 2; - final int calTypeSampleLocation = data.getIntValue(Data.FORMAT_UINT8, offset++); - final int calType = calTypeSampleLocation & 0x0F; - final int calSampleLocation = (calTypeSampleLocation & 0xF0) >> 4; - final int calNextCalibrationTime = data.getIntValue(Data.FORMAT_UINT16, offset); - // offset += 2; - // final int calCalibrationDataRecordNumber = data.getIntValue(Data.FORMAT_UINT16, offset); - // offset += 2; - // final int calStatus = data.getIntValue(Data.FORMAT_UINT8, offset++); - - builder.append(" to:\n"); - builder.append("Glucose Concentration of Calibration: ").append(calConcentration).append(" mg/dL\n"); - builder.append("Time: ").append(calTime).append(" min\n"); - builder.append("Type: ").append(parseType(calType)).append("\n"); - builder.append("Sample Location: ").append(parseSampleLocation(calSampleLocation)).append("\n"); - builder.append("Next Calibration Time: ").append(parseNextCalibrationTime(calNextCalibrationTime)).append(" min\n"); // field ignored on Set - // builder.append("Data Record Number: ").append(calCalibrationDataRecordNumber).append("\n"); // field ignored on Set - // parseStatus(builder, calStatus); // field ignored on Set - break; - } - case OP_GET_GLUCOSE_CALIBRATION_VALUE: { - final int calibrationRecordNumber = data.getIntValue(Data.FORMAT_UINT16, offset); - builder.append(": ").append(parseRecordNumber(calibrationRecordNumber)); - break; - } - case OP_GLUCOSE_CALIBRATION_VALUE_RESPONSE: { - final float calConcentration = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - offset += 2; - final int calTime = data.getIntValue(Data.FORMAT_UINT16, offset); - offset += 2; - final int calTypeSampleLocation = data.getIntValue(Data.FORMAT_UINT8, offset++); - final int calType = calTypeSampleLocation & 0x0F; - final int calSampleLocation = (calTypeSampleLocation & 0xF0) >> 4; - final int calNextCalibrationTime = data.getIntValue(Data.FORMAT_UINT16, offset); - offset += 2; - final int calCalibrationDataRecordNumber = data.getIntValue(Data.FORMAT_UINT16, offset); - offset += 2; - final int calStatus = data.getIntValue(Data.FORMAT_UINT8, offset); - - builder.append(":\n"); - if (calCalibrationDataRecordNumber > 0) { - builder.append("Glucose Concentration of Calibration: ").append(calConcentration).append(" mg/dL\n"); - builder.append("Time: ").append(calTime).append(" min\n"); - builder.append("Type: ").append(parseType(calType)).append("\n"); - builder.append("Sample Location: ").append(parseSampleLocation(calSampleLocation)).append("\n"); - builder.append("Next Calibration Time: ").append(parseNextCalibrationTime(calNextCalibrationTime)).append("\n"); - builder.append("Data Record Number: ").append(calCalibrationDataRecordNumber); - parseStatus(builder, calStatus); - } else { - builder.append("No Calibration Data Stored"); - } - break; - } - case OP_SET_PATIENT_HIGH_ALERT_LEVEL: - case OP_SET_PATIENT_LOW_ALERT_LEVEL: - case OP_SET_HYPO_ALERT_LEVEL: - case OP_SET_HYPER_ALERT_LEVEL: { - final float level = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - builder.append(" to: ").append(level).append(" mg/dL"); - break; - } - case OP_PATIENT_HIGH_ALERT_LEVEL_RESPONSE: - case OP_PATIENT_LOW_ALERT_LEVEL_RESPONSE: - case OP_HYPO_ALERT_LEVEL_RESPONSE: - case OP_HYPER_ALERT_LEVEL_RESPONSE: { - final float level = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - builder.append(": ").append(level).append(" mg/dL"); - break; - } - case OP_SET_RATE_OF_DECREASE_ALERT_LEVEL: - case OP_SET_RATE_OF_INCREASE_ALERT_LEVEL: { - final float level = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - builder.append(" to: ").append(level).append(" mg/dL/min"); - break; - } - case OP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE: - case OP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE: { - final float level = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - builder.append(": ").append(level).append(" mg/dL/min"); - break; - } - case OP_CODE_RESPONSE_CODE: - final int requestOpCode = data.getIntValue(Data.FORMAT_UINT8, offset++); - final int responseCode = data.getIntValue(Data.FORMAT_UINT8, offset++); - builder.append(" to ").append(parseOpCode(requestOpCode)).append(": ").append(parseResponseCode(responseCode)); - break; - } - - return builder.toString(); - } - - private static String parseOpCode(final int code) { - switch (code) { - case OP_SET_CGM_COMMUNICATION_INTERVAL: - return "Set CGM Communication Interval"; - case OP_GET_CGM_COMMUNICATION_INTERVAL: - return "Get CGM Communication Interval"; - case OP_CGM_COMMUNICATION_INTERVAL_RESPONSE: - return "CGM Communication Interval"; - case OP_SET_GLUCOSE_CALIBRATION_VALUE: - return "Set CGM Calibration Value"; - case OP_GET_GLUCOSE_CALIBRATION_VALUE: - return "Get CGM Calibration Value"; - case OP_GLUCOSE_CALIBRATION_VALUE_RESPONSE: - return "CGM Calibration Value"; - case OP_SET_PATIENT_HIGH_ALERT_LEVEL: - return "Set Patient High Alert Level"; - case OP_GET_PATIENT_HIGH_ALERT_LEVEL: - return "Get Patient High Alert Level"; - case OP_PATIENT_HIGH_ALERT_LEVEL_RESPONSE: - return "Patient High Alert Level"; - case OP_SET_PATIENT_LOW_ALERT_LEVEL: - return "Set Patient Low Alert Level"; - case OP_GET_PATIENT_LOW_ALERT_LEVEL: - return "Get Patient Low Alert Level"; - case OP_PATIENT_LOW_ALERT_LEVEL_RESPONSE: - return "Patient Low Alert Level"; - case OP_SET_HYPO_ALERT_LEVEL: - return "Set Hypo Alert Level"; - case OP_GET_HYPO_ALERT_LEVEL: - return "Get Hypo Alert Level"; - case OP_HYPO_ALERT_LEVEL_RESPONSE: - return "Hypo Alert Level"; - case OP_SET_HYPER_ALERT_LEVEL: - return "Set Hyper Alert Level"; - case OP_GET_HYPER_ALERT_LEVEL: - return "Get Hyper Alert Level"; - case OP_HYPER_ALERT_LEVEL_RESPONSE: - return "Hyper Alert Level"; - case OP_SET_RATE_OF_DECREASE_ALERT_LEVEL: - return "Set Rate of Decrease Alert Level"; - case OP_GET_RATE_OF_DECREASE_ALERT_LEVEL: - return "Get Rate of Decrease Alert Level"; - case OP_RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE: - return "Rate of Decrease Alert Level"; - case OP_SET_RATE_OF_INCREASE_ALERT_LEVEL: - return "Set Rate of Increase Alert Level"; - case OP_GET_RATE_OF_INCREASE_ALERT_LEVEL: - return "Get Rate of Increase Alert Level"; - case OP_RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE: - return "Rate of Increase Alert Level"; - case OP_RESET_DEVICE_SPECIFIC_ALERT: - return "Reset Device Specific Alert"; - case OP_CODE_START_SESSION: - return "Start Session"; - case OP_CODE_STOP_SESSION: - return "Stop Session"; - case OP_CODE_RESPONSE_CODE: - return "Response"; - default: - return "Reserved for future use (" + code + ")"; - } - } - - private static String parseResponseCode(final int code) { - switch (code) { - case 1: return "Success"; - case 2: return "Op Code not supported"; - case 3: return "Invalid Operand"; - case 4: return "Procedure not completed"; - case 5: return "Parameter out of range"; - default: - return "Reserved for future use (" + code + ")"; - } - } - - private static String parseType(final int type) { - switch (type) { - case 1: return "Capillary Whole blood"; - case 2: return "Capillary Plasma"; - case 3: return "Capillary Whole blood"; - case 4: return "Venous Plasma"; - case 5: return "Arterial Whole blood"; - case 6: return "Arterial Plasma"; - case 7: return "Undetermined Whole blood"; - case 8: return "Undetermined Plasma"; - case 9: return "Interstitial Fluid (ISF)"; - case 10: return "Control Solution"; - default: return "Reserved for future use (" + type + ")"; - } - } - - private static String parseSampleLocation(final int location) { - switch (location) { - case 1: return "Finger"; - case 2: return "Alternate Site Test (AST)"; - case 3: return "Earlobe"; - case 4: return "Control solution"; - case 5: return "Subcutaneous tissue"; - case 15: return "Sample Location value not available"; - default: return "Reserved for future use (" + location + ")"; - } - } - - private static String parseNextCalibrationTime(final int time) { - if (time == 0) - return "Calibration Required Instantly"; - return time + " min"; - } - - private static String parseRecordNumber(final int time) { - if (time == 0xFFFF) - return "Last Calibration Data"; - return String.valueOf(time); - } - - private static void parseStatus(final StringBuilder builder, final int status) { - if (status == 0) - return; - builder.append("\nStatus:\n"); - if ((status & 1) > 0) - builder.append("- Calibration Data rejected"); - if ((status & 2) > 0) - builder.append("- Calibration Data out of range"); - if ((status & 4) > 0) - builder.append("- Calibration Process pending"); - if ((status & 0xF8) > 0) - builder.append("- Reserved for future use (").append(status).append(")"); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CSCMeasurementParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CSCMeasurementParser.java deleted file mode 100644 index a5a28cc..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/CSCMeasurementParser.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class CSCMeasurementParser { - private static final byte WHEEL_REV_DATA_PRESENT = 0x01; // 1 bit - private static final byte CRANK_REV_DATA_PRESENT = 0x02; // 1 bit - - public static String parse(final Data data) { - int offset = 0; - final int flags = data.getByte(offset); // 1 byte - offset += 1; - - final boolean wheelRevPresent = (flags & WHEEL_REV_DATA_PRESENT) > 0; - final boolean crankRevPreset = (flags & CRANK_REV_DATA_PRESENT) > 0; - - int wheelRevolutions = 0; - int lastWheelEventTime = 0; - if (wheelRevPresent) { - wheelRevolutions = data.getIntValue(Data.FORMAT_UINT32, offset); - offset += 4; - - lastWheelEventTime = data.getIntValue(Data.FORMAT_UINT16, offset); // 1/1024 s - offset += 2; - } - - int crankRevolutions = 0; - int lastCrankEventTime = 0; - if (crankRevPreset) { - crankRevolutions = data.getIntValue(Data.FORMAT_UINT16, offset); - offset += 2; - - lastCrankEventTime = data.getIntValue(Data.FORMAT_UINT16, offset); - //offset += 2; - } - - final StringBuilder builder = new StringBuilder(); - if (wheelRevPresent) { - builder.append("Wheel rev: ").append(wheelRevolutions).append(",\n"); - builder.append("Last wheel event time: ").append(lastWheelEventTime).append(",\n"); - } - if (crankRevPreset) { - builder.append("Crank rev: ").append(crankRevolutions).append(",\n"); - builder.append("Last crank event time: ").append(lastCrankEventTime).append(",\n"); - } - if (!wheelRevPresent && !crankRevPreset) { - builder.append("No wheel or crank data"); - } - builder.setLength(builder.length() - 2); - return builder.toString(); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/DateTimeParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/DateTimeParser.java deleted file mode 100644 index 5e3e79b..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/DateTimeParser.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.parser; - -import java.util.Calendar; -import java.util.Locale; - -import no.nordicsemi.android.ble.common.callback.DateTimeDataCallback; -import no.nordicsemi.android.ble.data.Data; - -public class DateTimeParser { - /** - * Parses the date and time info. - * - * @param data - * @return time in human readable format - */ - public static String parse(final Data data) { - return parse(data, 0); - } - - /** - * Parses the date and time info. This data has 7 bytes - * - * @param data - * @param offset - * offset to start reading the time - * @return time in human readable format - */ - /* package */static String parse(final Data data, final int offset) { - final Calendar calendar = DateTimeDataCallback.readDateTime(data, offset); - return String.format(Locale.US, "%1$te %1$tb %1$tY, %1$tH:%1$tM:%1$tS", calendar); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/GlucoseMeasurementContextParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/GlucoseMeasurementContextParser.java deleted file mode 100644 index 8a81440..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/GlucoseMeasurementContextParser.java +++ /dev/null @@ -1,188 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class GlucoseMeasurementContextParser { - private static final int UNIT_kg = 0; - private static final int UNIT_l = 1; - - public static String parse(final Data data) { - final StringBuilder builder = new StringBuilder(); - - int offset = 0; - final int flags = data.getIntValue(Data.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 ? UNIT_l : UNIT_kg; - final boolean hbA1cPresent = (flags & 0x40) > 0; - final boolean moreFlagsPresent = (flags & 0x80) > 0; - - final int sequenceNumber = data.getIntValue(Data.FORMAT_UINT16, offset); - offset += 2; - - if (moreFlagsPresent) // not supported yet - offset += 1; - - builder.append("Sequence number: ").append(sequenceNumber); - - if (carbohydratePresent) { - final int carbohydrateId = data.getIntValue(Data.FORMAT_UINT8, offset); - final float carbohydrateUnits = data.getFloatValue(Data.FORMAT_SFLOAT, offset + 1); - builder.append("\nCarbohydrate: ").append(getCarbohydrate(carbohydrateId)).append(" (").append(carbohydrateUnits).append(carbohydrateUnits == UNIT_kg ? "kg" : "l").append(")"); - offset += 3; - } - - if (mealPresent) { - final int meal = data.getIntValue(Data.FORMAT_UINT8, offset); - builder.append("\nMeal: ").append(getMeal(meal)); - offset += 1; - } - - if (testerHealthPresent) { - final int testerHealth = data.getIntValue(Data.FORMAT_UINT8, offset); - final int tester = (testerHealth & 0xF0) >> 4; - final int health = (testerHealth & 0x0F); - builder.append("\nTester: ").append(getTester(tester)); - builder.append("\nHealth: ").append(getHealth(health)); - offset += 1; - } - - if (exercisePresent) { - final int exerciseDuration = data.getIntValue(Data.FORMAT_UINT16, offset); - final int exerciseIntensity = data.getIntValue(Data.FORMAT_UINT8, offset + 2); - builder.append("\nExercise duration: ").append(exerciseDuration).append("s (intensity ").append(exerciseIntensity).append("%)"); - offset += 3; - } - - if (medicationPresent) { - final int medicationId = data.getIntValue(Data.FORMAT_UINT8, offset); - final float medicationQuantity = data.getFloatValue(Data.FORMAT_SFLOAT, offset + 1); - builder.append("\nMedication: ").append(getMedicationId(medicationId)).append(" (").append(medicationQuantity).append(medicationUnit == UNIT_kg ? "kg" : "l"); - offset += 3; - } - - if (hbA1cPresent) { - final float HbA1c = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - builder.append("\nHbA1c: ").append(HbA1c).append("%"); - } - return builder.toString(); - } - - private static String getCarbohydrate(final int id) { - switch (id) { - case 1: - return "Breakfast"; - case 2: - return "Lunch"; - case 3: - return "Dinner"; - case 4: - return "Snack"; - case 5: - return "Drink"; - case 6: - return "Supper"; - case 7: - return "Brunch"; - default: - return "Reserved for future use (" + id + ")"; - } - } - - private static String getMeal(final int id) { - switch (id) { - case 1: - return "Preprandial (before meal)"; - case 2: - return "Postprandial (after meal)"; - case 3: - return "Fasting"; - case 4: - return "Casual (snacks, drinks, etc.)"; - case 5: - return "Bedtime"; - default: - return "Reserved for future use (" + id + ")"; - } - } - - private static String getTester(final int id) { - switch (id) { - case 1: - return "Self"; - case 2: - return "Health Care Professional"; - case 3: - return "Lab test"; - case 4: - return "Casual (snacks, drinks, etc.)"; - case 15: - return "Tester value not available"; - default: - return "Reserved for future use (" + id + ")"; - } - } - - private static String getHealth(final int id) { - switch (id) { - case 1: - return "Minor health issues"; - case 2: - return "Major health issues"; - case 3: - return "During menses"; - case 4: - return "Under stress"; - case 5: - return "No health issues"; - case 15: - return "Health value not available"; - default: - return "Reserved for future use (" + id + ")"; - } - } - - private static String getMedicationId(final int id) { - switch (id) { - case 1: - return "Rapid acting insulin"; - case 2: - return "Short acting insulin"; - case 3: - return "Intermediate acting insulin"; - case 4: - return "Long acting insulin"; - case 5: - return "Pre-mixed insulin"; - default: - return "Reserved for future use (" + id + ")"; - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/GlucoseMeasurementParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/GlucoseMeasurementParser.java deleted file mode 100644 index 18d59b4..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/GlucoseMeasurementParser.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class GlucoseMeasurementParser { - private static final int UNIT_kgpl = 0; - private static final int UNIT_molpl = 1; - - private static final int STATUS_DEVICE_BATTERY_LOW = 0x0001; - private static final int STATUS_SENSOR_MALFUNCTION = 0x0002; - private static final int STATUS_SAMPLE_SIZE_FOR_BLOOD_OR_CONTROL_SOLUTION_INSUFFICIENT = 0x0004; - private static final int STATUS_STRIP_INSERTION_ERROR = 0x0008; - private static final int STATUS_STRIP_TYPE_INCORRECT_FOR_DEVICE = 0x0010; - private static final int STATUS_SENSOR_RESULT_TOO_HIGH = 0x0020; - private static final int STATUS_SENSOR_RESULT_TOO_LOW = 0x0040; - private static final int STATUS_SENSOR_TEMPERATURE_TOO_HIGH = 0x0080; - private static final int STATUS_SENSOR_TEMPERATURE_TOO_LOW = 0x0100; - private static final int STATUS_SENSOR_READ_INTERRUPTED = 0x0200; - private static final int STATUS_GENERAL_DEVICE_FAULT = 0x0400; - private static final int STATUS_TIME_FAULT = 0x0800; - - public static String parse(final Data data) { - final StringBuilder builder = new StringBuilder(); - - int offset = 0; - final int flags = data.getIntValue(Data.FORMAT_UINT8, offset); - offset += 1; - - final boolean timeOffsetPresent = (flags & 0x01) > 0; - final boolean typeAndLocationPresent = (flags & 0x02) > 0; - final int concentrationUnit = (flags & 0x04) > 0 ? UNIT_molpl : UNIT_kgpl; - final boolean sensorStatusAnnunciationPresent = (flags & 0x08) > 0; - final boolean contextInfoFollows = (flags & 0x10) > 0; - - // create and fill the new record - final int sequenceNumber = data.getIntValue(Data.FORMAT_UINT16, offset); - builder.append("Sequence Number: ").append(sequenceNumber); - offset += 2; - - builder.append("\nBase Time: ").append(DateTimeParser.parse(data, offset)); - offset += 7; - - if (timeOffsetPresent) { - // time offset is ignored in the current release - final int timeOffset = data.getIntValue(Data.FORMAT_SINT16, offset); - builder.append("\nTime Offset: ").append(timeOffset).append(" min"); - offset += 2; - } - - if (typeAndLocationPresent) { - final float glucoseConcentration = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - final int typeAndLocation = data.getIntValue(Data.FORMAT_UINT8, offset + 2); - final int type = (typeAndLocation & 0xF0) >> 4; // TODO this way or around? - final int sampleLocation = (typeAndLocation & 0x0F); - builder.append("\nGlucose Concentration: ").append(glucoseConcentration).append(concentrationUnit == UNIT_kgpl ? " kg/l" : " mol/l"); - builder.append("\nSample Type: ").append(getType(type)); - builder.append("\nSample Location: ").append(getLocation(sampleLocation)); - offset += 3; - } - - if (sensorStatusAnnunciationPresent) { - final int status = data.getIntValue(Data.FORMAT_UINT16, offset); - builder.append("Status:\n").append(getStatusAnnunciation(status)); - } - - builder.append("\nContext information follows: ").append(contextInfoFollows); - return builder.toString(); - } - - private static String getType(final int type) { - switch (type) { - case 1: - return "Capillary Whole blood"; - case 2: - return "Capillary Plasma"; - case 3: - return "Venous Whole blood"; - case 4: - return "Venous Plasma"; - case 5: - return "Arterial Whole blood"; - case 6: - return "Arterial Plasma"; - case 7: - return "Undetermined Whole blood"; - case 8: - return "Undetermined Plasma"; - case 9: - return "Interstitial Fluid (ISF)"; - case 10: - return "Control Solution"; - default: - return "Reserved for future use (" + type + ")"; - } - } - - private static String getLocation(final int location) { - switch (location) { - case 1: - return "Finger"; - case 2: - return "Alternate Site Test (AST)"; - case 3: - return "Earlobe"; - case 4: - return "Control solution"; - case 15: - return "Value not available"; - default: - return "Reserved for future use (" + location + ")"; - } - } - - private static String getStatusAnnunciation(final int status) { - final StringBuilder builder = new StringBuilder(); - if ((status & STATUS_DEVICE_BATTERY_LOW) > 0) - builder.append("\nDevice battery low at time of measurement"); - if ((status & STATUS_SENSOR_MALFUNCTION) > 0) - builder.append("\nSensor malfunction or faulting at time of measurement"); - if ((status & STATUS_SAMPLE_SIZE_FOR_BLOOD_OR_CONTROL_SOLUTION_INSUFFICIENT) > 0) - builder.append("\nSample size for blood or control solution insufficient at time of measurement"); - if ((status & STATUS_STRIP_INSERTION_ERROR) > 0) - builder.append("\nStrip insertion error"); - if ((status & STATUS_STRIP_TYPE_INCORRECT_FOR_DEVICE) > 0) - builder.append("\nStrip type incorrect for device"); - if ((status & STATUS_SENSOR_RESULT_TOO_HIGH) > 0) - builder.append("\nSensor result higher than the device can process"); - if ((status & STATUS_SENSOR_RESULT_TOO_LOW) > 0) - builder.append("\nSensor result lower than the device can process"); - if ((status & STATUS_SENSOR_TEMPERATURE_TOO_HIGH) > 0) - builder.append("\nSensor temperature too high for valid test/result at time of measurement"); - if ((status & STATUS_SENSOR_TEMPERATURE_TOO_LOW) > 0) - builder.append("\nSensor temperature too low for valid test/result at time of measurement"); - if ((status & STATUS_SENSOR_READ_INTERRUPTED) > 0) - builder.append("\nSensor read interrupted because strip was pulled too soon at time of measurement"); - if ((status & STATUS_GENERAL_DEVICE_FAULT) > 0) - builder.append("\nGeneral device fault has occurred in the sensor"); - if ((status & STATUS_TIME_FAULT) > 0) - builder.append("\nTime fault has occurred in the sensor and time may be inaccurate"); - return builder.toString(); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/HeartRateMeasurementParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/HeartRateMeasurementParser.java deleted file mode 100644 index 9622072..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/HeartRateMeasurementParser.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.parser; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class HeartRateMeasurementParser { - private static final byte HEART_RATE_VALUE_FORMAT = 0x01; // 1 bit - private static final byte SENSOR_CONTACT_STATUS = 0x06; // 2 bits - private static final byte ENERGY_EXPANDED_STATUS = 0x08; // 1 bit - private static final byte RR_INTERVAL = 0x10; // 1 bit - - public static String parse(final Data data) { - int offset = 0; - final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); - - /* - * false Heart Rate Value Format is set to UINT8. Units: beats per minute (bpm) - * true Heart Rate Value Format is set to UINT16. Units: beats per minute (bpm) - */ - final boolean value16bit = (flags & HEART_RATE_VALUE_FORMAT) > 0; - - /* - * 0 Sensor Contact feature is not supported in the current connection - * 1 Sensor Contact feature is not supported in the current connection - * 2 Sensor Contact feature is supported, but contact is not detected - * 3 Sensor Contact feature is supported and contact is detected - */ - final int sensorContactStatus = (flags & SENSOR_CONTACT_STATUS) >> 1; - - /* - * false Energy Expended field is not present - * true Energy Expended field is present. Units: kilo Joules - */ - final boolean energyExpandedStatus = (flags & ENERGY_EXPANDED_STATUS) > 0; - - /* - * false RR-Interval values are not present. - * true One or more RR-Interval values are present. Units: 1/1024 seconds - */ - final boolean rrIntervalStatus = (flags & RR_INTERVAL) > 0; - - // heart rate value is 8 or 16 bit long - int heartRateValue = data.getIntValue(value16bit ? Data.FORMAT_UINT16 : Data.FORMAT_UINT8, offset++); // bits per minute - if (value16bit) - offset++; - - // energy expanded value is present if a flag was set - int energyExpanded = -1; - if (energyExpandedStatus) - energyExpanded = data.getIntValue(Data.FORMAT_UINT16, offset); - offset += 2; - - // RR-interval is set when a flag is set - final List rrIntervals = new ArrayList<>(); - if (rrIntervalStatus) { - for (int o = offset; o < data.getValue().length; o += 2) { - final int units = data.getIntValue(Data.FORMAT_UINT16, o); - rrIntervals.add(units * 1000.0f / 1024.0f); // RR interval is in [1/1024s] - } - } - - final StringBuilder builder = new StringBuilder(); - builder.append("Heart Rate Measurement: ").append(heartRateValue).append(" bpm"); - switch (sensorContactStatus) { - case 0: - case 1: - builder.append(",\nSensor Contact Not Supported"); - break; - case 2: - builder.append(",\nContact is NOT Detected"); - break; - case 3: - builder.append(",\nContact is Detected"); - break; - } - if (energyExpandedStatus) - builder.append(",\nEnergy Expanded: ").append(energyExpanded).append(" kJ"); - if (rrIntervalStatus) { - builder.append(",\nRR Interval: "); - for (final Float interval : rrIntervals) - builder.append(String.format(Locale.US, "%.02f ms, ", interval)); - builder.setLength(builder.length() - 2); // remove the ", " at the end - } - return builder.toString(); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/IntermediateCuffPressureParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/IntermediateCuffPressureParser.java deleted file mode 100644 index 632dc5e..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/IntermediateCuffPressureParser.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class IntermediateCuffPressureParser { - public static String parse(final Data data) { - final StringBuilder builder = new StringBuilder(); - - // first byte - flags - int offset = 0; - final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); - - final int unitType = flags & 0x01; - final boolean timestampPresent = (flags & 0x02) > 0; - final boolean pulseRatePresent = (flags & 0x04) > 0; - final boolean userIdPresent = (flags & 0x08) > 0; - final boolean statusPresent = (flags & 0x10) > 0; - - // following bytes - pressure - final float pressure = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - final String unit = unitType == 0 ? " mmHg" : " kPa"; - offset += 6; - builder.append("Cuff pressure: ").append(pressure).append(unit); - - // parse timestamp if present - if (timestampPresent) { - builder.append("Timestamp: ").append(DateTimeParser.parse(data, offset)); - offset += 7; - } - - // parse pulse rate if present - if (pulseRatePresent) { - final float pulseRate = data.getFloatValue(Data.FORMAT_SFLOAT, offset); - offset += 2; - builder.append("\nPulse: ").append(pulseRate).append(" bpm"); - } - - if (userIdPresent) { - final int userId = data.getIntValue(Data.FORMAT_UINT8, offset); - offset += 1; - builder.append("\nUser ID: ").append(userId); - } - - if (statusPresent) { - final int status = data.getIntValue(Data.FORMAT_UINT16, offset); - // offset += 2; - if ((status & 0x0001) > 0) - builder.append("\nBody movement detected"); - if ((status & 0x0002) > 0) - builder.append("\nCuff too lose"); - if ((status & 0x0004) > 0) - builder.append("\nIrregular pulse detected"); - if ((status & 0x0018) == 0x0008) - builder.append("\nPulse rate exceeds upper limit"); - if ((status & 0x0018) == 0x0010) - builder.append("\nPulse rate is less than lower limit"); - if ((status & 0x0018) == 0x0018) - builder.append("\nPulse rate range: Reserved for future use "); - if ((status & 0x0020) > 0) - builder.append("\nImproper measurement position"); - } - - return builder.toString(); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/RSCMeasurementParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/RSCMeasurementParser.java deleted file mode 100644 index 6d19622..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/RSCMeasurementParser.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.parser; - -import java.util.Locale; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class RSCMeasurementParser { - 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 static String parse(final Data data) { - int offset = 0; - final int flags = data.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 boolean walking = !running; - - final float instantaneousSpeed = (float) data.getIntValue(Data.FORMAT_UINT16, offset) / 256.0f; // 1/256 m/s - offset += 2; - - final int instantaneousCadence = data.getIntValue(Data.FORMAT_UINT8, offset); - offset += 1; - - float instantaneousStrideLength = 0; - if (islmPresent) { - instantaneousStrideLength = (float) data.getIntValue(Data.FORMAT_UINT16, offset) / 100.0f; // 1/100 m - offset += 2; - } - - float totalDistance = 0; - if (tdPreset) { - totalDistance = (float) data.getIntValue(Data.FORMAT_UINT32, offset) / 10.0f; - // offset += 4; - } - - final StringBuilder builder = new StringBuilder(); - builder.append(String.format(Locale.US, "Speed: %.2f m/s, Cadence: %d RPM,\n", instantaneousSpeed, instantaneousCadence)); - if (islmPresent) - builder.append(String.format(Locale.US, "Instantaneous Stride Length: %.2f m,\n", instantaneousStrideLength)); - if (tdPreset) - builder.append(String.format(Locale.US, "Total Distance: %.1f m,\n", totalDistance)); - if (walking) - builder.append("Status: WALKING"); - else - builder.append("Status: RUNNING"); - return builder.toString(); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/RecordAccessControlPointParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/RecordAccessControlPointParser.java deleted file mode 100644 index 0ef5954..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/RecordAccessControlPointParser.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class RecordAccessControlPointParser { - 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; - - 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; - - public static String parse(final Data data) { - final StringBuilder builder = new StringBuilder(); - final int opCode = data.getIntValue(Data.FORMAT_UINT8, 0); - final int operator = data.getIntValue(Data.FORMAT_UINT8, 1); - - switch (opCode) { - case OP_CODE_REPORT_STORED_RECORDS: - case OP_CODE_DELETE_STORED_RECORDS: - case OP_CODE_ABORT_OPERATION: - case OP_CODE_REPORT_NUMBER_OF_RECORDS: - builder.append(getOpCode(opCode)).append("\n"); - break; - case OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE: { - builder.append(getOpCode(opCode)).append(": "); - final int value = data.getIntValue(Data.FORMAT_UINT16, 2); - builder.append(value).append("\n"); - break; - } - case OP_CODE_RESPONSE_CODE: { - builder.append(getOpCode(opCode)).append(" for "); - final int targetOpCode = data.getIntValue(Data.FORMAT_UINT8, 2); - builder.append(getOpCode(targetOpCode)).append(": "); - final int status = data.getIntValue(Data.FORMAT_UINT8, 3); - builder.append(getStatus(status)).append("\n"); - break; - } - } - - switch (operator) { - case OPERATOR_ALL_RECORDS: - case OPERATOR_FIRST_RECORD: - case OPERATOR_LAST_RECORD: - builder.append("Operator: ").append(getOperator(operator)).append("\n"); - break; - case OPERATOR_GREATER_THEN_OR_EQUAL: - case OPERATOR_LESS_THEN_OR_EQUAL: { - final int filter = data.getIntValue(Data.FORMAT_UINT8, 2); - final int value = data.getIntValue(Data.FORMAT_UINT16, 3); - builder.append("Operator: ").append(getOperator(operator)).append(" ").append(value).append(" (filter: ").append(filter).append(")\n"); - break; - } - case OPERATOR_WITHING_RANGE: { - final int filter = data.getIntValue(Data.FORMAT_UINT8, 2); - final int value1 = data.getIntValue(Data.FORMAT_UINT16, 3); - final int value2 = data.getIntValue(Data.FORMAT_UINT16, 5); - builder.append("Operator: ").append(getOperator(operator)).append(" ").append(value1).append("-").append(value2).append(" (filter: ").append(filter).append(")\n"); - break; - } - } - if (builder.length() > 0) - builder.setLength(builder.length() - 1); - - return builder.toString(); - } - - private static String getOpCode(final int opCode) { - switch (opCode) { - case OP_CODE_REPORT_STORED_RECORDS: - return "Report stored records"; - case OP_CODE_DELETE_STORED_RECORDS: - return "Delete stored records"; - case OP_CODE_ABORT_OPERATION: - return "Abort operation"; - case OP_CODE_REPORT_NUMBER_OF_RECORDS: - return "Report number of stored records"; - case OP_CODE_NUMBER_OF_STORED_RECORDS_RESPONSE: - return "Number of stored records response"; - case OP_CODE_RESPONSE_CODE: - return "Response Code"; - default: - return "Reserved for future use"; - } - } - - private static String getOperator(final int operator) { - switch (operator) { - case OPERATOR_NULL: - return "Null"; - case OPERATOR_ALL_RECORDS: - return "All records"; - case OPERATOR_LESS_THEN_OR_EQUAL: - return "Less than or equal to"; - case OPERATOR_GREATER_THEN_OR_EQUAL: - return "Greater than or equal to"; - case OPERATOR_WITHING_RANGE: - return "Within range of"; - case OPERATOR_FIRST_RECORD: - return "First record(i.e. oldest record)"; - case OPERATOR_LAST_RECORD: - return "Last record (i.e. most recent record)"; - default: - return "Reserved for future use"; - } - } - - private static String getStatus(final int status) { - switch (status) { - case RESPONSE_SUCCESS: - return "Success"; - case RESPONSE_OP_CODE_NOT_SUPPORTED: - return "Operation not supported"; - case RESPONSE_INVALID_OPERATOR: - return "Invalid operator"; - case RESPONSE_OPERATOR_NOT_SUPPORTED: - return "Operator not supported"; - case RESPONSE_INVALID_OPERAND: - return "Invalid operand"; - case RESPONSE_NO_RECORDS_FOUND: - return "No records found"; - case RESPONSE_ABORT_UNSUCCESSFUL: - return "Abort unsuccessful"; - case RESPONSE_PROCEDURE_NOT_COMPLETED: - return "Procedure not completed"; - case RESPONSE_OPERAND_NOT_SUPPORTED: - return "Operand not supported"; - default: - return "Reserved for future use"; - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureMeasurementParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureMeasurementParser.java deleted file mode 100644 index cdefad7..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureMeasurementParser.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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.parser; - -import java.util.Locale; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class TemperatureMeasurementParser { - private static final byte TEMPERATURE_UNIT_FLAG = 0x01; // 1 bit - private static final byte TIMESTAMP_FLAG = 0x02; // 1 bits - private static final byte TEMPERATURE_TYPE_FLAG = 0x04; // 1 bit - - public static String parse(final Data data) { - int offset = 0; - final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); - - /* - * false Temperature is in Celsius degrees - * true Temperature is in Fahrenheit degrees - */ - final boolean fahrenheit = (flags & TEMPERATURE_UNIT_FLAG) > 0; - - /* - * false No Timestamp in the packet - * true There is a timestamp information - */ - final boolean timestampIncluded = (flags & TIMESTAMP_FLAG) > 0; - - /* - * false Temperature type is not included - * true Temperature type included in the packet - */ - final boolean temperatureTypeIncluded = (flags & TEMPERATURE_TYPE_FLAG) > 0; - - final float tempValue = data.getFloatValue(Data.FORMAT_FLOAT, offset); - offset += 4; - - String dateTime = null; - if (timestampIncluded) { - dateTime = DateTimeParser.parse(data, offset); - offset += 7; - } - - String type = null; - if (temperatureTypeIncluded) { - type = TemperatureTypeParser.parse(data, offset); - // offset++; - } - - final StringBuilder builder = new StringBuilder(); - builder.append(String.format(Locale.US, "%.02f", tempValue)); - - if (fahrenheit) - builder.append("°F"); - else - builder.append("°C"); - - if (timestampIncluded) - builder.append("\nTime: ").append(dateTime); - if (temperatureTypeIncluded) - builder.append("\nType: ").append(type); - return builder.toString(); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureTypeParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureTypeParser.java deleted file mode 100644 index 10d755e..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemperatureTypeParser.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -@SuppressWarnings("ConstantConditions") -public class TemperatureTypeParser { - - public static String parse(final Data data) { - return parse(data, 0); - } - - /* package */static String parse(final Data data, final int offset) { - final int type = data.getValue()[offset]; - - switch (type) { - case 1: - return "Armpit"; - case 2: - return "Body (general)"; - case 3: - return "Ear (usually ear lobe)"; - case 4: - return "Finger"; - case 5: - return "Gastro-intestinal Tract"; - case 6: - return "Mouth"; - case 7: - return "Rectum"; - case 8: - return "Toe"; - case 9: - return "Tympanum (ear drum)"; - default: - return "Unknown"; - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemplateParser.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemplateParser.java deleted file mode 100644 index ed0490a..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/parser/TemplateParser.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.parser; - -import no.nordicsemi.android.ble.data.Data; - -// TODO this method may be used for developing purposes to log the data from your device using the nRF Logger application. - -@SuppressWarnings("ConstantConditions") -public class TemplateParser { - // TODO add some flags, if needed - private static final byte HEART_RATE_VALUE_FORMAT = 0x01; // 1 bit - - /** - * This method converts the value of the characteristic to the String. The String is then logged in the nRF logger log session - * @param data the characteristic data to be parsed - * @return human readable value of the characteristic - */ - @SuppressWarnings("UnusedAssignment") - public static String parse(final Data data) { - int offset = 0; - final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); - - /* - * In the template we are using the HRM values as an example. - * false Heart Rate Value Format is set to UINT8. Units: beats per minute (bpm) - * true Heart Rate Value Format is set to UINT16. Units: beats per minute (bpm) - */ - final boolean value16bit = (flags & HEART_RATE_VALUE_FORMAT) > 0; - - // heart rate value is 8 or 16 bit long - int value = data.getIntValue(value16bit ? Data.FORMAT_UINT16 : Data.FORMAT_UINT8, offset++); // bits per minute - if (value16bit) - offset++; - - // TODO parse more data - - return "Template Measurement: " + value + " bpm"; - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/IDeviceLogger.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/IDeviceLogger.java deleted file mode 100644 index 59d6d59..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/IDeviceLogger.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2016, 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.multiconnect; - -import android.bluetooth.BluetoothDevice; -import androidx.annotation.StringRes; - -public interface IDeviceLogger { - /** - * Logs the given message with given log level into the device's log session. - * @param device the target device - * @param level the log level - * @param message the message to be logged - */ - void log(final BluetoothDevice device, final int level, final String message); - - /** - * Logs the given message with given log level into the device's log session. - * @param device the target device - * @param level the log level - * @param messageRes string resource id - * @param params additional (optional) parameters used to fill the message - */ - void log(final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params); -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/DeviceAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/DeviceAdapter.java deleted file mode 100644 index c41538b..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/DeviceAdapter.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2016, 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 android.bluetooth.BluetoothDevice; -import androidx.annotation.NonNull; -import androidx.recyclerview.widget.RecyclerView; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageButton; -import android.widget.ProgressBar; -import android.widget.TextView; - -import java.util.List; - -import no.nordicsemi.android.nrftoolbox.R; - -public class DeviceAdapter extends RecyclerView.Adapter { - private final ProximityService.ProximityBinder mService; - private final List mDevices; - - DeviceAdapter(final ProximityService.ProximityBinder binder) { - mService = binder; - mDevices = mService.getManagedDevices(); - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent, final int viewType) { - final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.activity_feature_proximity_item, parent, false); - return new ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) { - holder.bind(mDevices.get(position)); - } - - @Override - public int getItemCount() { - return mDevices.size(); - } - - public void onDeviceAdded(final BluetoothDevice device) { - final int position = mDevices.indexOf(device); - if (position == -1) { - notifyItemInserted(mDevices.size() - 1); - } else { - // This may happen when Bluetooth adapter was switched off and on again - // while there were devices on the list. - notifyItemChanged(position); - } - } - - public void onDeviceRemoved(final BluetoothDevice device) { - notifyDataSetChanged(); // we don't have position of the removed device here - } - - public void onDeviceStateChanged(final BluetoothDevice device) { - final int position = mDevices.indexOf(device); - if (position >= 0) - notifyItemChanged(position); - } - - public void onBatteryValueReceived(final BluetoothDevice device) { - final int position = mDevices.indexOf(device); - if (position >= 0) - notifyItemChanged(position); - } - - class ViewHolder extends RecyclerView.ViewHolder { - private TextView nameView; - private TextView addressView; - private TextView batteryView; - private ImageButton actionButton; - private ProgressBar progress; - - ViewHolder(final View itemView) { - super(itemView); - - nameView = itemView.findViewById(R.id.name); - addressView = itemView.findViewById(R.id.address); - batteryView = itemView.findViewById(R.id.battery); - actionButton = itemView.findViewById(R.id.action_find_silent); - progress = itemView.findViewById(R.id.progress); - - // Configure FIND / SILENT button - actionButton.setOnClickListener(v -> { - final int position = getAdapterPosition(); - final BluetoothDevice device = mDevices.get(position); - mService.toggleImmediateAlert(device); - }); - - // Configure Disconnect button - itemView.findViewById(R.id.action_disconnect).setOnClickListener(v -> { - final int position = getAdapterPosition(); - final BluetoothDevice device = mDevices.get(position); - mService.disconnect(device); - // The device might have not been connected, so there will be no callback - onDeviceRemoved(device); - }); - } - - private void bind(final BluetoothDevice device) { - final boolean ready = mService.isReady(device); - - String name = device.getName(); - if (TextUtils.isEmpty(name)) - name = nameView.getResources().getString(R.string.proximity_default_device_name); - nameView.setText(name); - addressView.setText(device.getAddress()); - - final boolean on = mService.isImmediateAlertOn(device); - actionButton.setImageResource(on ? R.drawable.ic_stat_notify_proximity_silent : R.drawable.ic_stat_notify_proximity_find); - actionButton.setVisibility(ready ? View.VISIBLE : View.GONE); - progress.setVisibility(ready ? View.GONE : View.VISIBLE); - - final Integer batteryValue = mService.getBatteryLevel(device); - if (batteryValue != null) { - batteryView.getCompoundDrawables()[0 /*left*/].setLevel(batteryValue); - batteryView.setVisibility(View.VISIBLE); - batteryView.setText(batteryView.getResources().getString(R.string.battery, batteryValue)); - batteryView.setAlpha(ready ? 1.0f : 0.5f); - } else { - batteryView.setVisibility(View.GONE); - } - } - } -} 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 deleted file mode 100644 index 23f0450..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/LinkLossFragment.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 android.app.Dialog; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import androidx.appcompat.app.AlertDialog; - -import no.nordicsemi.android.nrftoolbox.R; - -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); - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(requireContext()) - .setTitle(getString(R.string.app_name)) - .setMessage(getString(R.string.proximity_notification_link_loss_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 deleted file mode 100644 index bab1d05..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityActivity.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import java.util.UUID; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.multiconnect.BleMulticonnectProfileService; -import no.nordicsemi.android.nrftoolbox.profile.multiconnect.BleMulticonnectProfileServiceReadyActivity; -import no.nordicsemi.android.nrftoolbox.widget.DividerItemDecoration; - -public class ProximityActivity extends BleMulticonnectProfileServiceReadyActivity { - private RecyclerView mDevicesView; - private DeviceAdapter mAdapter; - - @Override - protected void onCreateView(final Bundle savedInstanceState) { - setContentView(R.layout.activity_feature_proximity); - 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() { - final RecyclerView recyclerView = mDevicesView = findViewById(android.R.id.list); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); - recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); - } - - @Override - protected int getLoggerProfileTitle() { - return R.string.proximity_feature_title; - } - - @Override - protected void onServiceBound(final ProximityService.ProximityBinder binder) { - mDevicesView.setAdapter(mAdapter = new DeviceAdapter(binder)); - } - - @Override - protected void onServiceUnbound() { - mDevicesView.setAdapter(mAdapter = null); - } - - @Override - protected Class getServiceClass() { - return ProximityService.class; - } - - @Override - protected int getAboutTextId() { - return R.string.proximity_about_text; - } - - @Override - protected UUID getFilterUUID() { - return ProximityManager.LINK_LOSS_SERVICE_UUID; - } - - @Override - public void onDeviceConnecting(final BluetoothDevice device) { - if (mAdapter != null) - mAdapter.onDeviceAdded(device); - } - - @Override - public void onDeviceConnected(final BluetoothDevice device) { - if (mAdapter != null) - mAdapter.onDeviceStateChanged(device); - } - - @Override - public void onDeviceReady(final BluetoothDevice device) { - if (mAdapter != null) - mAdapter.onDeviceStateChanged(device); - } - - @Override - public void onDeviceDisconnecting(final BluetoothDevice device) { - if (mAdapter != null) - mAdapter.onDeviceStateChanged(device); - } - - @Override - public void onDeviceDisconnected(final BluetoothDevice device) { - if (mAdapter != null) - mAdapter.onDeviceRemoved(device); - } - - @Override - public void onDeviceNotSupported(final BluetoothDevice device) { - super.onDeviceNotSupported(device); - if (mAdapter != null) - mAdapter.onDeviceRemoved(device); - } - - @Override - public void onLinkLossOccurred(final BluetoothDevice device) { - if (mAdapter != null) - mAdapter.onDeviceStateChanged(device); - - // The link loss may also be called when Bluetooth adapter was disabled - if (BluetoothAdapter.getDefaultAdapter().isEnabled()) - showLinkLossDialog(device.getName()); - } - - @SuppressWarnings("unused") - private void onBatteryLevelChanged(final BluetoothDevice device, final int batteryLevel) { - if (mAdapter != null) - mAdapter.onBatteryValueReceived(device); // Value will be obtained from the service - } - - @SuppressWarnings("unused") - private void onRemoteAlarmSwitched(final BluetoothDevice device, final boolean on) { - if (mAdapter != null) - mAdapter.onDeviceStateChanged(device); // Value will be obtained from the service - } - - private void showLinkLossDialog(final String name) { - try { - final LinkLossFragment dialog = LinkLossFragment.getInstance(name); - dialog.show(getSupportFragmentManager(), "scan_fragment"); - } catch (final Exception e) { - // the activity must have been destroyed - } - } - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(final Context context, final Intent intent) { - final String action = intent.getAction(); - final BluetoothDevice device = intent.getParcelableExtra(ProximityService.EXTRA_DEVICE); - - if (ProximityService.BROADCAST_BATTERY_LEVEL.equals(action)) { - final int batteryLevel = intent.getIntExtra(ProximityService.EXTRA_BATTERY_LEVEL, 0); - // Update GUI - onBatteryLevelChanged(device, batteryLevel); - } else if (ProximityService.BROADCAST_ALARM_SWITCHED.equals(action)) { - final boolean on = intent.getBooleanExtra(ProximityService.EXTRA_ALARM_STATE, false); - // Update GUI - onRemoteAlarmSwitched(device, on); - } - } - }; - - private static IntentFilter makeIntentFilter() { - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(ProximityService.BROADCAST_BATTERY_LEVEL); - intentFilter.addAction(ProximityService.BROADCAST_ALARM_SWITCHED); - return intentFilter; - } -} 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 deleted file mode 100644 index 315ebf6..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManager.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import androidx.annotation.NonNull; -import android.util.Log; - -import java.util.UUID; - -import no.nordicsemi.android.ble.callback.FailCallback; -import no.nordicsemi.android.ble.common.data.alert.AlertLevelData; -import no.nordicsemi.android.ble.error.GattError; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; -import no.nordicsemi.android.nrftoolbox.parser.AlertLevelParser; - -@SuppressWarnings("WeakerAccess") -class ProximityManager extends BatteryManager { - /** Link Loss service UUID. */ - final static UUID LINK_LOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb"); - /** Immediate Alert service UUID. */ - private final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb"); - /** Alert Level characteristic UUID. */ - private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb"); - - private BluetoothGattCharacteristic mAlertLevelCharacteristic, mLinkLossCharacteristic; - private boolean mAlertOn; - - ProximityManager(final Context context) { - super(context); - } - - @Override - protected boolean shouldAutoConnect() { - return true; - } - - @NonNull - @Override - protected BatteryManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving indication, etc. - */ - private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { - - @Override - protected void initialize() { - super.initialize(); - writeCharacteristic(mLinkLossCharacteristic, AlertLevelData.highAlert()) - .done(device -> log(Log.INFO, "Link loss alert level set")) - .fail((device, status) -> log(Log.WARN, "Failed to set link loss level: " + status)) - .enqueue(); - } - - @Override - protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - final BluetoothGattService llService = gatt.getService(LINK_LOSS_SERVICE_UUID); - if (llService != null) { - mLinkLossCharacteristic = llService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID); - } - return mLinkLossCharacteristic != null; - } - - @Override - protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { - super.isOptionalServiceSupported(gatt); - final BluetoothGattService iaService = gatt.getService(IMMEDIATE_ALERT_SERVICE_UUID); - if (iaService != null) { - mAlertLevelCharacteristic = iaService.getCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID); - } - return mAlertLevelCharacteristic != null; - } - - @Override - protected void onDeviceDisconnected() { - super.onDeviceDisconnected(); - mAlertLevelCharacteristic = null; - mLinkLossCharacteristic = null; - // Reset the alert flag - mAlertOn = false; - } - }; - - /** - * Toggles the immediate alert on the target device. - */ - public void toggleImmediateAlert() { - writeImmediateAlert(!mAlertOn); - } - - /** - * Writes the HIGH ALERT or NO ALERT command to the target device. - * - * @param on true to enable the alarm on proximity tag, false to disable it. - */ - public void writeImmediateAlert(final boolean on) { - if (!isConnected()) - return; - - writeCharacteristic(mAlertLevelCharacteristic, on ? AlertLevelData.highAlert() : AlertLevelData.noAlert()) - .before(device -> log(Log.VERBOSE, - on ? "Setting alarm to HIGH..." : "Disabling alarm...")) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, - "\"" + AlertLevelParser.parse(data) + "\" sent")) - .done(device -> { - mAlertOn = on; - mCallbacks.onRemoteAlarmSwitched(device, on); - }) - .fail((device, status) -> log(Log.WARN, - status == FailCallback.REASON_NULL_ATTRIBUTE ? - "Alert Level characteristic not found" : - GattError.parse(status))) - .enqueue(); - } - - /** - * Returns true if the alert has been enabled on the proximity tag, false otherwise. - */ - boolean isAlertEnabled() { - return mAlertOn; - } -} 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 deleted file mode 100644 index 9d2b867..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityManagerCallbacks.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import androidx.annotation.NonNull; - -import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; - -interface ProximityManagerCallbacks extends BatteryManagerCallbacks { - // No additional methods - void onRemoteAlarmSwitched(@NonNull final BluetoothDevice device, final boolean on); -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManager.java deleted file mode 100644 index b381d3d..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManager.java +++ /dev/null @@ -1,386 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -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.Context; -import android.os.Handler; -import android.util.Log; - -import java.util.UUID; - -import no.nordicsemi.android.error.GattError; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.parser.AlertLevelParser; -import no.nordicsemi.android.nrftoolbox.profile.multiconnect.IDeviceLogger; -import no.nordicsemi.android.nrftoolbox.utility.ParserUtils; - -class ProximityServerManager { - private final String TAG = "ProximityServerManager"; - - /** Immediate Alert service UUID */ - final static UUID IMMEDIATE_ALERT_SERVICE_UUID = UUID.fromString("00001802-0000-1000-8000-00805f9b34fb"); - /** Linkloss service UUID */ - final static UUID LINKLOSS_SERVICE_UUID = UUID.fromString("00001803-0000-1000-8000-00805f9b34fb"); - /** Alert Level characteristic UUID */ - private static final UUID ALERT_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A06-0000-1000-8000-00805f9b34fb"); - - private final static byte[] HIGH_ALERT = { 0x02 }; - private final static byte[] MILD_ALERT = { 0x01 }; - private final static byte[] NO_ALERT = { 0x00 }; - - private BluetoothGattServer mBluetoothGattServer; - private ProximityServerManagerCallbacks mCallbacks; - private IDeviceLogger mLogger; - private Handler mHandler; - private OnServerOpenCallback mOnServerOpenCallback; - private boolean mServerReady; - - public interface OnServerOpenCallback { - /** - * Method called when the GATT server was created and all services were added successfully. - */ - void onGattServerOpen(); - /** - * Method called when the GATT server failed to open and initialize services. - * -1 is returned when the server failed to start. - */ - void onGattServerFailed(final int error); - } - - ProximityServerManager(final ProximityServerManagerCallbacks callbacks) { - mHandler = new Handler(); - mCallbacks = callbacks; - } - - /** - * Sets the logger object. Logger is used to create logs in nRF Logger application. - * - * @param logger the logger object - */ - public void setLogger(final IDeviceLogger logger) { - mLogger = logger; - } - - /** - * Opens GATT server and creates 2 services: Link Loss Service and Immediate Alert Service. - * The callback is called when initialization is complete. - * - * @param context the context. - * @param callback optional callback notifying when all services has been added. - */ - public void openGattServer(final Context context, final OnServerOpenCallback callback) { - // Is the server already open? - if (mBluetoothGattServer != null) { - if (callback != null) - callback.onGattServerOpen(); - return; - } - - mOnServerOpenCallback = callback; - - final BluetoothManager manager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); - mBluetoothGattServer = manager.openGattServer(context, mGattServerCallbacks); - if (mBluetoothGattServer != null) { - // Start adding services one by one. The onServiceAdded method will be called when it completes. - addImmediateAlertService(); - } else { - if (callback != null) - callback.onGattServerFailed(-1); - mOnServerOpenCallback = null; - } - } - - /** - * Returns true if GATT server was opened and configured correctly. - * False if hasn't been opened, was closed, of failed to start. - */ - public boolean isServerReady() { - return mServerReady; - } - - /** - * Closes the GATT server. It will also disconnect all existing connections. - * If the service has already been closed, or hasn't been open, this method does nothing. - */ - public void closeGattServer() { - if (mBluetoothGattServer != null) { - mBluetoothGattServer.close(); - mBluetoothGattServer = null; - mOnServerOpenCallback = null; - mServerReady = false; - } - } - - /** - * This method notifies the Android that the Proximity profile will use the server connection - * to given device. If the server hasn't been open this method does nothing. - * The {@link #cancelConnection(BluetoothDevice)} method should be called when the connection - * is no longer used. - * - * @param device the target device. - */ - public void openConnection(final BluetoothDevice device) { - if (mBluetoothGattServer != null) { - mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Creating server connection..."); - mLogger.log(device, LogContract.Log.Level.DEBUG, "server.connect(device, autoConnect = true)"); - mBluetoothGattServer.connect(device, true); // In proximity the autoConnect is true - } - } - - /** - * Cancels the connection to the given device. This notifies Android that this profile will - * no longer use this connection and it can be disconnected. In practice, this method does - * not disconnect, so if the remote device decides still to use the phone's GATT server it - * will be able to do so. - *

- * This bug/feature can be tested using a proximity tag that does not release its connection - * when it got disconnected: - *

    - *
  1. Connect to your Proximity Tag.
  2. - *
  3. Verify that the bidirectional connection works - test the FIND ME button in - * nRF Toolbox and the FIND PHONE button on the tag.
  4. - *
  5. Disconnect from the tag
  6. - *
  7. When the device disappear from the list of devices click the FIND PHONE button on - * the tag. Your phone should still trigger an alarm, as the connection tag->phone - * is still active.
  8. - *
- * In order to avoid this issue make sure that your tag disconnects gently from phone when it - * got disconnected itself. - * - * @param device the device that will no longer be used. - */ - public void cancelConnection(final BluetoothDevice device) { - if (mBluetoothGattServer != null) { - mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Cancelling server connection..."); - mLogger.log(device, LogContract.Log.Level.DEBUG, "server.cancelConnection(device)"); - mBluetoothGattServer.cancelConnection(device); - } - } - - private void addImmediateAlertService() { - /* - * This method must be called in UI thread. It works fine on Nexus devices but if called - * from other thread (e.g. from onServiceAdded in gatt server callback) it hangs the app. - */ - final BluetoothGattCharacteristic alertLevel = - new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, - BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, - BluetoothGattCharacteristic.PERMISSION_WRITE); - alertLevel.setValue(NO_ALERT); - final BluetoothGattService immediateAlertService = - new BluetoothGattService(IMMEDIATE_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 (e.g. from onServiceAdded in gatt server callback) it hangs the app. - */ - final BluetoothGattCharacteristic linkLossAlertLevel = - new BluetoothGattCharacteristic(ALERT_LEVEL_CHARACTERISTIC_UUID, - BluetoothGattCharacteristic.PROPERTY_WRITE | BluetoothGattCharacteristic.PROPERTY_READ, - BluetoothGattCharacteristic.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ); - linkLossAlertLevel.setValue(HIGH_ALERT); - final 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 onServiceAdded(final int status, final BluetoothGattService service) { - if (status == BluetoothGatt.GATT_SUCCESS) { - // Adding another service from callback thread fails on Samsung S4 with Android 4.3 - mHandler.post(() -> { - if (IMMEDIATE_ALERT_SERVICE_UUID.equals(service.getUuid())) { - addLinkLossService(); - } else { - mServerReady = true; - // Both services has been added - if (mOnServerOpenCallback != null) - mOnServerOpenCallback.onGattServerOpen(); - mOnServerOpenCallback = null; - } - }); - } else { - Log.e(TAG, "GATT Server failed to add service, status: " + status); - if (mOnServerOpenCallback != null) - mOnServerOpenCallback.onGattServerFailed(status); - mOnServerOpenCallback = null; - } - } - - @Override - public void onConnectionStateChange(final BluetoothDevice device, final int status, final int newState) { - mLogger.log(device, LogContract.Log.Level.DEBUG, - "[Server callback] Connection state changed with status: " + status - + " and new state: " + newState + " (" + stateToString(newState) + ")"); - if (status == BluetoothGatt.GATT_SUCCESS) { - if (newState == BluetoothGatt.STATE_CONNECTED) { - mLogger.log(device, LogContract.Log.Level.INFO, - "[Server] Device with address " + device.getAddress() + " connected"); - } else { - mLogger.log(device, LogContract.Log.Level.INFO, "[Server] Device disconnected"); - mCallbacks.onAlarmStopped(device); - } - } else { - mLogger.log(device, LogContract.Log.Level.ERROR, "[Server] Error " + status + - " (0x" + Integer.toHexString(status) + "): " + GattError.parseConnectionError(status)); - } - } - - @Override - public void onCharacteristicReadRequest(final BluetoothDevice device, final int requestId, - final int offset, final BluetoothGattCharacteristic characteristic) { - mLogger.log(device, LogContract.Log.Level.DEBUG, - "[Server callback] Read request for characteristic " + characteristic.getUuid() - + " (requestId=" + requestId + ", offset=" + offset + ")"); - mLogger.log(device, LogContract.Log.Level.INFO, - "[Server] READ request for characteristic " + characteristic.getUuid() + " received"); - - byte[] value = characteristic.getValue(); - if (value != null && offset > 0) { - byte[] offsetValue = new byte[value.length - offset]; - System.arraycopy(value, offset, offsetValue, 0, offsetValue.length); - value = offsetValue; - } - if (value != null) { - mLogger.log(device, LogContract.Log.Level.DEBUG, - "server.sendResponse(GATT_SUCCESS, value=" + ParserUtils.parseDebug(value) + ")"); - } else { - mLogger.log(device, LogContract.Log.Level.DEBUG, "server.sendResponse(GATT_SUCCESS, value=null)"); - } - mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value); - mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent"); - } - - @Override - public void onCharacteristicWriteRequest(final BluetoothDevice device, final int requestId, - final BluetoothGattCharacteristic characteristic, final boolean preparedWrite, - final boolean responseNeeded, final int offset, final byte[] value) { - mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server callback] Write request to characteristic " + characteristic.getUuid() - + " (requestId=" + requestId + ", prepareWrite=" + preparedWrite + ", responseNeeded=" + responseNeeded - + ", offset=" + offset + ", value=" + ParserUtils.parseDebug(value) + ")"); - final String writeType = !responseNeeded ? "WRITE NO RESPONSE" : "WRITE COMMAND"; - mLogger.log(device, LogContract.Log.Level.INFO, "[Server] " + writeType - + " request for characteristic " + characteristic.getUuid() + " received, value: " + ParserUtils.parse(value)); - - if (offset == 0) { - characteristic.setValue(value); - } else { - final byte[] currentValue = characteristic.getValue(); - final byte[] newValue = new byte[currentValue.length + value.length]; - System.arraycopy(currentValue, 0, newValue, 0, currentValue.length); - System.arraycopy(value, 0, newValue, offset, value.length); - characteristic.setValue(newValue); - } - - if (!preparedWrite && value != null && value.length == 1) { // small validation - if (value[0] != NO_ALERT[0]) { - mLogger.log(device, LogContract.Log.Level.APPLICATION, - "[Server] Immediate alarm request received: " + AlertLevelParser.parse(characteristic)); - mCallbacks.onAlarmTriggered(device); - } else { - mLogger.log(device, LogContract.Log.Level.APPLICATION, - "[Server] Immediate alarm request received: OFF"); - mCallbacks.onAlarmStopped(device); - } - } - - mLogger.log(device, LogContract.Log.Level.DEBUG, "server.sendResponse(GATT_SUCCESS, offset=" - + offset + ", value=" + ParserUtils.parseDebug(value) + ")"); - mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null); - mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent"); - } - - @Override - public void onDescriptorReadRequest(final BluetoothDevice device, final int requestId, - final int offset, final BluetoothGattDescriptor descriptor) { - mLogger.log(device, LogContract.Log.Level.DEBUG, - "[Server callback] Write request to descriptor " + descriptor.getUuid() + " (requestId=" + requestId + ", offset=" + offset + ")"); - mLogger.log(device, LogContract.Log.Level.INFO, - "[Server] READ request for descriptor " + descriptor.getUuid() + " received"); - // This method is not supported - mLogger.log(device, LogContract.Log.Level.WARNING, "[Server] Operation not supported"); - mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server] server.sendResponse(GATT_REQUEST_NOT_SUPPORTED)"); - mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED, offset, null); - mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent"); - } - - @Override - public void onDescriptorWriteRequest(final BluetoothDevice device, final int requestId, - final BluetoothGattDescriptor descriptor, final boolean preparedWrite, - final boolean responseNeeded, final int offset, final byte[] value) { - mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server callback] Write request to descriptor " + descriptor.getUuid() - + " (requestId=" + requestId + ", prepareWrite=" + preparedWrite + ", responseNeeded=" + responseNeeded - + ", offset=" + offset + ", value=" + ParserUtils.parse(value) + ")"); - mLogger.log(device, LogContract.Log.Level.INFO, "[Server] READ request for descriptor " + descriptor.getUuid() + " received"); - // This method is not supported - mLogger.log(device, LogContract.Log.Level.WARNING, "[Server] Operation not supported"); - mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server] server.sendResponse(GATT_REQUEST_NOT_SUPPORTED)"); - mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED, offset, null); - mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent"); - } - - @Override - public void onExecuteWrite(final BluetoothDevice device, final int requestId, final boolean execute) { - mLogger.log(device, LogContract.Log.Level.DEBUG, - "[Server callback] Execute write request (requestId=" + requestId + ", execute=" + execute + ")"); - // This method is not supported - mLogger.log(device, LogContract.Log.Level.WARNING, "[Server] Operation not supported"); - mLogger.log(device, LogContract.Log.Level.DEBUG, "[Server] server.sendResponse(GATT_REQUEST_NOT_SUPPORTED)"); - mBluetoothGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_REQUEST_NOT_SUPPORTED, 0, null); - mLogger.log(device, LogContract.Log.Level.VERBOSE, "[Server] Response sent"); - } - }; - - /** - * Converts the connection state to String value. - * - * @param state the connection state. - * @return The state as String. - */ - private String stateToString(final int state) { - switch (state) { - case BluetoothProfile.STATE_CONNECTED: - return "CONNECTED"; - case BluetoothProfile.STATE_CONNECTING: - return "CONNECTING"; - case BluetoothProfile.STATE_DISCONNECTING: - return "DISCONNECTING"; - default: - return "DISCONNECTED"; - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManagerCallbacks.java deleted file mode 100644 index 9270d33..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityServerManagerCallbacks.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import androidx.annotation.NonNull; - -public interface ProximityServerManagerCallbacks { - void onAlarmTriggered(@NonNull final BluetoothDevice device); - - void onAlarmStopped(@NonNull final BluetoothDevice device); -} 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 deleted file mode 100644 index b9a195e..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/proximity/ProximityService.java +++ /dev/null @@ -1,570 +0,0 @@ -/* - * 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 android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.media.AudioManager; -import android.media.MediaPlayer; -import android.media.RingtoneManager; -import android.net.Uri; -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; -import androidx.core.app.NotificationManagerCompat; -import androidx.core.content.ContextCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import android.text.TextUtils; -import android.util.Log; - -import java.io.IOException; -import java.util.LinkedList; -import java.util.List; - -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.FeaturesActivity; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; -import no.nordicsemi.android.nrftoolbox.profile.multiconnect.BleMulticonnectProfileService; - -public class ProximityService extends BleMulticonnectProfileService implements ProximityManagerCallbacks, ProximityServerManagerCallbacks { - @SuppressWarnings("unused") - private static final String TAG = "ProximityService"; - - public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL"; - public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL"; - - public static final String BROADCAST_ALARM_SWITCHED = "no.nordicsemi.android.nrftoolbox.BROADCAST_ALARM_SWITCHED"; - public static final String EXTRA_ALARM_STATE = "no.nordicsemi.android.nrftoolbox.EXTRA_ALARM_STATE"; - - private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.proximity.ACTION_DISCONNECT"; - private final static String ACTION_FIND = "no.nordicsemi.android.nrftoolbox.proximity.ACTION_FIND"; - private final static String ACTION_SILENT = "no.nordicsemi.android.nrftoolbox.proximity.ACTION_SILENT"; - - private final static String PROXIMITY_GROUP_ID = "proximity_connected_tags"; - private final static int NOTIFICATION_ID = 1000; - private final static int OPEN_ACTIVITY_REQ = 0; - private final static int DISCONNECT_REQ = 1; - private final static int FIND_REQ = 2; - private final static int SILENT_REQ = 3; - - private final ProximityBinder mBinder = new ProximityBinder(); - private ProximityServerManager mServerManager; - private MediaPlayer mMediaPlayer; - private int mOriginalVolume; - /** - * When a device starts an alarm on the phone it is added to this list. - * Alarm is disabled when this list is empty. - */ - private List mDevicesWithAlarm; - - private int mAttempt; - private final static int MAX_ATTEMPTS = 1; - - /** - * This local binder is an interface for the bonded activity to operate with the proximity - * sensor. - */ - public class ProximityBinder extends LocalBinder { - /** - * Toggles the Immediate Alert on given remote device. - * - * @param device the connected device. - */ - public void toggleImmediateAlert(final BluetoothDevice device) { - final ProximityManager manager = (ProximityManager) getBleManager(device); - manager.toggleImmediateAlert(); - } - - /** - * Returns the current alarm state on given device. This value is not read from the device, - * it's just the last value written to it (initially false). - * - * @param device the connected device. - * @return True if alarm has been enabled, false if disabled. - */ - public boolean isImmediateAlertOn(final BluetoothDevice device) { - final ProximityManager manager = (ProximityManager) getBleManager(device); - return manager.isAlertEnabled(); - } - - /** - * Returns the last received battery level value. - * - * @param device the device of which battery level should be returned. - * @return Battery value or null if no value was received or Battery Level characteristic - * was not found, or the device is disconnected. - */ - public Integer getBatteryLevel(final BluetoothDevice device) { - final ProximityManager manager = (ProximityManager) getBleManager(device); - return manager.getBatteryLevel(); - } - } - - @Override - protected LocalBinder getBinder() { - return mBinder; - } - - @Override - protected LoggableBleManager initializeManager() { - return new ProximityManager(this); - } - - /** - * 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) { - final BluetoothDevice device = intent.getParcelableExtra(EXTRA_DEVICE); - mBinder.log(device, LogContract.Log.Level.INFO, "[Notification] DISCONNECT action pressed"); - mBinder.disconnect(device); - } - }; - - /** - * This broadcast receiver listens for {@link #ACTION_FIND} or {@link #ACTION_SILENT} that may - * be fired by pressing Find me action button on the notification. - */ - private final BroadcastReceiver mToggleAlarmActionBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(final Context context, final Intent intent) { - final BluetoothDevice device = intent.getParcelableExtra(EXTRA_DEVICE); - switch (intent.getAction()) { - case ACTION_FIND: - mBinder.log(device, LogContract.Log.Level.INFO, "[Notification] FIND action pressed"); - break; - case ACTION_SILENT: - mBinder.log(device, LogContract.Log.Level.INFO, "[Notification] SILENT action pressed"); - break; - } - mBinder.toggleImmediateAlert(device); - } - }; - - @Override - protected void onServiceCreated() { - mServerManager = new ProximityServerManager(this); - mServerManager.setLogger(mBinder); - - initializeAlarm(); - - registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT)); - final IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_FIND); - filter.addAction(ACTION_SILENT); - registerReceiver(mToggleAlarmActionBroadcastReceiver, filter); - } - - @Override - public void onServiceStopped() { - cancelNotifications(); - - // Close the GATT server. If it hasn't been opened this method does nothing - mServerManager.closeGattServer(); - - releaseAlarm(); - - unregisterReceiver(mDisconnectActionBroadcastReceiver); - unregisterReceiver(mToggleAlarmActionBroadcastReceiver); - - super.onServiceStopped(); - } - - @Override - protected void onBluetoothEnabled() { - mAttempt = 0; - getHandler().post(new Runnable() { - @Override - public void run() { - final Runnable that = this; - // Start the GATT Server only if Bluetooth is enabled - mServerManager.openGattServer(ProximityService.this, - new ProximityServerManager.OnServerOpenCallback() { - @Override - public void onGattServerOpen() { - // We are now ready to reconnect devices - ProximityService.super.onBluetoothEnabled(); - } - - @Override - public void onGattServerFailed(final int error) { - mServerManager.closeGattServer(); - - if (mAttempt < MAX_ATTEMPTS) { - mAttempt++; - getHandler().postDelayed(that, 2000); - } else { - showToast(getString(R.string.proximity_server_error, error)); - // GATT server failed to start, but we may connect as a client - ProximityService.super.onBluetoothEnabled(); - } - } - }); - } - }); - } - - @Override - protected void onBluetoothDisabled() { - super.onBluetoothDisabled(); - // Close the GATT server - mServerManager.closeGattServer(); - } - - @Override - protected void onRebind() { - // When the activity rebinds to the service, remove the notification - cancelNotifications(); - - // This method will read the Battery Level value from each connected device, if possible - // and then try to enable battery notifications (if it has NOTIFY property). - // If the Battery Level characteristic has only the NOTIFY property, it will only try to - // enable notifications. - for (final BluetoothDevice device : getManagedDevices()) { - final ProximityManager manager = (ProximityManager) getBleManager(device); - manager.readBatteryLevelCharacteristic(); - manager.enableBatteryLevelCharacteristicNotifications(); - } - } - - @Override - public void onUnbind() { - // When we are connected, but the application is not open, we are not really interested - // in battery level notifications. But we will still be receiving other values, if enabled. - for (final BluetoothDevice device : getManagedDevices()) { - final ProximityManager manager = (ProximityManager) getBleManager(device); - manager.disableBatteryLevelCharacteristicNotifications(); - } - - createBackgroundNotification(); - } - - @Override - public void onDeviceConnected(final BluetoothDevice device) { - super.onDeviceConnected(device); - - if (!mBound) { - createBackgroundNotification(); - } - } - - @Override - public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { - super.onServicesDiscovered(device, optionalServicesFound); - mServerManager.openConnection(device); - } - - @Override - public void onLinkLossOccurred(final BluetoothDevice device) { - mServerManager.cancelConnection(device); - stopAlarm(device); - super.onLinkLossOccurred(device); - - if (!mBound) { - createBackgroundNotification(); - if (BluetoothAdapter.getDefaultAdapter().isEnabled()) - createLinkLossNotification(device); - else - cancelNotification(device); - } - } - - @Override - public void onDeviceDisconnected(final BluetoothDevice device) { - mServerManager.cancelConnection(device); - stopAlarm(device); - super.onDeviceDisconnected(device); - - if (!mBound) { - cancelNotification(device); - createBackgroundNotification(); - } - } - - @Override - public void onAlarmTriggered(@NonNull final BluetoothDevice device) { - playAlarm(device); - } - - @Override - public void onAlarmStopped(@NonNull final BluetoothDevice device) { - stopAlarm(device); - } - - @Override - public void onRemoteAlarmSwitched(@NonNull final BluetoothDevice device, final boolean on) { - final Intent broadcast = new Intent(BROADCAST_ALARM_SWITCHED); - broadcast.putExtra(EXTRA_DEVICE, device); - broadcast.putExtra(EXTRA_ALARM_STATE, on); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - - if (!mBound) { - createBackgroundNotification(); - } - } - - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); - broadcast.putExtra(EXTRA_DEVICE, device); - broadcast.putExtra(EXTRA_BATTERY_LEVEL, batteryLevel); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - private void createBackgroundNotification() { - final List connectedDevices = getConnectedDevices(); - for (final BluetoothDevice device : connectedDevices) { - createNotificationForConnectedDevice(device); - } - createSummaryNotification(); - } - - private void createSummaryNotification() { - final NotificationCompat.Builder builder = getNotificationBuilder(); - builder.setColor(ContextCompat.getColor(this, R.color.actionBarColorDark)); - builder.setShowWhen(false).setDefaults(0); - // An ongoing notification will not be shown on Android Wear. - builder.setOngoing(true); - builder.setGroup(PROXIMITY_GROUP_ID).setGroupSummary(true); - builder.setContentTitle(getString(R.string.app_name)); - - final List managedDevices = getManagedDevices(); - final List connectedDevices = getConnectedDevices(); - if (connectedDevices.isEmpty()) { - // No connected devices - final int numberOfManagedDevices = managedDevices.size(); - if (numberOfManagedDevices == 1) { - final String name = getDeviceName(managedDevices.get(0)); - // We don't use plurals here, as we only have the default language and 'one' is not - // in every language (versions differ in %d or %s) and throw an exception in e.g. in Chinese. - builder.setContentText(getString(R.string.proximity_notification_text_nothing_connected_one_disconnected, name)); - } else { - builder.setContentText(getString(R.string.proximity_notification_text_nothing_connected_number_disconnected, numberOfManagedDevices)); - } - } else { - // There are some proximity tags connected - final StringBuilder text = new StringBuilder(); - - final int numberOfConnectedDevices = connectedDevices.size(); - if (numberOfConnectedDevices == 1) { - final String name = getDeviceName(connectedDevices.get(0)); - text.append(getString(R.string.proximity_notification_summary_text_name, name)); - } else { - text.append(getString(R.string.proximity_notification_summary_text_number, numberOfConnectedDevices)); - } - - // If there are some disconnected devices, also print them - final int numberOfDisconnectedDevices = managedDevices.size() - numberOfConnectedDevices; - if (numberOfDisconnectedDevices == 1) { - text.append(", "); - // Find the single disconnected device to get its name - for (final BluetoothDevice device : managedDevices) { - if (!isConnected(device)) { - final String name = getDeviceName(device); - text.append(getString(R.string.proximity_notification_text_nothing_connected_one_disconnected, name)); - break; - } - } - } else if (numberOfDisconnectedDevices > 1) { - text.append(", "); - // If there are more, just write number of them - text.append(getString(R.string.proximity_notification_text_nothing_connected_number_disconnected, numberOfDisconnectedDevices)); - } - text.append("."); - builder.setContentText(text); - } - - final Notification notification = builder.build(); - final NotificationManagerCompat nm = NotificationManagerCompat.from(this); - nm.notify(NOTIFICATION_ID, notification); - } - - /** - * Creates the notification for given connected device. - * Adds 3 action buttons: DISCONNECT, FIND and SILENT which perform given action on the device. - */ - private void createNotificationForConnectedDevice(final BluetoothDevice device) { - final NotificationCompat.Builder builder = getNotificationBuilder(); - builder.setColor(ContextCompat.getColor(this, R.color.actionBarColorDark)); - builder.setGroup(PROXIMITY_GROUP_ID).setDefaults(0); - // An ongoing notification will not be shown on Android Wear. - builder.setOngoing(true); - builder.setContentTitle(getString(R.string.proximity_notification_text, getDeviceName(device))); - - // Add DISCONNECT action - final Intent disconnect = new Intent(ACTION_DISCONNECT); - disconnect.putExtra(EXTRA_DEVICE, device); - final PendingIntent disconnectAction = - PendingIntent.getBroadcast(this, DISCONNECT_REQ + device.hashCode(), - disconnect, PendingIntent.FLAG_UPDATE_CURRENT); - builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.proximity_action_disconnect), disconnectAction)); - // This will keep the same order of notification even after an action was clicked on one of them. - builder.setSortKey(getDeviceName(device) + device.getAddress()); - - // Add FIND or SILENT action - final ProximityManager manager = (ProximityManager) getBleManager(device); - if (manager.isAlertEnabled()) { - final Intent silentAllIntent = new Intent(ACTION_SILENT); - silentAllIntent.putExtra(EXTRA_DEVICE, device); - final PendingIntent silentAction = - PendingIntent.getBroadcast(this, SILENT_REQ + device.hashCode(), - silentAllIntent, PendingIntent.FLAG_UPDATE_CURRENT); - builder.addAction(new NotificationCompat.Action(R.drawable.ic_stat_notify_proximity_silent, getString(R.string.proximity_action_silent), silentAction)); - } else { - final Intent findAllIntent = new Intent(ACTION_FIND); - findAllIntent.putExtra(EXTRA_DEVICE, device); - final PendingIntent findAction = - PendingIntent.getBroadcast(this, FIND_REQ + device.hashCode(), - findAllIntent, PendingIntent.FLAG_UPDATE_CURRENT); - builder.addAction(new NotificationCompat.Action(R.drawable.ic_stat_notify_proximity_find, getString(R.string.proximity_action_find), findAction)); - } - - final Notification notification = builder.build(); - final NotificationManagerCompat nm = NotificationManagerCompat.from(this); - nm.notify(device.getAddress(), NOTIFICATION_ID, notification); - } - - /** - * Creates a notification showing information about a device that got disconnected. - */ - private void createLinkLossNotification(final BluetoothDevice device) { - final NotificationCompat.Builder builder = getNotificationBuilder(); - builder.setColor(ContextCompat.getColor(this, R.color.orange)); - - final Uri notificationUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM); - // Make sure the sound is played even in DND mode - builder.setSound(notificationUri, AudioManager.STREAM_ALARM); - builder.setPriority(NotificationCompat.PRIORITY_HIGH); - builder.setCategory(NotificationCompat.CATEGORY_ALARM); - builder.setShowWhen(true); - // An ongoing notification would not be shown on Android Wear. - builder.setOngoing(false); - // This notification is to be shown not in a group - - final String name = getDeviceName(device); - builder.setContentTitle(getString(R.string.proximity_notification_link_loss_alert, name)); - builder.setTicker(getString(R.string.proximity_notification_link_loss_alert, name)); - - final Notification notification = builder.build(); - final NotificationManagerCompat nm = NotificationManagerCompat.from(this); - nm.notify(device.getAddress(), NOTIFICATION_ID, notification); - } - - private NotificationCompat.Builder getNotificationBuilder() { - final Intent parentIntent = new Intent(this, FeaturesActivity.class); - parentIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - final Intent targetIntent = new Intent(this, ProximityActivity.class); - - // Both activities above have launchMode="singleTask" in the AndroidManifest.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 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.PROXIMITY_WARNINGS_CHANNEL); - builder.setContentIntent(pendingIntent).setAutoCancel(false); - builder.setSmallIcon(R.drawable.ic_stat_notify_proximity); - return builder; - } - - /** - * Cancels the existing notification. If there is no active notification this method does nothing - */ - private void cancelNotifications() { - final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - nm.cancel(NOTIFICATION_ID); - - final List managedDevices = getManagedDevices(); - for (final BluetoothDevice device : managedDevices) { - nm.cancel(device.getAddress(), NOTIFICATION_ID); - } - } - - /** - * Cancels the existing notification for given device. If there is no active notification this method does nothing - */ - private void cancelNotification(final BluetoothDevice device) { - final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); - nm.cancel(device.getAddress(), NOTIFICATION_ID); - } - - private void initializeAlarm() { - mDevicesWithAlarm = new LinkedList<>(); - mMediaPlayer = new MediaPlayer(); - mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM); - mMediaPlayer.setLooping(true); - mMediaPlayer.setVolume(1.0f, 1.0f); - try { - mMediaPlayer.setDataSource(this, RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM)); - } catch (final IOException e) { - Log.e(TAG, "Initialize Alarm failed: ", e); - } - } - - private void releaseAlarm() { - mMediaPlayer.release(); - mMediaPlayer = null; - } - - private void playAlarm(final BluetoothDevice device) { - final boolean alarmPlaying = !mDevicesWithAlarm.isEmpty(); - if (!mDevicesWithAlarm.contains(device)) - mDevicesWithAlarm.add(device); - - if (!alarmPlaying) { - // Save the current alarm volume and set it to max - final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - mOriginalVolume = am.getStreamVolume(AudioManager.STREAM_ALARM); - am.setStreamVolume(AudioManager.STREAM_ALARM, am.getStreamMaxVolume(AudioManager.STREAM_ALARM), AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); - try { - mMediaPlayer.prepare(); - mMediaPlayer.start(); - } catch (final IOException e) { - Log.e(TAG, "Prepare Alarm failed: ", e); - } - } - } - - private void stopAlarm(final BluetoothDevice device) { - mDevicesWithAlarm.remove(device); - if (mDevicesWithAlarm.isEmpty() && mMediaPlayer.isPlaying()) { - mMediaPlayer.stop(); - // Restore original volume - final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); - am.setStreamVolume(AudioManager.STREAM_ALARM, mOriginalVolume, 0); - } - } - - private String getDeviceName(final BluetoothDevice device) { - String name = device.getName(); - if (TextUtils.isEmpty(name)) - name = getString(R.string.proximity_default_device_name); - return name; - } -} 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 deleted file mode 100644 index 2d052b0..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCActivity.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.PreferenceManager; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import android.view.Menu; -import android.widget.TextView; - -import java.util.Locale; -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.rsc.settings.SettingsActivity; -import no.nordicsemi.android.nrftoolbox.rsc.settings.SettingsFragment; - -public class RSCActivity extends BleProfileServiceReadyActivity { - private TextView mSpeedView; - private TextView mSpeedUnitView; - private TextView mCadenceView; - private TextView mDistanceView; - private TextView mDistanceUnitView; - private TextView mTotalDistanceView; - private TextView mTotalDistanceUnitView; - private TextView mStridesCountView; - private TextView mActivityView; - private TextView mBatteryLevelView; - - @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 = findViewById(R.id.speed); - mSpeedUnitView = findViewById(R.id.speed_unit); - mCadenceView = findViewById(R.id.cadence); - mDistanceView = findViewById(R.id.distance); - mDistanceUnitView = findViewById(R.id.distance_unit); - mTotalDistanceView = findViewById(R.id.total_distance); - mTotalDistanceUnitView = findViewById(R.id.total_distance_unit); - mStridesCountView = findViewById(R.id.strides); - mActivityView = findViewById(R.id.activity); - mBatteryLevelView = findViewById(R.id.battery); - } - - @Override - protected void onResume() { - super.onResume(); - setDefaultUI(); - } - - @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); - mTotalDistanceView.setText(R.string.not_available_value); - mStridesCountView.setText(R.string.not_available_value); - mActivityView.setText(R.string.not_available); - mBatteryLevelView.setText(R.string.not_available); - - setUnits(); - } - - private void setUnits() { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT))); - - switch (unit) { - case SettingsFragment.SETTINGS_UNIT_M_S: // [m/s] - mSpeedUnitView.setText(R.string.rsc_speed_unit_m_s); - mDistanceUnitView.setText(R.string.rsc_distance_unit_m); - mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km); - break; - case SettingsFragment.SETTINGS_UNIT_KM_H: // [km/h] - mSpeedUnitView.setText(R.string.rsc_speed_unit_km_h); - mDistanceUnitView.setText(R.string.rsc_distance_unit_m); - mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km); - break; - case SettingsFragment.SETTINGS_UNIT_MPH: // [mph] - mSpeedUnitView.setText(R.string.rsc_speed_unit_mph); - mDistanceUnitView.setText(R.string.rsc_distance_unit_yd); - mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile); - break; - } - } - - @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 - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.settings_and_about, 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 RSCService.class; - } - - @Override - protected UUID getFilterUUID() { - return RSCManager.RUNNING_SPEED_AND_CADENCE_SERVICE_UUID; - } - - @Override - protected void onServiceBound(final RSCService.RSCBinder binder) { - // not used - } - - @Override - protected void onServiceUnbound() { - // not used - } - - @Override - public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { - // not used - } - - @Override - public void onDeviceDisconnected(final BluetoothDevice device) { - super.onDeviceDisconnected(device); - mBatteryLevelView.setText(R.string.not_available); - } - - private void onMeasurementReceived(float speed, int cadence, long totalDistance, final boolean running) { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT))); - - switch (unit) { - case SettingsFragment.SETTINGS_UNIT_KM_H: - speed = speed * 3.6f; - // pass through intended - case SettingsFragment.SETTINGS_UNIT_M_S: - if (totalDistance == -1) { - mTotalDistanceView.setText(R.string.not_available); - mTotalDistanceUnitView.setText(null); - } else { - mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1000.0f)); // 1 km in m - mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_km); - } - break; - case SettingsFragment.SETTINGS_UNIT_MPH: - speed = speed * 2.2369f; - if (totalDistance == -1) { - mTotalDistanceView.setText(R.string.not_available); - mTotalDistanceUnitView.setText(null); - } else { - mTotalDistanceView.setText(String.format(Locale.US, "%.2f", totalDistance / 1609.31f)); // 1 mile in m - mTotalDistanceUnitView.setText(R.string.rsc_total_distance_unit_mile); - } - break; - } - - mSpeedView.setText(String.format(Locale.US, "%.1f", speed)); - mCadenceView.setText(String.format(Locale.US, "%d", cadence)); - mActivityView.setText(running ? R.string.rsc_running : R.string.rsc_walking); - } - - private void onStripesUpdate(final long distance, final int strides) { - if (distance == -1) { - mDistanceView.setText(R.string.not_available); - mDistanceUnitView.setText(R.string.rsc_distance_unit_m); - } else { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); - final int unit = Integer.parseInt(preferences.getString(SettingsFragment.SETTINGS_UNIT, String.valueOf(SettingsFragment.SETTINGS_UNIT_DEFAULT))); - - switch (unit) { - case SettingsFragment.SETTINGS_UNIT_KM_H: - case SettingsFragment.SETTINGS_UNIT_M_S: - if (distance < 100000L) { // 1 km in cm - mDistanceView.setText(String.format(Locale.US, "%.1f", distance / 100.0f)); - mDistanceUnitView.setText(R.string.rsc_distance_unit_m); - } else { - mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 100000.0f)); - mDistanceUnitView.setText(R.string.rsc_distance_unit_km); - } - break; - case SettingsFragment.SETTINGS_UNIT_MPH: - if (distance < 160931L) { // 1 mile in cm - mDistanceView.setText(String.format(Locale.US, "%.1f", distance / 91.4392f)); - mDistanceUnitView.setText(R.string.rsc_distance_unit_yd); - } else { - mDistanceView.setText(String.format(Locale.US, "%.2f", distance / 160931.23f)); - mDistanceUnitView.setText(R.string.rsc_distance_unit_mile); - } - break; - } - } - - 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 long totalDistance = intent.getLongExtra(RSCService.EXTRA_TOTAL_DISTANCE, -1); - final boolean running = intent.getBooleanExtra(RSCService.EXTRA_ACTIVITY, false); - // Update GUI - onMeasurementReceived(speed, cadence, totalDistance, running); - } else if (RSCService.BROADCAST_STRIDES_UPDATE.equals(action)) { - final int strides = intent.getIntExtra(RSCService.EXTRA_STRIDES, 0); - final long distance = intent.getLongExtra(RSCService.EXTRA_DISTANCE, -1); - // Update GUI - onStripesUpdate(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 deleted file mode 100644 index aeb7ba8..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManager.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.UUID; - -import no.nordicsemi.android.ble.common.callback.rsc.RunningSpeedAndCadenceMeasurementDataCallback; -import no.nordicsemi.android.ble.data.Data; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; -import no.nordicsemi.android.nrftoolbox.parser.RSCMeasurementParser; - -public class RSCManager extends BatteryManager { - /** Running Speed and Cadence Measurement service UUID */ - public static final UUID RUNNING_SPEED_AND_CADENCE_SERVICE_UUID = UUID.fromString("00001814-0000-1000-8000-00805f9b34fb"); - /** Running Speed and Cadence Measurement characteristic UUID */ - private static final UUID RSC_MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00002A53-0000-1000-8000-00805f9b34fb"); - - private BluetoothGattCharacteristic mRSCMeasurementCharacteristic; - - RSCManager(final Context context) { - super(context); - } - - @NonNull - @Override - protected BatteryManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving indication, etc. - */ - private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { - - @Override - protected void initialize() { - super.initialize(); - setNotificationCallback(mRSCMeasurementCharacteristic) - .with(new RunningSpeedAndCadenceMeasurementDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, "\"" + RSCMeasurementParser.parse(data) + "\" received"); - super.onDataReceived(device, data); - } - - @Override - public void onRSCMeasurementReceived(@NonNull final BluetoothDevice device, final boolean running, - final float instantaneousSpeed, final int instantaneousCadence, - @Nullable final Integer strideLength, - @Nullable final Long totalDistance) { - mCallbacks.onRSCMeasurementReceived(device, running, instantaneousSpeed, - instantaneousCadence, strideLength, totalDistance); - } - }); - enableNotifications(mRSCMeasurementCharacteristic).enqueue(); - } - - @Override - public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - final BluetoothGattService service = gatt.getService(RUNNING_SPEED_AND_CADENCE_SERVICE_UUID); - if (service != null) { - mRSCMeasurementCharacteristic = service.getCharacteristic(RSC_MEASUREMENT_CHARACTERISTIC_UUID); - } - return mRSCMeasurementCharacteristic != null; - } - - @Override - protected void onDeviceDisconnected() { - super.onDeviceDisconnected(); - mRSCMeasurementCharacteristic = 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 deleted file mode 100644 index 1a06cd2..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCManagerCallbacks.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.ble.common.profile.rsc.RunningSpeedAndCadenceMeasurementCallback; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; - -interface RSCManagerCallbacks extends BatteryManagerCallbacks, RunningSpeedAndCadenceMeasurementCallback { - -} 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 deleted file mode 100644 index 0448033..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/RSCService.java +++ /dev/null @@ -1,252 +0,0 @@ -/* - * 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 android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Handler; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.app.NotificationCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; - -import no.nordicsemi.android.log.Logger; -import no.nordicsemi.android.nrftoolbox.FeaturesActivity; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; - -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_STRIDE_LENGTH = "no.nordicsemi.android.nrftoolbox.rsc.EXTRA_STRIDE_LENGTH"; - 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"; - - public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL"; - public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL"; - - private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.rsc.ACTION_DISCONNECT"; - - private RSCManager mManager; - - /** The last value of a cadence */ - private float mCadence; - /** Trip distance in cm */ - private long mDistance; - /** Stride length in cm */ - private Integer 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 bound activity to operate with the RSC sensor. - */ - class RSCBinder extends LocalBinder { - // empty - } - - @Override - protected LocalBinder getBinder() { - return mBinder; - } - - @Override - protected LoggableBleManager 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 - protected void onRebind() { - // when the activity rebinds to the service, remove the notification - cancelNotification(); - - if (isConnected()) { - // This method will read the Battery Level value, if possible and then try to enable battery notifications (if it has NOTIFY property). - // If the Battery Level characteristic has only the NOTIFY property, it will only try to enable notifications. - mManager.readBatteryLevelCharacteristic(); - } - } - - @Override - protected void onUnbind() { - // When we are connected, but the application is not open, we are not really interested in battery level notifications. - // But we will still be receiving other values, if enabled. - if (isConnected()) - mManager.disableBatteryLevelCharacteristicNotifications(); - - // when the activity closes we need to show the notification that user is connected to the sensor - createNotification(R.string.rsc_notification_connected_message, 0); - } - - private final Runnable mUpdateStridesTask = new Runnable() { - @Override - public void run() { - if (!isConnected()) - return; - - mStepsNumber++; - mDistance += mStrideLength; // [cm] - 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 * 60.0f / mCadence); - mHandler.postDelayed(mUpdateStridesTask, interval); - } else { - mTaskInProgress = false; - } - } - }; - - @Override - public void onRSCMeasurementReceived(@NonNull final BluetoothDevice device, final boolean running, - final float instantaneousSpeed, final int instantaneousCadence, - @Nullable final Integer strideLength, - @Nullable final Long totalDistance) { - final Intent broadcast = new Intent(BROADCAST_RSC_MEASUREMENT); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_SPEED, instantaneousSpeed); - broadcast.putExtra(EXTRA_CADENCE, instantaneousCadence); - broadcast.putExtra(EXTRA_STRIDE_LENGTH, strideLength); - broadcast.putExtra(EXTRA_TOTAL_DISTANCE, totalDistance); - broadcast.putExtra(EXTRA_ACTIVITY, running); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - - // Start strides counter if not in progress - mCadence = instantaneousCadence; - if (strideLength != null) { - mStrideLength = strideLength; - } - if (!mTaskInProgress && strideLength != null && instantaneousCadence > 0) { - mTaskInProgress = true; - - final long interval = (long) (1000.0f * 60.0f / mCadence); - mHandler.postDelayed(mUpdateStridesTask, interval); - } - } - - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { - final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_BATTERY_LEVEL, 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 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, 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 AndroidManifest.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 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL); - builder.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(new NotificationCompat.Action(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(), "[Notification] Disconnect action pressed"); - if (isConnected()) - getBinder().disconnect(); - else - stopSelf(); - } - }; - -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/settings/SettingsActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/settings/SettingsActivity.java deleted file mode 100644 index fb22c16..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/settings/SettingsActivity.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.settings; - -import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import android.view.MenuItem; - -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsActivity extends AppCompatActivity { - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_settings); - - final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - // Display the fragment as the main content. - getSupportFragmentManager().beginTransaction().replace(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/rsc/settings/SettingsFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/settings/SettingsFragment.java deleted file mode 100644 index 367309b..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/rsc/settings/SettingsFragment.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.settings; - -import android.os.Bundle; -import android.preference.PreferenceFragment; - -import androidx.preference.PreferenceFragmentCompat; -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsFragment extends PreferenceFragmentCompat { - public static final String SETTINGS_UNIT = "settings_rsc_unit"; - public static final int SETTINGS_UNIT_M_S = 0; // [m/s] - public static final int SETTINGS_UNIT_KM_H = 1; // [m/s] - public static final int SETTINGS_UNIT_MPH = 2; // [m/s] - public static final int SETTINGS_UNIT_DEFAULT = SETTINGS_UNIT_KM_H; - - @Override - public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { - addPreferencesFromResource(R.xml.settings_rsc); - } -} 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 deleted file mode 100644 index 7a248b5..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ExtendedBluetoothDevice.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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; - -import no.nordicsemi.android.support.v18.scanner.ScanResult; - -public class ExtendedBluetoothDevice { - /* package */ static final int NO_RSSI = -1000; - 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(final ScanResult scanResult) { - this.device = scanResult.getDevice(); - this.name = scanResult.getScanRecord() != null ? scanResult.getScanRecord().getDeviceName() : null; - this.rssi = scanResult.getRssi(); - this.isBonded = false; - } - - public ExtendedBluetoothDevice(final BluetoothDevice device) { - this.device = device; - this.name = device.getName(); - this.rssi = NO_RSSI; - this.isBonded = true; - } - - public boolean matches(final ScanResult scanResult) { - return device.getAddress().equals(scanResult.getDevice().getAddress()); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/Readme.txt b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/Readme.txt deleted file mode 100644 index aa3ffa4..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/Readme.txt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - - nRF Toolbox demonstrates how to implement the Bluetooth Smart features in an Android application. - It consists of number of profiles, like Heart Rate, Blood Pressure etc. that may be use as is to communicate with real devices. - They use the Bluetooth SIG adopted profiles, that may be found here: https://developer.bluetooth.org/gatt/profiles/Pages/ProfilesHome.aspx - - The Template Profile has been created to give a quick start with implementing proprietary services. Just start modifying 4 classes inside - the template package to implement features you need. - - Below you will find a short step-by-step tutorial: - - 1. The template consists of the following files: - - TemplateActivity - the main class that is responsible for managing the view of your profile - - TemplateService - the service that is started whenever you connect to a device. I handles the Bluetooth Smart communication using the... - - TemplateManager - the manager that handles all the BLE logic required to communicate with the device. The TemplateManager derives from - the BleManager which handles most of the event itself and propagates the data-relevant to deriving class. You don't - have to, or even shouldn't modify the BleManager (unless you want to change the default behaviour). - - TemplateManagerCallbacks - the interface with a list of callbacks that the TemplateManager can call. Each method is usually related to one - BLE event, e.g. receiving a new value of the characteristic.\ - - TemplateParser - an optional class in the .parser package that is responsible for converting the characteristic value to String. - This is used only for debugging. The String returned by the parse(..) method is then logged into the nRF Logger application - (if such installed). - - /settings/SettingsActivity and /settings/SettingsFragment - classes used to present user preferences. A stub implementation in the template. - - /res/layout/activity_feature_template.xml - the layout file for the TemplateActivity - - /res/values/strings_template.xml - a set of strings used in the layout file - - /res/xml/settings/template.xml - the user settings configuration - - /res/drawable/(x)hdpi/ic_template_feature.png - the template profile icon (HDPI, XHDPI). Please, keep the files size. - - /res/drawable/(x)hdpi/ic_stat_notify_template - the icon that is used in the notification - -2. The communication between the components goes as follows: - - User clicks the CONNECT button and selects a target device on TemplateActivity. - - The base class of the TemplateActivity starts the service given by getServiceClass() method. - - The service starts and initializes the TemplateManager. TemplateActivity binds to the service and is being given the TemplateBinder object (the service API) as a result. - - The manager connects to the device using Bluetooth Smart and discovers its services. - - The manager initializes the device. Initialization is done using the list of actions given by the initGatt(..) method in the TemplateManager. - Initialization usually contains enabling notifications, writing some initial values etc. - - When initialization is complete the manager calls the onDeviceReady() callback. - - The service sends the BROADCAST_DEVICE_READY broadcast to the activity. Communication from the Service to the Activity is always done using the LocalBroadcastManager broadcasts. - - The base class of the TemplateActivity listens to the broadcasts and calls appropriate methods. - - - When a custom event occurs, for example a notification is received, the manager parses the incoming data and calls the proper callback. - - The callback implementation in the TemplateService sends a broadcast message with values given in parameters. - - The TemplateActivity, which had registered a broadcast receiver before, listens to the broadcasts, reads the values and present them to users. - - - Communication Activity->Service is done using the API in the TemplateBinder. You may find the example of how to use it in the ProximityActivity. - -3. Please read the files listed above and the TODO messages for more information what to modify in the files. - -4. Remember to add your activities and the service in the AndroidManifest.xml file. The nRF Toolbox lists all activities with the following intent filter: - - - - - -5. Feel free to rename the nRF Toolbox application (/res/values/strings.xml ->app_name), change the toolbar colors (/res/values/color.xml -> actionBarColor, actionBarColorDark). - In order to remove unused profiles from the main FeaturesActivity just comment out their intent-filter tags in the AndroidManifest.xml file. diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateActivity.java deleted file mode 100644 index 60778ce..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateActivity.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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.template; - -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import android.view.Menu; -import android.widget.EditText; -import android.widget.Switch; -import android.widget.TextView; - - -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.template.settings.SettingsActivity; - - -/** - * Modify the Template Activity to match your needs. - */ -public class TemplateActivity extends BleProfileServiceReadyActivity { - @SuppressWarnings("unused") - private final String TAG = "TemplateActivity"; - - // TODO change view references to match your need - private TextView mValueView; - private TextView mHeatingStatusView; - private EditText mTimeValueView; - private EditText mTempValueView; - private Integer mSetTime ; - private Integer mSetTemp ; - private Switch mHeatingState ; - - - @Override - protected void onCreateView(final Bundle savedInstanceState) { - // TODO modify the layout file(s). By default the activity shows only one field - the Heart Rate value as a sample - setContentView(R.layout.activity_feature_template); - setGUI(); - } - - private void setGUI() { - // TODO assign your views to fields - mValueView = findViewById(R.id.value); - mTimeValueView = findViewById(R.id.u_time); - mTempValueView = findViewById(R.id.u_temp); - mHeatingState = findViewById(R.id.heating_state); - mHeatingStatusView= findViewById(R.id.heating_status_text); - - mHeatingState.setOnCheckedChangeListener((buttonView, isChecked) -> { - if (isChecked) { - getService().heatingSwitch(1); - mSetTime = Integer.parseInt(mTimeValueView.getText().toString()); - getService().sendTimeDuration(mSetTime); - mSetTemp = Integer.parseInt(mTempValueView.getText().toString()); - getService().sendTemp(mSetTemp); - } - else { - getService().heatingSwitch(0); - } - mHeatingStatusView.setText(isChecked ? R.string.Heating_block_on : R.string.Heating_block_off); - }); - - - findViewById(R.id.time_set_button).setOnClickListener(v -> { - if (isDeviceConnected()) { - - mSetTime = Integer.parseInt(mTimeValueView.getText().toString()); - getService().sendTimeDuration(mSetTime); - } - }); - - findViewById(R.id.temp_set_button).setOnClickListener(v -> { - if (isDeviceConnected()) { - mSetTemp = Integer.parseInt(mTempValueView.getText().toString()); - getService().sendTemp(mSetTemp); - } - }); - } - - @Override - protected void onInitialize(final Bundle savedInstanceState) { - LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); - } - - @Override - protected void setDefaultUI() { - // TODO clear your UI - mValueView.setText(R.string.not_available_value); - } - - @Override - protected int getLoggerProfileTitle() { - return R.string.template_feature_title; - } - - @Override - protected int getAboutTextId() { - return R.string.template_about_text; - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.settings_and_about, 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 int getDefaultDeviceName() { - return R.string.template_default_name; - } - - @Override - protected UUID getFilterUUID() { - // TODO this method may return the UUID of the service that is required to be in the advertisement packet of a device in order to be listed on the Scanner dialog. - // If null is returned no filtering is done. - return TemplateManager.SERVICE_UUID; - } - - @Override - protected Class getServiceClass() { - return TemplateService.class; - } - - @Override - protected void onServiceBound(final TemplateService.TemplateBinder binder) { - // not used - } - - @Override - protected void onServiceUnbound() { - // not used - } - - @Override - public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { - // this may notify user or show some views - } - - @Override - public void onDeviceDisconnected(final BluetoothDevice device) { - super.onDeviceDisconnected(device); - } - - // Handling updates from the device - @SuppressWarnings("unused") - private void setValueOnView(@NonNull final BluetoothDevice device, final int value) { - // TODO assign the value to a view - mValueView.setText(String.valueOf(value)); - } - - @SuppressWarnings("unused") - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { - -} - - private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(final Context context, final Intent intent) { - final String action = intent.getAction(); - final BluetoothDevice device = intent.getParcelableExtra(TemplateService.EXTRA_DEVICE); - - if (TemplateService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) { - final int value = intent.getIntExtra(TemplateService.EXTRA_DATA, 0); - // Update GUI - setValueOnView(device, value); - } else if (TemplateService.BROADCAST_BATTERY_LEVEL.equals(action)) { - final int batteryLevel = intent.getIntExtra(TemplateService.EXTRA_BATTERY_LEVEL, 0); - // Update GUI - onBatteryLevelChanged(device, batteryLevel); - } - } - }; - - private static IntentFilter makeIntentFilter() { - final IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(TemplateService.BROADCAST_TEMPLATE_MEASUREMENT); - intentFilter.addAction(TemplateService.BROADCAST_BATTERY_LEVEL); - return intentFilter; - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManager.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManager.java deleted file mode 100644 index 514e850..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManager.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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.template; - -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import androidx.annotation.NonNull; - -import android.util.Log; - -import java.util.UUID; - -import no.nordicsemi.android.ble.BleManager; -import no.nordicsemi.android.ble.data.Data; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.battery.BatteryManager; -import no.nordicsemi.android.nrftoolbox.parser.TemplateParser; -import no.nordicsemi.android.nrftoolbox.template.callback.TemplateDataCallback; - - -/** - * Modify to template manager to match your requirements. - * The TemplateManager extends {@link BatteryManager}, but it may easily extend {@link BleManager} - * instead if you don't need Battery Service support. If not, also modify the - * {@link TemplateManagerCallbacks} to extend {@link no.nordicsemi.android.ble.BleManagerCallbacks} - * and replace BatteryManagerGattCallback to BleManagerGattCallback in this class. - */ -public class TemplateManager extends BatteryManager { - // TODO Replace the services and characteristics below to match your device. - /** - * The service UUID. - */ - static final UUID SERVICE_UUID = UUID.fromString("00001500-1212-efde-1523-785feabcd123"); // Heart Rate service - /** - * A UUID of a characteristic with notify property. - */ - //private static final UUID MEASUREMENT_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement - //private static final UUID TEMPERATURE_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Heart Rate Measurement - /** - * A UUID of a characteristic with read property. - */ - //private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); // Body Sensor Location - private static final UUID TEMP_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); // Body Sensor Location - /** - * A UUID of a characteristic with write property. - */ - private static final UUID TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); // Device Name - /** - * A UUID of a characteristic with write property. - */ - private static final UUID TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001503-1212-efde-1523-785feabcd123"); // Device Name - /** - * A UUID of a characteristic with write property. - */ - private static final UUID AMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001504-1212-efde-1523-785feabcd123"); // Device Name - - /** - * Some other service UUID. - */ - private static final UUID OTHER_SERVICE_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); // Generic Access service - /** - * A UUID of a characteristic with write property. - */ - private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb"); // Device Name - - - // TODO Add more services and characteristics references. - - private BluetoothGattCharacteristic mReadBlockTempCharacteristic, mSetAmpTempCharacteristic, mSetAmpTimeCharacteristic, mAmpStartStopCharacteristic, mRequiredCharacteristic, mDeviceNameCharacteristic, mOptionalCharacteristic; - - public TemplateManager(final Context context) { - super(context); - } - - @NonNull - @Override - protected BatteryManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving indication, etc. - */ - private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { - - @Override - protected void initialize() { - // Initialize the Battery Manager. It will enable Battery Level notifications. - // Remove it if you don't need this feature. - super.initialize(); - - // TODO Initialize your manager here. - // Initialization is done once, after the device is connected. Usually it should - // enable notifications or indications on some characteristics, write some data or - // read some features / version. - // After the initialization is complete, the onDeviceReady(...) method will be called. - - // Increase the MTU - requestMtu(43)//requestMtu(43) - .with((device, mtu) -> log(LogContract.Log.Level.APPLICATION, "MTU changed to " + mtu)) - .done(device -> { - // You may do some logic in here that should be done when the request finished successfully. - // In case of MTU this method is called also when the MTU hasn't changed, or has changed - // to a different (lower) value. Use .with(...) to get the MTU value. - }) - .fail((device, status) -> log(Log.WARN, "MTU change not supported")) - .enqueue(); - - // Set notification callback - setNotificationCallback(mReadBlockTempCharacteristic) - // This callback will be called each time the notification is received - .with(new TemplateDataCallback() { - @Override - public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(LogContract.Log.Level.APPLICATION, TemplateParser.parse(data)); - super.onDataReceived(device, data); - } - - @Override - public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) { - // Let's lass received data to the service - mCallbacks.onSampleValueReceived(device, value); - } - - @Override - public void onInvalidDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { - log(Log.WARN, "Invalid data received: " + data); - } - }); - - // Enable notifications - enableNotifications(mReadBlockTempCharacteristic) - // Method called after the data were sent (data will contain 0x0100 in this case) - .with((device, data) -> log(Log.DEBUG, "Data sent: " + data)) - // Method called when the request finished successfully. This will be called after .with(..) callback - .done(device -> log(LogContract.Log.Level.APPLICATION, "Notifications enabled successfully")) - // Methods called in case of an error, for example when the characteristic does not have Notify property - .fail((device, status) -> log(Log.WARN, "Failed to enable notifications")) - .enqueue(); - } - - @Override - protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - // TODO Initialize required characteristics. - // It should return true if all has been discovered (that is that device is supported). - final BluetoothGattService service = gatt.getService(SERVICE_UUID); - if (service != null) { - mReadBlockTempCharacteristic = service.getCharacteristic(TEMP_READABLE_CHARACTERISTIC_UUID); - mSetAmpTimeCharacteristic = service.getCharacteristic(TIME_WRITABLE_CHARACTERISTIC_UUID); - mSetAmpTempCharacteristic = service.getCharacteristic(TEMP_WRITABLE_CHARACTERISTIC_UUID); - mAmpStartStopCharacteristic = service.getCharacteristic(AMP_WRITABLE_CHARACTERISTIC_UUID); - } - final BluetoothGattService otherService = gatt.getService(OTHER_SERVICE_UUID); - if (otherService != null) { - mDeviceNameCharacteristic = otherService.getCharacteristic(READABLE_CHARACTERISTIC_UUID); - } - - return mReadBlockTempCharacteristic != null && mSetAmpTimeCharacteristic != null && mSetAmpTempCharacteristic!= null && mAmpStartStopCharacteristic != null ; - } - - @Override - protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { - // Initialize Battery characteristic - super.isOptionalServiceSupported(gatt); - - // TODO If there are some optional characteristics, initialize them there. - final BluetoothGattService service = gatt.getService(SERVICE_UUID); - if (service != null) { - mOptionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID); - } - return mOptionalCharacteristic != null; - } - - @Override - protected void onDeviceDisconnected() { - // Release Battery Service - super.onDeviceDisconnected(); - - // TODO Release references to your characteristics. - mRequiredCharacteristic = null; - mDeviceNameCharacteristic = null; - mOptionalCharacteristic = null; - } - - @Override - protected void onDeviceReady() { - super.onDeviceReady(); - - // Initialization is now ready. - // The service or activity has been notified with no.nordicsemi.android.ble.BatteryManagerCallbacks#onDeviceReady(). - // TODO Do some extra logic here, of remove onDeviceReady(). - - // Device is ready, let's read something here. Usually there is nothing else to be done - // here, as all had been done during initialization. - readCharacteristic(mReadBlockTempCharacteristic) - .with((device, data) -> { - // Characteristic value has been read - // Let's do some magic with it. - if (data.size() > 0) { - final Integer value = data.getIntValue(Data.FORMAT_UINT8, 0); - log(LogContract.Log.Level.APPLICATION, "Value '" + value + "' has been read!"); - } else { - log(Log.WARN, "Value is empty!"); - } - }) - .enqueue(); - } - }; - - // TODO Define manager's API - - /** - * This method will write important data to the device. - * - * @param parameter parameter to be written. - */ - - - //Heating Switch - void heatingSwitch(int state) { - log(Log.WARN, "Write time duration \"" + state + "\""); - //final byte time_in_byte = time_duration.getBytes()[0]; - final byte state_in_byte = (byte) state; - writeCharacteristic(mAmpStartStopCharacteristic, Data.opCode(state_in_byte)) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, - "\"" + data.size() + "\" Heating State")) - .split() - .enqueue(); - - } - - //Set Time - void sendTimeDuration(int time_duration) { - log(Log.WARN, "Write time duration \"" + time_duration + "\""); - //final byte time_in_byte = time_duration.getBytes()[0]; - final byte time_in_byte = (byte) time_duration; - writeCharacteristic(mSetAmpTimeCharacteristic, Data.opCode(time_in_byte)) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, - "\"" + data.size() + "\" Set Time")) - .split() - .enqueue(); - - } - - - //Set Temp - void sendTemp(int temp) { - log(Log.WARN, "Write temp \"" + temp + "\""); - //final byte temp_in_byte = temp.getBytes()[0]; - final byte temp_in_byte = (byte) temp; - - writeCharacteristic(mSetAmpTempCharacteristic, Data.opCode(temp_in_byte)) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, - "\"" + data.size() + "\" Set Temp")) - .split() - .enqueue(); - - } - -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManagerCallbacks.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManagerCallbacks.java deleted file mode 100644 index 05b03d8..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateManagerCallbacks.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * 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.template; - -import no.nordicsemi.android.nrftoolbox.battery.BatteryManagerCallbacks; -import no.nordicsemi.android.nrftoolbox.template.callback.TemplateCharacteristicCallback; - -/** - * Interface {@link TemplateManagerCallbacks} must be implemented by {@link TemplateService} - * in order to receive callbacks from {@link TemplateManager} - */ -interface TemplateManagerCallbacks extends BatteryManagerCallbacks, TemplateCharacteristicCallback { - - // Callbacks are called when a data has been received/written to a remote device. - // This is the way how the manager notifies the activity about this event. - - // TODO add more callbacks. - // If you need, create more ...Callback interfaces and extend this interface with them. -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateService.java deleted file mode 100644 index 7c927be..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/TemplateService.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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.template; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; - -import no.nordicsemi.android.log.Logger; -import no.nordicsemi.android.nrftoolbox.FeaturesActivity; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; - -public class TemplateService extends BleProfileService implements TemplateManagerCallbacks { - public static final String BROADCAST_TEMPLATE_MEASUREMENT = "no.nordicsemi.android.nrftoolbox.template.BROADCAST_MEASUREMENT"; - public static final String EXTRA_DATA = "no.nordicsemi.android.nrftoolbox.template.EXTRA_DATA"; - - public static final String BROADCAST_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.BROADCAST_BATTERY_LEVEL"; - public static final String EXTRA_BATTERY_LEVEL = "no.nordicsemi.android.nrftoolbox.EXTRA_BATTERY_LEVEL"; - - private final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.template.ACTION_DISCONNECT"; - - private final static int NOTIFICATION_ID = 864; - private final static int OPEN_ACTIVITY_REQ = 0; - private final static int DISCONNECT_REQ = 1; - - private TemplateManager mManager; - - private final LocalBinder mBinder = new TemplateBinder(); - - /** - * This local binder is an interface for the bound activity to operate with the sensor. - */ - class TemplateBinder extends LocalBinder { - // TODO Define service API that may be used by a bound Activity - - /** - * Sends some important data to the device. - * - * @param parameter some parameter. - */ - - public void heatingSwitch(int state){ - mManager.heatingSwitch(state); - } - public void sendTimeDuration(int time) { - mManager.sendTimeDuration(time); - } - public void sendTemp(int temp) { - mManager.sendTemp(temp); - } - - } - - @Override - protected LocalBinder getBinder() { - return mBinder; - } - - @Override - protected LoggableBleManager initializeManager() { - return mManager = new TemplateManager(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 - protected void onRebind() { - // when the activity rebinds to the service, remove the notification - cancelNotification(); - } - - @Override - protected void onUnbind() { - // when the activity closes we need to show the notification that user is connected to the sensor - createNotification(R.string.template_notification_connected_message, 0); - } - - @Override - public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) { - final Intent broadcast = new Intent(BROADCAST_TEMPLATE_MEASUREMENT); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_DATA, value); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - - if (!mBound) { - // Here we may update the notification to display the current value. - // TODO modify the notification here - } - } - - @Override - public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { - - } - - /** - * 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 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, TemplateActivity.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 AndroidManifest.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 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL); - builder.setContentIntent(pendingIntent); - builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); - builder.setSmallIcon(R.drawable.ic_stat_notify_template); - builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); - builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.template_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(), "[Notification] Disconnect action pressed"); - if (isConnected()) - getBinder().disconnect(); - else - stopSelf(); - } - }; -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/callback/TemplateCharacteristicCallback.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/callback/TemplateCharacteristicCallback.java deleted file mode 100644 index 34e6d44..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/callback/TemplateCharacteristicCallback.java +++ /dev/null @@ -1,21 +0,0 @@ -package no.nordicsemi.android.nrftoolbox.template.callback; - -import android.bluetooth.BluetoothDevice; -import androidx.annotation.NonNull; - -/** - * This class defines your characteristic API. - * In this example (that is the HRM characteristic, which the template is based on), is notifying - * with a value (Heart Rate). The single method just returns the value and ignores other - * optional data from Heart Rate Measurement characteristic for simplicity. - */ -public interface TemplateCharacteristicCallback { - - /** - * Called when a value is received. - * - * @param device a device from which the value was obtained. - * @param value the new value. - */ - void onSampleValueReceived(@NonNull final BluetoothDevice device, int value); -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/settings/SettingsActivity.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/settings/SettingsActivity.java deleted file mode 100644 index 00f410d..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/settings/SettingsActivity.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * 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.template.settings; - -import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import android.view.MenuItem; - -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsActivity extends AppCompatActivity { - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_settings); - - final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - - // Display the fragment as the main content. - getSupportFragmentManager().beginTransaction().replace(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/template/settings/SettingsFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/settings/SettingsFragment.java deleted file mode 100644 index 3475b49..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/settings/SettingsFragment.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.template.settings; - -import android.os.Bundle; -import android.preference.PreferenceFragment; - -import androidx.preference.PreferenceFragmentCompat; -import no.nordicsemi.android.nrftoolbox.R; - -public class SettingsFragment extends PreferenceFragmentCompat { - public static final String SETTINGS_DATA = "settings_template_data"; // TODO values matching those in settings_template.xml file in /res/xml - public static final int SETTINGS_VARIANT_A = 0; - public static final int SETTINGS_VARIANT_B = 1; - public static final int SETTINGS_VARIANT_DEFAULT = SETTINGS_VARIANT_A; - - @Override - public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { - addPreferencesFromResource(R.xml.settings_template); - } -} 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 deleted file mode 100644 index efce6fa..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTActivity.java +++ /dev/null @@ -1,826 +0,0 @@ -/* - * 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 android.Manifest; -import android.animation.ArgbEvaluator; -import android.animation.ValueAnimator; -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.bluetooth.BluetoothDevice; -import android.content.ActivityNotFoundException; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.database.Cursor; -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.os.Environment; -import android.os.Handler; -import android.preference.PreferenceManager; -import androidx.annotation.NonNull; -import com.google.android.material.snackbar.Snackbar; -import androidx.core.app.ActivityCompat; -import androidx.fragment.app.DialogFragment; -import androidx.core.app.NotificationCompat; -import androidx.core.content.ContextCompat; -import androidx.slidingpanelayout.widget.SlidingPaneLayout; -import androidx.appcompat.app.AlertDialog; -import android.util.Log; -import android.view.Menu; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ListView; -import android.widget.Toast; - -import com.google.android.gms.common.api.GoogleApiClient; - -import org.simpleframework.xml.Serializer; -import org.simpleframework.xml.core.Persister; -import org.simpleframework.xml.strategy.Strategy; -import org.simpleframework.xml.strategy.Type; -import org.simpleframework.xml.strategy.Visitor; -import org.simpleframework.xml.strategy.VisitorStrategy; -import org.simpleframework.xml.stream.Format; -import org.simpleframework.xml.stream.HyphenStyle; -import org.simpleframework.xml.stream.InputNode; -import org.simpleframework.xml.stream.NodeMap; -import org.simpleframework.xml.stream.OutputNode; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.StringWriter; -import java.util.UUID; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.dfu.adapter.FileBrowserAppsAdapter; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileServiceReadyActivity; -import no.nordicsemi.android.nrftoolbox.uart.database.DatabaseHelper; -import no.nordicsemi.android.nrftoolbox.uart.domain.Command; -import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration; -import no.nordicsemi.android.nrftoolbox.uart.wearable.UARTConfigurationSynchronizer; -import no.nordicsemi.android.nrftoolbox.utility.FileHelper; -import no.nordicsemi.android.nrftoolbox.widget.ClosableSpinner; - -public class UARTActivity extends BleProfileServiceReadyActivity implements UARTInterface, - UARTNewConfigurationDialogFragment.NewConfigurationDialogListener, UARTConfigurationsAdapter.ActionListener, AdapterView.OnItemSelectedListener, - GoogleApiClient.ConnectionCallbacks { - private final static String TAG = "UARTActivity"; - - private final static String PREFS_BUTTON_ENABLED = "prefs_uart_enabled_"; - private final static String PREFS_BUTTON_COMMAND = "prefs_uart_command_"; - private final static String PREFS_BUTTON_ICON = "prefs_uart_icon_"; - /** This preference keeps the ID of the selected configuration. */ - private final static String PREFS_CONFIGURATION = "configuration_id"; - /** This preference is set to true when initial data synchronization for wearables has been completed. */ - private final static String PREFS_WEAR_SYNCED = "prefs_uart_synced"; - private final static String SIS_EDIT_MODE = "sis_edit_mode"; - - private final static int SELECT_FILE_REQ = 2678; // random - private final static int PERMISSION_REQ = 24; // random, 8-bit - - UARTConfigurationSynchronizer mWearableSynchronizer; - - /** The current configuration. */ - private UartConfiguration mConfiguration; - private DatabaseHelper mDatabaseHelper; - private SharedPreferences mPreferences; - private UARTConfigurationsAdapter mConfigurationsAdapter; - private ClosableSpinner mConfigurationSpinner; - private SlidingPaneLayout mSlider; - private View mContainer; - private UARTService.UARTBinder mServiceBinder; - private ConfigurationListener mConfigurationListener; - private boolean mEditMode; - - public interface ConfigurationListener { - void onConfigurationModified(); - void onConfigurationChanged(final UartConfiguration configuration); - void setEditMode(final boolean editMode); - } - - public void setConfigurationListener(final ConfigurationListener listener) { - mConfigurationListener = listener; - } - - @Override - protected Class getServiceClass() { - return UARTService.class; - } - - @Override - protected int getLoggerProfileTitle() { - return R.string.uart_feature_title; - } - - @Override - protected Uri getLocalAuthorityLogger() { - return UARTLocalLogContentProvider.AUTHORITY_URI; - } - - @Override - protected void setDefaultUI() { - // empty - } - - @Override - protected void onServiceBound(final UARTService.UARTBinder binder) { - mServiceBinder = binder; - } - - @Override - protected void onServiceUnbound() { - mServiceBinder = null; - } - - @Override - protected void onInitialize(final Bundle savedInstanceState) { - mPreferences = PreferenceManager.getDefaultSharedPreferences(this); - mDatabaseHelper = new DatabaseHelper(this); - ensureFirstConfiguration(mDatabaseHelper); - mConfigurationsAdapter = new UARTConfigurationsAdapter(this, this, mDatabaseHelper.getConfigurationsNames()); - - // Initialize Wearable synchronizer - mWearableSynchronizer = UARTConfigurationSynchronizer.from(this, this); - } - - /** - * Method called when Google API Client connects to Wearable.API. - */ - @Override - public void onConnected(final Bundle bundle) { - // Ensure the Wearable API was connected - if (!mWearableSynchronizer.hasConnectedApi()) - return; - - if (!mPreferences.getBoolean(PREFS_WEAR_SYNCED, false)) { - new Thread(() -> { - final Cursor cursor = mDatabaseHelper.getConfigurations(); - try { - while (cursor.moveToNext()) { - final long id = cursor.getLong(0 /* _ID */); - try { - final String xml = cursor.getString(2 /* XML */); - final Format format = new Format(new HyphenStyle()); - final Serializer serializer = new Persister(format); - final UartConfiguration configuration = serializer.read(UartConfiguration.class, xml); - mWearableSynchronizer.onConfigurationAddedOrEdited(id, configuration).await(); - } catch (final Exception e) { - Log.w(TAG, "Deserializing configuration with id " + id + " failed", e); - } - } - mPreferences.edit().putBoolean(PREFS_WEAR_SYNCED, true).apply(); - } finally { - cursor.close(); - } - }).start(); - } - } - - /** - * Method called then Google API client connection was suspended. - * @param cause the cause of suspension - */ - @Override - public void onConnectionSuspended(final int cause) { - // dp nothing - } - - @Override - protected void onDestroy() { - super.onDestroy(); - mWearableSynchronizer.close(); - } - - @Override - protected void onCreateView(final Bundle savedInstanceState) { - setContentView(R.layout.activity_feature_uart); - - mContainer = findViewById(R.id.container); - // Setup the sliding pane if it exists - final SlidingPaneLayout slidingPane = mSlider = 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) getSupportFragmentManager().findFragmentById(R.id.fragment_log); - logFragment.onFragmentHidden(); - } - }); - } - } - - @Override - protected void onViewCreated(final Bundle savedInstanceState) { - getSupportActionBar().setDisplayShowTitleEnabled(false); - - final ClosableSpinner configurationSpinner = mConfigurationSpinner = findViewById(R.id.toolbar_spinner); - configurationSpinner.setOnItemSelectedListener(this); - configurationSpinner.setAdapter(mConfigurationsAdapter); - configurationSpinner.setSelection(mConfigurationsAdapter.getItemPosition(mPreferences.getLong(PREFS_CONFIGURATION, 0))); - } - - @Override - protected void onRestoreInstanceState(final @NonNull 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 - public void onServicesDiscovered(final BluetoothDevice device, 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) getSupportFragmentManager().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 - public void send(final String text) { - if (mServiceBinder != null) - mServiceBinder.send(text); - } - - public void setEditMode(final boolean editMode) { - setEditMode(editMode, true); - invalidateOptionsMenu(); - } - - @Override - public void onBackPressed() { - if (mSlider != null && mSlider.isOpen()) { - mSlider.closePane(); - return; - } - if (mEditMode) { - setEditMode(false); - return; - } - super.onBackPressed(); - } - - @Override - public boolean onCreateOptionsMenu(final Menu menu) { - getMenuInflater().inflate(R.menu.uart_menu_configurations, menu); - getMenuInflater().inflate(mEditMode ? R.menu.uart_menu_config : R.menu.uart_menu, menu); - - final int configurationsCount = mDatabaseHelper.getConfigurationsCount(); - menu.findItem(R.id.action_remove).setVisible(configurationsCount > 1); - return super.onCreateOptionsMenu(menu); - } - - @Override - protected boolean onOptionsItemSelected(int itemId) { - final String name = mConfiguration.getName(); - switch (itemId) { - case R.id.action_configure: - setEditMode(!mEditMode); - return true; - case R.id.action_show_log: - mSlider.openPane(); - return true; - case R.id.action_share: { - final String xml = mDatabaseHelper.getConfiguration(mConfigurationSpinner.getSelectedItemId()); - - final Intent intent = new Intent(Intent.ACTION_SEND); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setType("text/xml"); - intent.putExtra(Intent.EXTRA_TEXT, xml); - intent.putExtra(Intent.EXTRA_SUBJECT, mConfiguration.getName()); - try { - startActivity(intent); - } catch (final ActivityNotFoundException e) { - Toast.makeText(this, R.string.no_uri_application, Toast.LENGTH_SHORT).show(); - } - return true; - } - case R.id.action_export: { - if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { - exportConfiguration(); - } else { - ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE }, PERMISSION_REQ); - } - return true; - } - case R.id.action_rename: { - final DialogFragment fragment = UARTNewConfigurationDialogFragment.getInstance(name, false); - fragment.show(getSupportFragmentManager(), null); - // onNewConfiguration(name, false) will be called when user press OK - return true; - } - case R.id.action_duplicate: { - final DialogFragment fragment = UARTNewConfigurationDialogFragment.getInstance(name, true); - fragment.show(getSupportFragmentManager(), null); - // onNewConfiguration(name, true) will be called when user press OK - return true; - } - case R.id.action_remove: { - mDatabaseHelper.removeDeletedServerConfigurations(); // just to be sure nothing has left - final UartConfiguration removedConfiguration = mConfiguration; - final long id = mDatabaseHelper.deleteConfiguration(name); - if (id >= 0) - mWearableSynchronizer.onConfigurationDeleted(id); - refreshConfigurations(); - - final Snackbar snackbar = Snackbar.make(mContainer, R.string.uart_configuration_deleted, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_undo, v -> { - final long id1 = mDatabaseHelper.restoreDeletedServerConfiguration(name); - if (id1 >= 0) - mWearableSynchronizer.onConfigurationAddedOrEdited(id1, removedConfiguration); - refreshConfigurations(); - }); - snackbar.setDuration(5000); // This is not an error - snackbar.show(); - return true; - } - } - return false; - } - - @Override - public void onRequestPermissionsResult(final int requestCode, final @NonNull String[] permissions, final @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - switch (requestCode) { - case PERMISSION_REQ: { - if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // We have been granted the Manifest.permission.WRITE_EXTERNAL_STORAGE permission. Now we may proceed with exporting. - exportConfiguration(); - } else { - Toast.makeText(this, R.string.no_required_permission, Toast.LENGTH_SHORT).show(); - } - break; - } - } - } - - @Override - public void onItemSelected(final AdapterView parent, final View view, final int position, final long id) { - if (position > 0) { // FIXME this is called twice after rotation. - try { - final String xml = mDatabaseHelper.getConfiguration(id); - final Format format = new Format(new HyphenStyle()); - final Serializer serializer = new Persister(format); - mConfiguration = serializer.read(UartConfiguration.class, xml); - mConfigurationListener.onConfigurationChanged(mConfiguration); - } catch (final Exception e) { - Log.e(TAG, "Selecting configuration failed", e); - - String message; - if (e.getLocalizedMessage() != null) - message = e.getLocalizedMessage(); - else if (e.getCause() != null && e.getCause().getLocalizedMessage() != null) - message = e.getCause().getLocalizedMessage(); - else - message = "Unknown error"; - final String msg = message; - Snackbar.make(mContainer, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_details, v -> new AlertDialog.Builder(UARTActivity.this).setMessage(msg).setTitle(R.string.uart_action_details).setPositiveButton(R.string.ok, null).show()).show(); - return; - } - - mPreferences.edit().putLong(PREFS_CONFIGURATION, id).apply(); - } - } - - @Override - public void onNothingSelected(final AdapterView parent) { - // do nothing - } - - @Override - public void onNewConfigurationClick() { - // No item has been selected. We must close the spinner manually. - mConfigurationSpinner.close(); - - // Open the dialog - final DialogFragment fragment = UARTNewConfigurationDialogFragment.getInstance(null, false); - fragment.show(getSupportFragmentManager(), null); - - // onNewConfiguration(null, false) will be called when user press OK - } - - @Override - public void onImportClick() { - // No item has been selected. We must close the spinner manually. - mConfigurationSpinner.close(); - - final Intent intent = new Intent(Intent.ACTION_GET_CONTENT); - intent.setType("text/xml"); - 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 = 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, (dialog, which) -> dialog.dismiss()).setPositiveButton(R.string.yes, (dialog, 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(); - } - } - - @Override - protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if (resultCode == Activity.RESULT_CANCELED) - return; - - switch (requestCode) { - case SELECT_FILE_REQ: { - // clear previous data - 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 with use of a 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(); - try { - final FileInputStream fis = new FileInputStream(path); - loadConfiguration(fis); - } catch (final FileNotFoundException e) { - Toast.makeText(this, R.string.uart_configuration_load_error, Toast.LENGTH_LONG).show(); - } - } else if (uri.getScheme().equals("content")) { - // An Uri has been returned - Uri u = uri; - - // If application returned Uri for streaming, let's us it. Does it works? - final Bundle extras = data.getExtras(); - if (extras != null && extras.containsKey(Intent.EXTRA_STREAM)) - u = extras.getParcelable(Intent.EXTRA_STREAM); - - try { - final InputStream is = getContentResolver().openInputStream(u); - loadConfiguration(is); - } catch (final FileNotFoundException e) { - Toast.makeText(this, R.string.uart_configuration_load_error, Toast.LENGTH_LONG).show(); - } - } - break; - } - } - } - - public void onCommandChanged(final int index, final String message, final boolean active, final int eol, final int iconIndex) { - final Command command = mConfiguration.getCommands()[index]; - - command.setCommand(message); - command.setActive(active); - command.setEol(eol); - command.setIconIndex(iconIndex); - mConfigurationListener.onConfigurationModified(); - saveConfiguration(); - } - - @Override - public void onNewConfiguration(final String name, final boolean duplicate) { - final boolean exists = mDatabaseHelper.configurationExists(name); - if (exists) { - Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show(); - return; - } - - UartConfiguration configuration = mConfiguration; - if (!duplicate) - configuration = new UartConfiguration(); - configuration.setName(name); - - try { - final Format format = new Format(new HyphenStyle()); - final Strategy strategy = new VisitorStrategy(new CommentVisitor()); - final Serializer serializer = new Persister(strategy, format); - final StringWriter writer = new StringWriter(); - serializer.write(configuration, writer); - final String xml = writer.toString(); - - final long id = mDatabaseHelper.addConfiguration(name, xml); - mWearableSynchronizer.onConfigurationAddedOrEdited(id, configuration); - refreshConfigurations(); - selectConfiguration(mConfigurationsAdapter.getItemPosition(id)); - } catch (final Exception e) { - Log.e(TAG, "Error while creating a new configuration", e); - } - } - - @Override - public void onRenameConfiguration(final String newName) { - final boolean exists = mDatabaseHelper.configurationExists(newName); - if (exists) { - Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show(); - return; - } - - final String oldName = mConfiguration.getName(); - mConfiguration.setName(newName); - - try { - final Format format = new Format(new HyphenStyle()); - final Strategy strategy = new VisitorStrategy(new CommentVisitor()); - final Serializer serializer = new Persister(strategy, format); - final StringWriter writer = new StringWriter(); - serializer.write(mConfiguration, writer); - final String xml = writer.toString(); - - mDatabaseHelper.renameConfiguration(oldName, newName, xml); - mWearableSynchronizer.onConfigurationAddedOrEdited(mPreferences.getLong(PREFS_CONFIGURATION, 0), mConfiguration); - refreshConfigurations(); - } catch (final Exception e) { - Log.e(TAG, "Error while renaming configuration", e); - } - } - - private void refreshConfigurations() { - mConfigurationsAdapter.swapCursor(mDatabaseHelper.getConfigurationsNames()); - mConfigurationsAdapter.notifyDataSetChanged(); - invalidateOptionsMenu(); - } - - private void selectConfiguration(final int position) { - mConfigurationSpinner.setSelection(position); - } - - /** - * 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; - mConfigurationListener.setEditMode(editMode); - if (!change) { - final ColorDrawable color = new ColorDrawable(); - int darkColor = 0; - if (editMode) { - color.setColor(ContextCompat.getColor(this, R.color.orange)); - darkColor = ContextCompat.getColor(this, R.color.dark_orange); - } else { - color.setColor(ContextCompat.getColor(this, R.color.actionBarColor)); - darkColor = ContextCompat.getColor(this, 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 = ContextCompat.getColor(this, editMode ? R.color.actionBarColorDark : R.color.dark_orange); - final int colorTo = ContextCompat.getColor(this, !editMode ? R.color.actionBarColorDark : R.color.dark_orange); - - final ValueAnimator anim = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo); - anim.setDuration(200); - anim.addUpdateListener(animation -> getWindow().setStatusBarColor((Integer) animation.getAnimatedValue())); - anim.start(); - } - - if (mSlider != null && editMode) { - mSlider.closePane(); - } - } - } - - /** - * Saves the given configuration in the database. - */ - private void saveConfiguration() { - final UartConfiguration configuration = mConfiguration; - try { - final Format format = new Format(new HyphenStyle()); - final Strategy strategy = new VisitorStrategy(new CommentVisitor()); - final Serializer serializer = new Persister(strategy, format); - final StringWriter writer = new StringWriter(); - serializer.write(configuration, writer); - final String xml = writer.toString(); - - mDatabaseHelper.updateConfiguration(configuration.getName(), xml); - mWearableSynchronizer.onConfigurationAddedOrEdited(mPreferences.getLong(PREFS_CONFIGURATION, 0), configuration); - } catch (final Exception e) { - Log.e(TAG, "Error while creating a new configuration", e); - } - } - - /** - * Loads the configuration from the given input stream. - * @param is the input stream - */ - private void loadConfiguration(final InputStream is) { - try { - final BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - final StringBuilder builder = new StringBuilder(); - for (String line = reader.readLine(); line != null; line = reader.readLine()) { - builder.append(line).append("\n"); - } - final String xml = builder.toString(); - - final Format format = new Format(new HyphenStyle()); - final Serializer serializer = new Persister(format); - final UartConfiguration configuration = serializer.read(UartConfiguration.class, xml); - - final String name = configuration.getName(); - if (!mDatabaseHelper.configurationExists(name)) { - final long id = mDatabaseHelper.addConfiguration(name, xml); - mWearableSynchronizer.onConfigurationAddedOrEdited(id, configuration); - refreshConfigurations(); - new Handler().post(() -> selectConfiguration(mConfigurationsAdapter.getItemPosition(id))); - } else { - Toast.makeText(this, R.string.uart_configuration_name_already_taken, Toast.LENGTH_LONG).show(); - } - } catch (final Exception e) { - Log.e(TAG, "Loading configuration failed", e); - - String message; - if (e.getLocalizedMessage() != null) - message = e.getLocalizedMessage(); - else if (e.getCause() != null && e.getCause().getLocalizedMessage() != null) - message = e.getCause().getLocalizedMessage(); - else - message = "Unknown error"; - final String msg = message; - Snackbar.make(mContainer, R.string.uart_configuration_loading_failed, Snackbar.LENGTH_INDEFINITE).setAction(R.string.uart_action_details, v -> new AlertDialog.Builder(UARTActivity.this).setMessage(msg).setTitle(R.string.uart_action_details).setPositiveButton(R.string.ok, null).show()).show(); - } - } - - private void exportConfiguration() { - // TODO this may not work if the SD card is not available. (Lenovo A806, email from 11.03.2015) - final File folder = new File(Environment.getExternalStorageDirectory(), FileHelper.NORDIC_FOLDER); - if (!folder.exists()) - folder.mkdir(); - final File serverFolder = new File(folder, FileHelper.UART_FOLDER); - if (!serverFolder.exists()) - serverFolder.mkdir(); - - final String fileName = mConfiguration.getName() + ".xml"; - final File file = new File(serverFolder, fileName); - try { - file.createNewFile(); - final FileOutputStream fos = new FileOutputStream(file); - final OutputStreamWriter writer = new OutputStreamWriter(fos); - writer.append(mDatabaseHelper.getConfiguration(mConfigurationSpinner.getSelectedItemId())); - writer.close(); - - // Notify user about the file - final Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(FileHelper.getContentUri(this, file), "text/xml"); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - final PendingIntent pendingIntent = PendingIntent.getActivity(this, 420, intent, 0); - final Notification notification = new NotificationCompat.Builder(this, ToolboxApplication.FILE_SAVED_CHANNEL).setContentIntent(pendingIntent).setContentTitle(fileName).setContentText(getText(R.string.uart_configuration_export_succeeded)) - .setAutoCancel(true).setShowWhen(true).setTicker(getText(R.string.uart_configuration_export_succeeded_ticker)).setSmallIcon(android.R.drawable.stat_notify_sdcard).build(); - final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - nm.notify(fileName, 823, notification); - } catch (final Exception e) { - Log.e(TAG, "Error while exporting configuration", e); - Toast.makeText(this, R.string.uart_configuration_save_error, Toast.LENGTH_SHORT).show(); - } - } - - /** - * Converts the old configuration, stored in preferences, into the first XML configuration and saves it to the database. - * If there is already any configuration in the database this method does nothing. - */ - private void ensureFirstConfiguration(final DatabaseHelper mDatabaseHelper) { - // This method ensures that the "old", single configuration has been saved to the database. - if (mDatabaseHelper.getConfigurationsCount() == 0) { - final UartConfiguration configuration = new UartConfiguration(); - configuration.setName("First configuration"); - final Command[] commands = configuration.getCommands(); - - for (int i = 0; i < 9; ++i) { - final String cmd = mPreferences.getString(PREFS_BUTTON_COMMAND + i, null); - if (cmd != null) { - final Command command = new Command(); - command.setCommand(cmd); - command.setActive(mPreferences.getBoolean(PREFS_BUTTON_ENABLED + i, false)); - command.setEol(0); // default one - command.setIconIndex(mPreferences.getInt(PREFS_BUTTON_ICON + i, 0)); - commands[i] = command; - } - } - - try { - final Format format = new Format(new HyphenStyle()); - final Strategy strategy = new VisitorStrategy(new CommentVisitor()); - final Serializer serializer = new Persister(strategy, format); - final StringWriter writer = new StringWriter(); - serializer.write(configuration, writer); - final String xml = writer.toString(); - - mDatabaseHelper.addConfiguration(configuration.getName(), xml); - } catch (final Exception e) { - Log.e(TAG, "Error while creating default configuration", e); - } - } - } - - /** - * The comment visitor will add comments to the XML during saving. - */ - private class CommentVisitor implements Visitor { - @Override - public void read(final Type type, final NodeMap node) throws Exception { - // do nothing - } - - @Override - public void write(final Type type, final NodeMap node) throws Exception { - if (type.getType().equals(Command[].class)) { - OutputNode element = node.getNode(); - - StringBuilder builder = new StringBuilder("A configuration must have 9 commands, one for each button.\n Possible icons are:"); - for (Command.Icon icon : Command.Icon.values()) - builder.append("\n - ").append(icon.toString()); - element.setComment(builder.toString()); - } - } - } -} 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 deleted file mode 100644 index 7a25d8a..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTButtonAdapter.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * 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 android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ImageView; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.uart.domain.Command; -import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration; - -public class UARTButtonAdapter extends BaseAdapter { - private UartConfiguration mConfiguration; - private boolean mEditMode; - - public UARTButtonAdapter(final UartConfiguration configuration) { - mConfiguration = configuration; - } - - public void setEditMode(final boolean editMode) { - mEditMode = editMode; - notifyDataSetChanged(); - } - - public void setConfiguration(final UartConfiguration configuration) { - mConfiguration = configuration; - notifyDataSetChanged(); - } - - @Override - public int getCount() { - return mConfiguration != null ? mConfiguration.getCommands().length : 0; - } - - @Override - public Object getItem(final int position) { - return mConfiguration.getCommands()[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) { - final Command command = (Command) getItem(position); - return mEditMode || (command != null && command.isActive()); - } - - @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 Command command = (Command) getItem(position); - final ImageView image = (ImageView) view; - final boolean active = command != null && command.isActive(); - if (active) { - final int icon = command.getIconIndex(); - 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/UARTConfigurationsAdapter.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsAdapter.java deleted file mode 100644 index 1c4b25b..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTConfigurationsAdapter.java +++ /dev/null @@ -1,127 +0,0 @@ -/************************************************************************************************************************************************* - * 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 android.content.Context; -import android.database.Cursor; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CursorAdapter; -import android.widget.TextView; - -import no.nordicsemi.android.nrftoolbox.R; - -public class UARTConfigurationsAdapter extends CursorAdapter { - final Context mContext; - final ActionListener mListener; - - public interface ActionListener { - void onNewConfigurationClick(); - void onImportClick(); - } - - public UARTConfigurationsAdapter(final Context context, final ActionListener listener, final Cursor c) { - super(context, c, 0); - mContext = context; - mListener = listener; - } - - @Override - public int getCount() { - return super.getCount() + 1; // One for buttons at the top - } - - @Override - public boolean isEmpty() { - return super.getCount() == 0; - } - - @Override - public boolean hasStableIds() { - return true; - } - - @Override - public long getItemId(final int position) { - if (position > 0) - return super.getItemId(position - 1); - return 0; - } - - public int getItemPosition(final long id) { - final Cursor cursor = getCursor(); - if (cursor == null) - return 1; - - if (cursor.moveToFirst()) - do { - if (cursor.getLong(0 /* _ID */) == id) - return cursor.getPosition() + 1; - } while (cursor.moveToNext()); - return 1; // should never happen - } - - @Override - public View getView(final int position, final View convertView, final ViewGroup parent) { - if (position == 0) { - // This empty view should never be visible. Only positions 1+ are valid. Position 0 is reserved for action buttons. - // It is only created temporally when activity is created. - return LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_spinner_item, parent, false); - } - return super.getView(position - 1, convertView, parent); - } - - @Override - public View getDropDownView(final int position, final View convertView, final ViewGroup parent) { - if (position == 0) { - return newToolbarView(mContext, parent); - } - if (convertView instanceof ViewGroup) - return super.getDropDownView(position - 1, null, parent); - return super.getDropDownView(position - 1, convertView, parent); - } - - @Override - public View newView(final Context context, final Cursor cursor, final ViewGroup parent) { - return LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_spinner_item, parent, false); - } - - @Override - public View newDropDownView(final Context context, final Cursor cursor, final ViewGroup parent) { - return LayoutInflater.from(mContext).inflate(R.layout.feature_uart_dropdown_item, parent, false); - } - - public View newToolbarView(final Context context, final ViewGroup parent) { - final View view = LayoutInflater.from(context).inflate(R.layout.feature_uart_dropdown_title, parent, false); - view.findViewById(R.id.action_add).setOnClickListener(v -> mListener.onNewConfigurationClick()); - view.findViewById(R.id.action_import).setOnClickListener(v -> mListener.onImportClick()); - return view; - } - - @Override - public void bindView(final View view, final Context context, final Cursor cursor) { - final String name = cursor.getString(1 /* NAME */); - ((TextView) view).setText(name); - } -} 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 deleted file mode 100644 index 374b53b..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTControlFragment.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * 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 android.content.Context; -import android.os.Bundle; -import androidx.fragment.app.Fragment; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.GridView; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.uart.domain.Command; -import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration; - -public class UARTControlFragment extends Fragment implements GridView.OnItemClickListener, UARTActivity.ConfigurationListener { - private final static String TAG = "UARTControlFragment"; - private final static String SIS_EDIT_MODE = "sis_edit_mode"; - - private UartConfiguration mConfiguration; - private UARTButtonAdapter mAdapter; - private boolean mEditMode; - - @Override - public void onAttach(final Context context) { - super.onAttach(context); - - try { - ((UARTActivity)context).setConfigurationListener(this); - } catch (final ClassCastException e) { - Log.e(TAG, "The parent activity must implement EditModeListener"); - } - } - - @Override - public void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (savedInstanceState != null) { - mEditMode = savedInstanceState.getBoolean(SIS_EDIT_MODE); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - ((UARTActivity)getActivity()).setConfigurationListener(null); - } - - @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 = view.findViewById(R.id.grid); - grid.setAdapter(mAdapter = new UARTButtonAdapter(mConfiguration)); - grid.setOnItemClickListener(this); - mAdapter.setEditMode(mEditMode); - - return view; - } - - @Override - public void onItemClick(final AdapterView parent, final View view, final int position, final long id) { - if (mEditMode) { - Command command = mConfiguration.getCommands()[position]; - if (command == null) - mConfiguration.getCommands()[position] = command = new Command(); - final UARTEditDialog dialog = UARTEditDialog.getInstance(position, command); - dialog.show(getChildFragmentManager(), null); - } else { - final Command command = (Command)mAdapter.getItem(position); - final Command.Eol eol = command.getEol(); - String text = command.getCommand(); - if (text == null) - text = ""; - switch (eol) { - case CR_LF: - text = text.replaceAll("\n", "\r\n"); - break; - case CR: - text = text.replaceAll("\n", "\r"); - break; - } - final UARTInterface uart = (UARTInterface) getActivity(); - uart.send(text); - } - } - - @Override - public void onConfigurationModified() { - mAdapter.notifyDataSetChanged(); - } - - @Override - public void onConfigurationChanged(final UartConfiguration configuration) { - mConfiguration = configuration; - mAdapter.setConfiguration(configuration); - } - - @Override - public void setEditMode(final boolean editMode) { - mEditMode = editMode; - mAdapter.setEditMode(mEditMode); - } -} 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 deleted file mode 100644 index 9277019..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTEditDialog.java +++ /dev/null @@ -1,189 +0,0 @@ -/* - * 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 android.app.Dialog; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import androidx.appcompat.app.AlertDialog; -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.EditText; -import android.widget.GridView; -import android.widget.ImageView; -import android.widget.RadioGroup; - -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.uart.domain.Command; - -public class UARTEditDialog extends DialogFragment implements View.OnClickListener, GridView.OnItemClickListener { - private final static String ARG_INDEX = "index"; - private final static String ARG_COMMAND = "command"; - private final static String ARG_EOL = "eol"; - private final static String ARG_ICON_INDEX = "iconIndex"; - private int mActiveIcon; - - private EditText mField; - private CheckBox mActiveCheckBox; - private RadioGroup mEOLGroup; - private IconAdapter mIconAdapter; - - public static UARTEditDialog getInstance(final int index, final Command command) { - final UARTEditDialog fragment = new UARTEditDialog(); - - final Bundle args = new Bundle(); - args.putInt(ARG_INDEX, index); - args.putString(ARG_COMMAND, command.getCommand()); - args.putInt(ARG_EOL, command.getEol().index); - args.putInt(ARG_ICON_INDEX, command.getIconIndex()); - fragment.setArguments(args); - - return fragment; - } - - @NonNull - @Override - public Dialog onCreateDialog(final Bundle savedInstanceState) { - final LayoutInflater inflater = LayoutInflater.from(getActivity()); - - // Read button configuration - final Bundle args = getArguments(); - final int index = args.getInt(ARG_INDEX); - final String command = args.getString(ARG_COMMAND); - final int eol = args.getInt(ARG_EOL); - final int iconIndex = args.getInt(ARG_ICON_INDEX); - final boolean active = true; // change to active by default - mActiveIcon = iconIndex; - - // Create view - final View view = inflater.inflate(R.layout.feature_uart_dialog_edit, null); - final EditText field = mField = view.findViewById(R.id.field); - final GridView grid = view.findViewById(R.id.grid); - final CheckBox checkBox = mActiveCheckBox = view.findViewById(R.id.active); - checkBox.setOnCheckedChangeListener((buttonView, isChecked) -> { - field.setEnabled(isChecked); - grid.setEnabled(isChecked); - if (mIconAdapter != null) - mIconAdapter.notifyDataSetChanged(); - }); - - final RadioGroup eolGroup = mEOLGroup = view.findViewById(R.id.uart_eol); - switch (Command.Eol.values()[eol]) { - case CR_LF: - eolGroup.check(R.id.uart_eol_cr_lf); - break; - case CR: - eolGroup.check(R.id.uart_eol_cr); - break; - case LF: - default: - eolGroup.check(R.id.uart_eol_lf); - break; - } - - 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 = mActiveCheckBox.isChecked(); - final String command = mField.getText().toString(); - int eol; - - switch (mEOLGroup.getCheckedRadioButtonId()) { - case R.id.uart_eol_cr_lf: - eol = Command.Eol.CR_LF.index; - break; - case R.id.uart_eol_cr: - eol = Command.Eol.CR.index; - break; - case R.id.uart_eol_lf: - default: - eol = Command.Eol.LF.index; - break; - } - - // Save values - final Bundle args = getArguments(); - final int index = args.getInt(ARG_INDEX); - - dismiss(); - final UARTActivity parent = (UARTActivity) getActivity(); - parent.onCommandChanged(index, command, active, eol, mActiveIcon); - } - - @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 && mActiveCheckBox.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 deleted file mode 100644 index 6619ca5..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTInterface.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 { - - 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 deleted file mode 100644 index c196a36..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLocalLogContentProvider.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 android.net.Uri; - -import no.nordicsemi.android.log.localprovider.LocalLogContentProvider; - -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 deleted file mode 100644 index ffaa413..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogAdapter.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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 android.content.Context; -import android.database.Cursor; -import android.graphics.Color; -import androidx.annotation.NonNull; -import android.util.SparseIntArray; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.CursorAdapter; -import android.widget.TextView; - -import java.util.Calendar; - -import no.nordicsemi.android.log.LogContract.Log.Level; -import no.nordicsemi.android.nrftoolbox.R; - -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); - } - - UARTLogAdapter(@NonNull final 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 = view.findViewById(R.id.time); - holder.data = 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 deleted file mode 100644 index bf2f511..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTLogFragment.java +++ /dev/null @@ -1,299 +0,0 @@ -/* - * 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 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.database.Cursor; -import android.os.Bundle; -import android.os.IBinder; -import androidx.annotation.NonNull; -import androidx.fragment.app.ListFragment; -import androidx.loader.app.LoaderManager; -import androidx.loader.content.CursorLoader; -import androidx.loader.content.Loader; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -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 no.nordicsemi.android.log.ILogSession; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; - -public class UARTLogFragment extends ListFragment implements LoaderManager.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(requireContext()).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 bound to it - * and notified via mServiceConnection. - */ - final Intent service = new Intent(getActivity(), UARTService.class); - requireActivity().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 { - requireActivity().unbindService(mServiceConnection); - mUARTInterface = null; - } catch (final IllegalArgumentException e) { - // do nothing, we were not connected to the sensor - } - } - - @Override - public void onSaveInstanceState(@NonNull 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() { - LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(mCommonBroadcastReceiver); - super.onDestroy(); - } - - @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 = view.findViewById(R.id.field); - field.setOnEditorActionListener((v, actionId, event) -> { - if (actionId == EditorInfo.IME_ACTION_SEND) { - onSendClicked(); - return true; - } - return false; - }); - - final Button sendButton = mSendButton = view.findViewById(R.id.action_send); - sendButton.setOnClickListener(v -> onSendClicked()); - return view; - } - - @Override - public void onViewCreated(@NonNull final View view, final Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - // Create the log adapter, initially with null cursor - mLogAdapter = new UARTLogAdapter(requireContext()); - setListAdapter(mLogAdapter); - } - - @NonNull - @Override - public Loader onCreateLoader(final int id, final Bundle args) { - switch (id) { - case LOG_REQUEST_ID: { - return new CursorLoader(requireContext(), mLogSession.getSessionEntriesUri(), LOG_PROJECTION, null, null, LogContract.Log.TIME); - } - } - throw new UnsupportedOperationException("Could not create loader with ID " + id); - } - - @Override - public void onLoadFinished(@NonNull 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(@NonNull 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); - requireActivity().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() { - final InputMethodManager imm = (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE); - if (imm != null) { - 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 deleted file mode 100644 index 3089ef1..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManager.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothGatt; -import android.bluetooth.BluetoothGattCharacteristic; -import android.bluetooth.BluetoothGattService; -import android.content.Context; -import androidx.annotation.NonNull; -import android.text.TextUtils; - -import java.util.UUID; - -import no.nordicsemi.android.ble.WriteRequest; -import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; - -public class UARTManager extends LoggableBleManager { - /** Nordic UART Service UUID */ - private final static UUID UART_SERVICE_UUID = UUID.fromString("6E400001-B5A3-F393-E0A9-E50E24DCCA9E"); - /** RX characteristic UUID */ - private final static UUID UART_RX_CHARACTERISTIC_UUID = UUID.fromString("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"); - /** TX characteristic UUID */ - private final static UUID UART_TX_CHARACTERISTIC_UUID = UUID.fromString("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"); - - private BluetoothGattCharacteristic mRXCharacteristic, mTXCharacteristic; - /** - * A flag indicating whether Long Write can be used. It's set to false if the UART RX - * characteristic has only PROPERTY_WRITE_NO_RESPONSE property and no PROPERTY_WRITE. - * If you set it to false here, it will never use Long Write. - * - * TODO change this flag if you don't want to use Long Write even with Write Request. - */ - private boolean mUseLongWrite = true; - - UARTManager(final Context context) { - super(context); - } - - @NonNull - @Override - protected BleManagerGattCallback getGattCallback() { - return mGattCallback; - } - - /** - * BluetoothGatt callbacks for connection/disconnection, service discovery, - * receiving indication, etc. - */ - private final BleManagerGattCallback mGattCallback = new BleManagerGattCallback() { - - @Override - protected void initialize() { - setNotificationCallback(mTXCharacteristic) - .with((device, data) -> { - final String text = data.getStringValue(0); - log(LogContract.Log.Level.APPLICATION, "\"" + text + "\" received"); - mCallbacks.onDataReceived(device, text); - }); - requestMtu(260).enqueue(); - enableNotifications(mTXCharacteristic).enqueue(); - } - - @Override - public boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { - final BluetoothGattService service = gatt.getService(UART_SERVICE_UUID); - if (service != null) { - mRXCharacteristic = service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID); - mTXCharacteristic = service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID); - } - - boolean writeRequest = false; - boolean writeCommand = false; - if (mRXCharacteristic != null) { - final int rxProperties = mRXCharacteristic.getProperties(); - writeRequest = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE) > 0; - writeCommand = (rxProperties & BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE) > 0; - - // Set the WRITE REQUEST type when the characteristic supports it. - // This will allow to send long write (also if the characteristic support it). - // In case there is no WRITE REQUEST property, this manager will divide texts - // longer then MTU-3 bytes into up to MTU-3 bytes chunks. - if (writeRequest) - mRXCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT); - else - mUseLongWrite = false; - } - - return mRXCharacteristic != null && mTXCharacteristic != null && (writeRequest || writeCommand); - } - - @Override - protected void onDeviceDisconnected() { - mRXCharacteristic = null; - mTXCharacteristic = null; - mUseLongWrite = true; - } - }; - - // This has been moved to the service in BleManager v2.0. - /*@Override - protected boolean shouldAutoConnect() { - // We want the connection to be kept - return true; - }*/ - - /** - * Sends the given text to RX characteristic. - * @param text the text to be sent - */ - public void send(final String text) { - // Are we connected? - if (mRXCharacteristic == null) - return; - - if (!TextUtils.isEmpty(text)) { - final WriteRequest request = writeCharacteristic(mRXCharacteristic, text.getBytes()) - .with((device, data) -> log(LogContract.Log.Level.APPLICATION, - "\"" + data.getStringValue(0) + "\" sent")); - if (!mUseLongWrite) { - // This will automatically split the long data into MTU-3-byte long packets. - request.split(); - } - request.enqueue(); - } - } -} 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 deleted file mode 100644 index 4a5bf24..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTManagerCallbacks.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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 android.bluetooth.BluetoothDevice; - -import no.nordicsemi.android.ble.BleManagerCallbacks; - -public interface UARTManagerCallbacks extends BleManagerCallbacks { - - void onDataReceived(final BluetoothDevice device, final String data); - - void onDataSent(final BluetoothDevice device, final String data); -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTNewConfigurationDialogFragment.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTNewConfigurationDialogFragment.java deleted file mode 100644 index d6820e0..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTNewConfigurationDialogFragment.java +++ /dev/null @@ -1,134 +0,0 @@ -/************************************************************************************************************************************************* - * 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 android.app.Dialog; -import android.content.Context; -import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import androidx.appcompat.app.AlertDialog; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; - -import no.nordicsemi.android.nrftoolbox.R; - -public class UARTNewConfigurationDialogFragment extends DialogFragment implements View.OnClickListener { - private static final String NAME = "name"; - private static final String DUPLICATE = "duplicate"; - - private EditText mEditText; - - private NewConfigurationDialogListener mListener; - - public interface NewConfigurationDialogListener { - /** - * Creates a new configuration with given name. - * @param name the name - * @param duplicate true if configuration is to be duplicated - */ - void onNewConfiguration(final String name, final boolean duplicate); - - /** - * Renames the current configuration with given name. - * @param newName the new name - */ - void onRenameConfiguration(final String newName); - } - - @Override - public void onAttach(final Context context) { - super.onAttach(context); - - if (context instanceof NewConfigurationDialogListener) { - mListener = (NewConfigurationDialogListener) context; - } else { - throw new IllegalArgumentException("The parent activity must implement NewConfigurationDialogListener"); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mListener = null; - } - - public static DialogFragment getInstance(final String name, final boolean duplicate) { - final DialogFragment dialog = new UARTNewConfigurationDialogFragment(); - - final Bundle args = new Bundle(); - args.putString(NAME, name); - args.putBoolean(DUPLICATE, duplicate); - dialog.setArguments(args); - - return dialog; - } - - @Override - @NonNull - public Dialog onCreateDialog(final Bundle savedInstanceState) { - final Context context = getActivity(); - - final Bundle args = getArguments(); - final String oldName = args.getString(NAME); - final boolean duplicate = args.getBoolean(DUPLICATE); - final int titleResId = duplicate || oldName == null ? R.string.uart_new_configuration_title : R.string.uart_rename_configuration_title; - - final LayoutInflater inflater = LayoutInflater.from(getActivity()); - final View view = inflater.inflate(R.layout.feature_uart_dialog_new_configuration, null); - final EditText editText = mEditText = view.findViewById(R.id.name); - editText.setText(args.getString(NAME)); - final View actionClear = view.findViewById(R.id.action_clear); - actionClear.setOnClickListener(v -> editText.setText(null)); - - final AlertDialog dialog = new AlertDialog.Builder(context).setTitle(titleResId).setView(view).setNegativeButton(R.string.cancel, null) - .setPositiveButton(R.string.ok, null).setCancelable(false).show(); // this must be show() or the getButton() below will return null. - - final Button okButton = dialog.getButton(AlertDialog.BUTTON_POSITIVE); - okButton.setOnClickListener(this); - - return dialog; - } - - @Override - public void onClick(final View v) { - final String newName = mEditText.getText().toString().trim(); - if (TextUtils.isEmpty(newName)) { - mEditText.setError(getString(R.string.uart_empty_name_error)); - return; - } - - final String oldName = getArguments().getString(NAME); - final boolean duplicate = getArguments().getBoolean(DUPLICATE); - - if (duplicate || TextUtils.isEmpty(oldName)) - mListener.onNewConfiguration(newName, duplicate); - else { - mListener.onRenameConfiguration(newName); - } - dismiss(); - } -} 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 deleted file mode 100644 index 2e885ff..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/UARTService.java +++ /dev/null @@ -1,319 +0,0 @@ -/* - * 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 android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import android.text.TextUtils; -import android.util.Log; - -import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.wearable.MessageApi; -import com.google.android.gms.wearable.Node; -import com.google.android.gms.wearable.NodeApi; -import com.google.android.gms.wearable.Wearable; - -import no.nordicsemi.android.log.Logger; -import no.nordicsemi.android.nrftoolbox.FeaturesActivity; -import no.nordicsemi.android.nrftoolbox.R; -import no.nordicsemi.android.nrftoolbox.ToolboxApplication; -import no.nordicsemi.android.nrftoolbox.profile.BleProfileService; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; -import no.nordicsemi.android.nrftoolbox.wearable.common.Constants; - -public class UARTService extends BleProfileService implements UARTManagerCallbacks { - private static final String TAG = "UARTService"; - - 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"; - - /** A broadcast message with this action and the message in {@link Intent#EXTRA_TEXT} will be sent t the UART device. */ - public final static String ACTION_SEND = "no.nordicsemi.android.nrftoolbox.uart.ACTION_SEND"; - /** A broadcast message with this action is triggered when a message is received from the UART device. */ - private final static String ACTION_RECEIVE = "no.nordicsemi.android.nrftoolbox.uart.ACTION_RECEIVE"; - /** Action send when user press the DISCONNECT button on the notification. */ - public final static String ACTION_DISCONNECT = "no.nordicsemi.android.nrftoolbox.uart.ACTION_DISCONNECT"; - /** A source of an action. */ - public final static String EXTRA_SOURCE = "no.nordicsemi.android.nrftoolbox.uart.EXTRA_SOURCE"; - public final static int SOURCE_NOTIFICATION = 0; - public final static int SOURCE_WEARABLE = 1; - public final static int SOURCE_3RD_PARTY = 2; - - 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 GoogleApiClient mGoogleApiClient; - private UARTManager mManager; - - private final LocalBinder mBinder = new UARTBinder(); - - public class UARTBinder extends LocalBinder implements UARTInterface { - @Override - public void send(final String text) { - mManager.send(text); - } - } - - @Override - protected LocalBinder getBinder() { - return mBinder; - } - - @Override - protected LoggableBleManager initializeManager() { - return mManager = new UARTManager(this); - } - - @Override - protected boolean shouldAutoConnect() { - return true; - } - - @Override - public void onCreate() { - super.onCreate(); - - registerReceiver(mDisconnectActionBroadcastReceiver, new IntentFilter(ACTION_DISCONNECT)); - registerReceiver(mIntentBroadcastReceiver, new IntentFilter(ACTION_SEND)); - - mGoogleApiClient = new GoogleApiClient.Builder(this) - .addApi(Wearable.API) - .build(); - mGoogleApiClient.connect(); - } - - @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); - unregisterReceiver(mIntentBroadcastReceiver); - - mGoogleApiClient.disconnect(); - - super.onDestroy(); - } - - @Override - protected void onRebind() { - // when the activity rebinds to the service, remove the notification - cancelNotification(); - } - - @Override - protected void onUnbind() { - // when the activity closes we need to show the notification that user is connected to the sensor - createNotification(R.string.uart_notification_connected_message, 0); - } - - @Override - public void onDeviceConnected(@NonNull final BluetoothDevice device) { - super.onDeviceConnected(device); - sendMessageToWearables(Constants.UART.DEVICE_CONNECTED, notNull(getDeviceName())); - } - - @Override - protected boolean stopWhenDisconnected() { - return false; - } - - @Override - public void onDeviceDisconnected(@NonNull final BluetoothDevice device) { - super.onDeviceDisconnected(device); - sendMessageToWearables(Constants.UART.DEVICE_DISCONNECTED, notNull(getDeviceName())); - } - - @Override - public void onLinkLossOccurred(@NonNull final BluetoothDevice device) { - super.onLinkLossOccurred(device); - sendMessageToWearables(Constants.UART.DEVICE_LINKLOSS, notNull(getDeviceName())); - } - - private String notNull(final String name) { - if (!TextUtils.isEmpty(name)) - return name; - return getString(R.string.not_available); - } - - @Override - public void onDataReceived(final BluetoothDevice device, final String data) { - final Intent broadcast = new Intent(BROADCAST_UART_RX); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_DATA, data); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - - // send the data received to other apps, e.g. the Tasker - final Intent globalBroadcast = new Intent(ACTION_RECEIVE); - globalBroadcast.putExtra(BluetoothDevice.EXTRA_DEVICE, getBluetoothDevice()); - globalBroadcast.putExtra(Intent.EXTRA_TEXT, data); - sendBroadcast(globalBroadcast); - } - - @Override - public void onDataSent(final BluetoothDevice device, final String data) { - final Intent broadcast = new Intent(BROADCAST_UART_TX); - broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); - broadcast.putExtra(EXTRA_DATA, data); - LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - } - - /** - * Sends the given message to all connected wearables. If the path is equal to {@link Constants.UART#DEVICE_DISCONNECTED} the service will be stopped afterwards. - * @param path message path - * @param message the message - */ - private void sendMessageToWearables(final @NonNull String path, final @NonNull String message) { - if(mGoogleApiClient.isConnected()) { - new Thread(() -> { - NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(mGoogleApiClient).await(); - for(Node node : nodes.getNodes()) { - Logger.v(getLogSession(), "[WEAR] Sending message '" + path + "' to " + node.getDisplayName()); - final MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(mGoogleApiClient, node.getId(), path, message.getBytes()).await(); - if(result.getStatus().isSuccess()){ - Logger.i(getLogSession(), "[WEAR] Message sent"); - } else { - Logger.w(getLogSession(), "[WEAR] Sending message failed: " + result.getStatus().getStatusMessage()); - Log.w(TAG, "Failed to send " + path + " to " + node.getDisplayName()); - } - } - if (Constants.UART.DEVICE_DISCONNECTED.equals(path)) - stopService(); - }).start(); - } else { - if (Constants.UART.DEVICE_DISCONNECTED.equals(path)) - stopService(); - } - } - - /** - * 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 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, UARTActivity.class); - - final Intent disconnect = new Intent(ACTION_DISCONNECT); - disconnect.putExtra(EXTRA_SOURCE, SOURCE_NOTIFICATION); - final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT); - - // both activities above have launchMode="singleTask" in the AndroidManifest.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 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, ToolboxApplication.CONNECTED_DEVICE_CHANNEL); - builder.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(new NotificationCompat.Action(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) { - final int source = intent.getIntExtra(EXTRA_SOURCE, SOURCE_NOTIFICATION); - switch (source) { - case SOURCE_NOTIFICATION: - Logger.i(getLogSession(), "[Notification] Disconnect action pressed"); - break; - case SOURCE_WEARABLE: - Logger.i(getLogSession(), "[WEAR] '" + Constants.ACTION_DISCONNECT + "' message received"); - break; - } - if (isConnected()) - getBinder().disconnect(); - else - stopSelf(); - } - }; - - /** - * Broadcast receiver that listens for {@link #ACTION_SEND} from other apps. Sends the String or int content of the {@link Intent#EXTRA_TEXT} extra to the remote device. - * The integer content will be sent as String (65 -> "65", not 65 -> "A"). - */ - private BroadcastReceiver mIntentBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(final Context context, final Intent intent) { - final boolean hasMessage = intent.hasExtra(Intent.EXTRA_TEXT); - if (hasMessage) { - String message = intent.getStringExtra(Intent.EXTRA_TEXT); - if (message == null) { - final int intValue = intent.getIntExtra(Intent.EXTRA_TEXT, Integer.MIN_VALUE); // how big is the chance of such data? - if (intValue != Integer.MIN_VALUE) - message = String.valueOf(intValue); - } - - if (message != null) { - final int source = intent.getIntExtra(EXTRA_SOURCE, SOURCE_3RD_PARTY); - switch (source) { - case SOURCE_WEARABLE: - Logger.i(getLogSession(), "[WEAR] '" + Constants.UART.COMMAND + "' message received with data: \"" + message + "\""); - break; - case SOURCE_3RD_PARTY: - default: - Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received with data: \"" + message + "\""); - break; - } - mManager.send(message); - return; - } - } - // No data od incompatible type of EXTRA_TEXT - if (!hasMessage) - Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received no data."); - else - Logger.i(getLogSession(), "[Broadcast] " + ACTION_SEND + " broadcast received incompatible data type. Only String and int are supported."); - } - }; -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/ConfigurationContract.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/ConfigurationContract.java deleted file mode 100644 index c0a40d1..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/ConfigurationContract.java +++ /dev/null @@ -1,38 +0,0 @@ -/************************************************************************************************************************************************* - * 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.database; - -import android.provider.BaseColumns; - -public class ConfigurationContract { - - protected interface ConfigurationColumns { - /** The XML with configuration. */ - String XML = "xml"; - } - - public final class Configuration implements BaseColumns, NameColumns, ConfigurationColumns, UndoColumns { - private Configuration() { - // empty - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/DatabaseHelper.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/DatabaseHelper.java deleted file mode 100644 index e636aaf..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/DatabaseHelper.java +++ /dev/null @@ -1,259 +0,0 @@ -/************************************************************************************************************************************************* - * 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.database; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.provider.BaseColumns; - -public class DatabaseHelper { - /** Database file name */ - private static final String DATABASE_NAME = "toolbox_uart.db"; - /** Database version */ - private static final int DATABASE_VERSION = 1; - - private interface Tables { - /** Configurations table. See {@link ConfigurationContract.Configuration} for column names. */ - String CONFIGURATIONS = "configurations"; - } - - private static final String[] ID_PROJECTION = new String[] { BaseColumns._ID }; - private static final String[] NAME_PROJECTION = new String[] { BaseColumns._ID, NameColumns.NAME }; - private static final String[] XML_PROJECTION = new String[] { BaseColumns._ID, ConfigurationContract.Configuration.XML }; - private static final String[] CONFIGURATION_PROJECTION = new String[] { BaseColumns._ID, NameColumns.NAME, ConfigurationContract.Configuration.XML }; - - private static final String ID_SELECTION = BaseColumns._ID + "=?"; - private static final String NAME_SELECTION = NameColumns.NAME + "=?"; - private static final String DELETED_SELECTION = UndoColumns.DELETED + "=1"; - private static final String NOT_DELETED_SELECTION = UndoColumns.DELETED + "=0"; - - private static SQLiteHelper mDatabaseHelper; - private static SQLiteDatabase mDatabase; - private final ContentValues mValues = new ContentValues(); - private final String[] mSingleArg = new String[1]; - - public DatabaseHelper(final Context context) { - if (mDatabaseHelper == null) { - mDatabaseHelper = new SQLiteHelper(context); - mDatabase = mDatabaseHelper.getWritableDatabase(); - } - } - - /** - * Returns number of saved configurations. - */ - public int getConfigurationsCount() { - final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, ID_PROJECTION, NOT_DELETED_SELECTION, null, null, null, null); - try { - return cursor.getCount(); - } finally { - cursor.close(); - } - } - - /** - * Returns the list of all saved configurations. - * @return cursor - */ - public Cursor getConfigurations() { - return mDatabase.query(Tables.CONFIGURATIONS, CONFIGURATION_PROJECTION, NOT_DELETED_SELECTION, null, null, null, ConfigurationContract.Configuration.NAME + " ASC"); - } - - /** - * Returns the list of names of all saved configurations. - * @return cursor - */ - public Cursor getConfigurationsNames() { - return mDatabase.query(Tables.CONFIGURATIONS, NAME_PROJECTION, NOT_DELETED_SELECTION, null, null, null, ConfigurationContract.Configuration.NAME + " ASC"); - } - - /** - * Returns the XML wth the configuration by id. - * @param id the configuration id in the DB - * @return the XML with configuration or null - */ - public String getConfiguration(final long id) { - mSingleArg[0] = String.valueOf(id); - - final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, XML_PROJECTION, ID_SELECTION, mSingleArg, null, null, null); - try { - if (cursor.moveToNext()) - return cursor.getString(1 /* XML */); - return null; - } finally { - cursor.close(); - } - } - - /** - * Adds new configuration to the database. - * @param name the configuration name - * @param configuration the XML - * @return the id or -1 if error occurred - */ - public long addConfiguration(final String name, final String configuration) { - final ContentValues values = mValues; - values.clear(); - values.put(ConfigurationContract.Configuration.NAME, name); - values.put(ConfigurationContract.Configuration.XML, configuration); - values.put(ConfigurationContract.Configuration.DELETED, 0); - return mDatabase.replace(Tables.CONFIGURATIONS, null, values); - } - - /** - * Updates the configuration with the given name with the new XML - * @param name the configuration name to be updated - * @param configuration the new XML with configuration - * @return number of rows updated - */ - public int updateConfiguration(final String name, final String configuration) { - mSingleArg[0] = name; - - final ContentValues values = mValues; - values.clear(); - values.put(ConfigurationContract.Configuration.XML, configuration); - values.put(ConfigurationContract.Configuration.DELETED, 0); - return mDatabase.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, mSingleArg); - } - - /** - * Marks the configuration with given name as deleted. If may be restored or removed permanently afterwards. - * @param name the configuration name - * @return id of the deleted configuration - */ - public long deleteConfiguration(final String name) { - mSingleArg[0] = name; - - final ContentValues values = mValues; - values.clear(); - values.put(ConfigurationContract.Configuration.DELETED, 1); - mDatabase.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, mSingleArg); - - final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, ID_PROJECTION, NAME_SELECTION, mSingleArg, null, null, null); - try { - if (cursor.moveToNext()) - return cursor.getLong(0 /* _ID */); - return -1; - } finally { - cursor.close(); - } - } - - public int removeDeletedServerConfigurations() { - return mDatabase.delete(Tables.CONFIGURATIONS, DELETED_SELECTION, null); - } - - /** - * Restores deleted configuration. Returns the ID of the first one. - * @return the DI of the restored configuration. - */ - public long restoreDeletedServerConfiguration(final String name) { - mSingleArg[0] = name; - - final ContentValues values = mValues; - values.clear(); - values.put(ConfigurationContract.Configuration.DELETED, 0); - mDatabase.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, mSingleArg); - - final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, ID_PROJECTION, NAME_SELECTION, mSingleArg, null, null, null); - try { - if (cursor.moveToNext()) - return cursor.getLong(0 /* _ID */); - return -1; - } finally { - cursor.close(); - } - } - - /** - * Renames the server configuration and replaces its XML (name inside has changed). - * @param oldName the old name to look for - * @param newName the new configuration name - * @param configuration the new XML - * @return number of rows affected - */ - public int renameConfiguration(final String oldName, final String newName, final String configuration) { - mSingleArg[0] = oldName; - - final ContentValues values = mValues; - values.clear(); - values.put(ConfigurationContract.Configuration.NAME, newName); - values.put(ConfigurationContract.Configuration.XML, configuration); - return mDatabase.update(Tables.CONFIGURATIONS, values, NAME_SELECTION, mSingleArg); - } - - /** - * Returns true if a configuration with given name was found in the database. - * @param name the name to check - * @return true if such name exists, false otherwise - */ - public boolean configurationExists(final String name) { - mSingleArg[0] = name; - - final Cursor cursor = mDatabase.query(Tables.CONFIGURATIONS, NAME_PROJECTION, NAME_SELECTION + " AND " + NOT_DELETED_SELECTION, mSingleArg, null, null, null); - try { - return cursor.getCount() > 0; - } finally { - cursor.close(); - } - } - - private class SQLiteHelper extends SQLiteOpenHelper { - - /** - * The SQL code that creates the Server Configurations: - * - *
-		 * ----------------------------------------------------------------------------
-		 *                            CONFIGURATIONS                           |
-		 * ----------------------------------------------------------------------------
-		 * | _id (int, pk, auto increment) | name (text) | xml (text) | deleted (int) |
-		 * ----------------------------------------------------------------------------
-		 * 
- */ - private static final String CREATE_CONFIGURATIONS = "CREATE TABLE " + Tables.CONFIGURATIONS+ "(" + ConfigurationContract.Configuration._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " - + ConfigurationContract.Configuration.NAME + " TEXT UNIQUE NOT NULL, " + ConfigurationContract.Configuration.XML + " TEXT NOT NULL, " + ConfigurationContract.Configuration.DELETED +" INTEGER NOT NULL DEFAULT(0))"; - - private static final String DROP_IF_EXISTS = "DROP TABLE IF EXISTS "; - - public SQLiteHelper(Context context) { - super(context, DATABASE_NAME, null, DATABASE_VERSION); - } - - @Override - public void onCreate(final SQLiteDatabase db) { - db.execSQL(CREATE_CONFIGURATIONS); - } - - @Override - public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) { - // This method does nothing for now. - switch (oldVersion) { - case 1: - // do nothing - } - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/NameColumns.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/NameColumns.java deleted file mode 100644 index 65aba51..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/NameColumns.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * 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.database; - -public interface NameColumns { - /** The name */ - String NAME = "name"; -} \ No newline at end of file diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/UndoColumns.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/UndoColumns.java deleted file mode 100644 index 12ff898..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/database/UndoColumns.java +++ /dev/null @@ -1,27 +0,0 @@ -/************************************************************************************************************************************************* - * 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.database; - -public interface UndoColumns { - /** The 'deleted' flag */ - String DELETED = "deleted"; -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/Command.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/Command.java deleted file mode 100644 index e364c55..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/Command.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 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.domain; - -import org.simpleframework.xml.Attribute; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.Text; - -@Root -public class Command { - public enum Icon { - LEFT(0), - UP(1), - RIGHT(2), - DOWN(3), - SETTINGS(4), - REW(5), - PLAY(6), - PAUSE(7), - STOP(8), - FWD(9), - INFO(10), - NUMBER_1(11), - NUMBER_2(12), - NUMBER_3(13), - NUMBER_4(14), - NUMBER_5(15), - NUMBER_6(16), - NUMBER_7(17), - NUMBER_8(18), - NUMBER_9(19); - - public final int index; - - Icon(final int index) { - this.index = index; - } - } - - public enum Eol { - LF(0), - CR(1), - CR_LF(2); - - public final int index; - - Eol(final int index) { - this.index = index; - } - } - - @Text(required = false) - private String command; - - @Attribute(required = false) - private boolean active = false; - - @Attribute(required = false) - private Eol eol = Eol.LF; - - @Attribute(required = false) - private Icon icon = Icon.LEFT; - - /** - * Sets the command. - * @param command the command that will be sent to UART device - */ - public void setCommand(final String command) { - this.command = command; - } - - /** - * Sets whether the command is active. - * @param active true to make it active - */ - public void setActive(final boolean active) { - this.active = active; - } - - /** - * Sets the new line type. - * @param eol end of line terminator - */ - public void setEol(final int eol) { - this.eol = Eol.values()[eol]; - } - - /** - * Sets the icon index. - * @param index index of the icon. - */ - public void setIconIndex(final int index) { - this.icon = Icon.values()[index]; - } - - /** - * Returns the command that will be sent to UART device. - * @return the command - */ - public String getCommand() { - return command; - } - - /** - * Returns whether the icon is active. - * @return true if it's active - */ - public boolean isActive() { - return active; - } - - /** - * Returns the new line type. - * @return end of line terminator - */ - public Eol getEol() { - return eol; - } - - /** - * Returns the icon index. - * @return the icon index - */ - public int getIconIndex() { - return icon.index; - } - /** - * Returns the EOL index. - * @return the EOL index - */ - public int getEolIndex() { - return eol.index; - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/UartConfiguration.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/UartConfiguration.java deleted file mode 100644 index 981f48c..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/domain/UartConfiguration.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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.domain; - -import org.simpleframework.xml.Attribute; -import org.simpleframework.xml.ElementArray; -import org.simpleframework.xml.Root; -import org.simpleframework.xml.core.PersistenceException; -import org.simpleframework.xml.core.Validate; - -@Root -public class UartConfiguration { - public static final int COMMANDS_COUNT = 9; - - @Attribute(required = false, empty = "Unnamed") - private String name; - - @ElementArray - private Command[] commands = new Command[COMMANDS_COUNT]; - - /** - * Returns the field name - * - * @return optional name - */ - public String getName() { - return name; - } - - /** - * Sets the name to specified value - * @param name the new name - */ - public void setName(final String name) { - this.name = name; - } - - /** - * Returns the array of commands. There is always 9 of them. - * @return the commands array - */ - public Command[] getCommands() { - return commands; - } - - @Validate - private void validate() throws PersistenceException{ - if (commands == null || commands.length != COMMANDS_COUNT) - throw new PersistenceException("There must be always " + COMMANDS_COUNT + " commands in a configuration."); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/wearable/UARTConfigurationSynchronizer.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/wearable/UARTConfigurationSynchronizer.java deleted file mode 100644 index 696a078..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/uart/wearable/UARTConfigurationSynchronizer.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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.wearable; - -import android.content.Context; -import android.net.Uri; - -import com.google.android.gms.common.api.GoogleApiClient; -import com.google.android.gms.common.api.PendingResult; -import com.google.android.gms.wearable.DataApi; -import com.google.android.gms.wearable.DataMap; -import com.google.android.gms.wearable.PutDataMapRequest; -import com.google.android.gms.wearable.PutDataRequest; -import com.google.android.gms.wearable.Wearable; - -import java.util.ArrayList; - -import no.nordicsemi.android.nrftoolbox.uart.domain.Command; -import no.nordicsemi.android.nrftoolbox.uart.domain.UartConfiguration; -import no.nordicsemi.android.nrftoolbox.wearable.common.Constants; - -public class UARTConfigurationSynchronizer { - private static final String WEAR_URI_PREFIX = "wear:"; // no / at the end as the path already has it - - private static UARTConfigurationSynchronizer mInstance; - private GoogleApiClient mGoogleApiClient; - - /** - * Initializes the synchronizer. - * @param context the activity context - * @param listener the connection callbacks listener - */ - public static UARTConfigurationSynchronizer from(final Context context, final GoogleApiClient.ConnectionCallbacks listener) { - if (mInstance == null) - mInstance = new UARTConfigurationSynchronizer(); - - mInstance.init(context, listener); - return mInstance; - } - - private UARTConfigurationSynchronizer() { - // private constructor - } - - private void init(final Context context, final GoogleApiClient.ConnectionCallbacks listener) { - if (mGoogleApiClient != null) - return; - - mGoogleApiClient = new GoogleApiClient.Builder(context) - .addApiIfAvailable(Wearable.API) - .addConnectionCallbacks(listener) - .build(); - mGoogleApiClient.connect(); - } - - /** - * Closes the synchronizer. - */ - public void close() { - if (mGoogleApiClient != null) - mGoogleApiClient.disconnect(); - mGoogleApiClient = null; - } - - /** - * Returns true if Wearable API has been connected. - */ - public boolean hasConnectedApi() { - return mGoogleApiClient != null && mGoogleApiClient.isConnected() && mGoogleApiClient.hasConnectedApi(Wearable.API); - } - - /** - * Synchronizes the UART configurations between handheld and wearables. - * Call this when configuration has been created or altered. - * @return pending result - */ - public PendingResult onConfigurationAddedOrEdited(final long id, final UartConfiguration configuration) { - if (!hasConnectedApi()) - return null; - - final PutDataMapRequest mapRequest = PutDataMapRequest.create(Constants.UART.CONFIGURATIONS + "/" + id); - final DataMap map = mapRequest.getDataMap(); - map.putString(Constants.UART.Configuration.NAME, configuration.getName()); - final ArrayList commands = new ArrayList<>(UartConfiguration.COMMANDS_COUNT); - for (Command command : configuration.getCommands()) { - if (command != null && command.isActive()) { - final DataMap item = new DataMap(); - item.putInt(Constants.UART.Configuration.Command.ICON_ID, command.getIconIndex()); - item.putString(Constants.UART.Configuration.Command.MESSAGE, command.getCommand()); - item.putInt(Constants.UART.Configuration.Command.EOL, command.getEolIndex()); - commands.add(item); - } - } - map.putDataMapArrayList(Constants.UART.Configuration.COMMANDS, commands); - final PutDataRequest request = mapRequest.asPutDataRequest(); - return Wearable.DataApi.putDataItem(mGoogleApiClient, request); - } - - /** - * Synchronizes the UART configurations between handheld and wearables. - * Call this when configuration has been deleted. - * @return pending result - */ - public PendingResult onConfigurationDeleted(final long id) { - if (!hasConnectedApi()) - return null; - return Wearable.DataApi.deleteDataItems(mGoogleApiClient, id2Uri(id)); - } - - /** - * Creates URI without nodeId. - * @param id the configuration id in the database - * @return Uri that may be used to delete the associated DataMap. - */ - private Uri id2Uri(final long id) { - return Uri.parse(WEAR_URI_PREFIX + Constants.UART.CONFIGURATIONS + "/" + id); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/FileHelper.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/FileHelper.java deleted file mode 100644 index a0aef68..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/FileHelper.java +++ /dev/null @@ -1,246 +0,0 @@ -/* - * 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 android.content.ContentValues; -import android.content.Context; -import android.content.SharedPreferences; -import android.database.Cursor; -import android.net.Uri; -import android.os.Environment; -import android.preference.PreferenceManager; -import android.provider.BaseColumns; -import android.provider.MediaStore; -import android.widget.Toast; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import no.nordicsemi.android.nrftoolbox.R; - -public class FileHelper { - private static final String TAG = "FileHelper"; - - private static final String PREFS_SAMPLES_VERSION = "no.nordicsemi.android.nrftoolbox.dfu.PREFS_SAMPLES_VERSION"; - private static final int CURRENT_SAMPLES_VERSION = 4; - - public static final String NORDIC_FOLDER = "Nordic Semiconductor"; - public static final String UART_FOLDER = "UART Configurations"; - public static final String BOARD_FOLDER = "Board"; - public static final String BOARD_NRF6310_FOLDER = "nrf6310"; - public static final String BOARD_PCA10028_FOLDER = "pca10028"; - public static final String BOARD_PCA10036_FOLDER = "pca10036"; - - public static boolean newSamplesAvailable(final Context context) { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); - final int version = preferences.getInt(PREFS_SAMPLES_VERSION, 0); - return version < CURRENT_SAMPLES_VERSION; - } - - public static void createSamples(final Context context) { - final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context); - 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 migrated to 3.1 - new File(root, "dfu_2_0.sh").delete(); // This file has been migrated to 3.0 - new File(root, "dfu_3_0.sh").delete(); // This file has been migrated to 3.1 - 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(context, 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(context, 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(context, 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(context, 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(context, 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(context, 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(context, 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(context, 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(context, R.raw.ble_app_hrs_dfu_s110_v7_1_0_ext_init, f); - oldCopied = true; - } - new File(root, "ble_app_hrs_dfu_s110_v8_0_0.zip").delete(); // name changed - f = new File(pca10028, "ble_app_hrs_dfu_s110_v8_0_0_sdk_v8_0.zip"); - if (!f.exists()) { - copyRawResource(context, R.raw.ble_app_hrs_dfu_s110_v8_0_0_sdk_v8_0, f); - newCopied = true; - } - f = new File(pca10028, "ble_app_hrs_dfu_s110_v8_0_0_sdk_v9_0.zip"); - if (!f.exists()) { - copyRawResource(context, R.raw.ble_app_hrs_dfu_s110_v8_0_0_sdk_v9_0, f); - newCopied = true; - } - f = new File(pca10028, "ble_app_hrs_dfu_all_in_one_sdk_v9_0.zip"); - if (!f.exists()) { - copyRawResource(context, R.raw.ble_app_hrs_dfu_all_in_one_sdk_v9_0, f); - newCopied = true; - } - - if (oldCopied) - Toast.makeText(context, R.string.dfu_example_files_created, Toast.LENGTH_SHORT).show(); - else if (newCopied) - Toast.makeText(context, R.string.dfu_example_new_files_created, Toast.LENGTH_SHORT).show(); - - // Scripts - newCopied = false; - f = new File(root, "dfu_3_1.bat"); - if (!f.exists()) { - copyRawResource(context, R.raw.dfu_win_3_1, f); - newCopied = true; - } - f = new File(root, "dfu_3_1.sh"); - if (!f.exists()) { - copyRawResource(context, R.raw.dfu_mac_3_1, f); - newCopied = true; - } - f = new File(root, "README.txt"); - if (!f.exists()) { - copyRawResource(context, R.raw.readme, f); - } - if (newCopied) - Toast.makeText(context, 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 context activity context - * @param rawResId the resource id - * @param dest destination file - */ - private static void copyRawResource(final Context context, final int rawResId, final File dest) { - try { - final InputStream is = context.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()); - } - } - - public static Uri getContentUri(final Context context, final File file) { - final String filePath = file.getAbsolutePath(); - final Uri uri = MediaStore.Files.getContentUri("external"); - final Cursor cursor = context.getContentResolver().query( - uri, - new String[]{BaseColumns._ID}, - MediaStore.Files.FileColumns.DATA + "=? ", - new String[]{filePath}, null); - try { - if (cursor != null && cursor.moveToFirst()) { - final int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID)); - return Uri.withAppendedPath(uri, String.valueOf(id)); - } else { - if (file.exists()) { - final ContentValues values = new ContentValues(); - values.put(MediaStore.Files.FileColumns.DATA, filePath); - return context.getContentResolver().insert(uri, values); - } else { - return null; - } - } - } finally { - cursor.close(); - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/ParserUtils.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/ParserUtils.java deleted file mode 100644 index 5e11b14..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/utility/ParserUtils.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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; - -public class ParserUtils extends no.nordicsemi.android.ble.utils.ParserUtils { - - public static String parseDebug(final byte[] data) { - if (data == null || data.length == 0) - return ""; - - final char[] out = new char[data.length * 2]; - for (int j = 0; j < data.length; j++) { - int v = data[j] & 0xFF; - out[j * 2] = HEX_ARRAY[v >>> 4]; - out[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return "0x" + new String(out); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/MainWearableListenerService.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/MainWearableListenerService.java deleted file mode 100644 index 30661f5..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/wearable/MainWearableListenerService.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * 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.wearable; - -import android.content.Intent; - -import com.google.android.gms.wearable.MessageEvent; -import com.google.android.gms.wearable.WearableListenerService; - -import no.nordicsemi.android.nrftoolbox.uart.UARTService; -import no.nordicsemi.android.nrftoolbox.wearable.common.Constants; - -/** - * The main listener for messages from Wearable devices. There may be only one such service per application so it has to handle messages from all profiles. - */ -public class MainWearableListenerService extends WearableListenerService { - - @Override - public void onMessageReceived(final MessageEvent messageEvent) { - switch (messageEvent.getPath()) { - case Constants.ACTION_DISCONNECT: { - // A disconnect message was sent. The information which profile should be disconnected is in the data. - final String profile = new String(messageEvent.getData()); - - switch (profile) { - // Currently only UART profile has Wear support - case Constants.UART.PROFILE: { - final Intent disconnectIntent = new Intent(UARTService.ACTION_DISCONNECT); - disconnectIntent.putExtra(UARTService.EXTRA_SOURCE, UARTService.SOURCE_WEARABLE); - sendBroadcast(disconnectIntent); - break; - } - } - break; - } - case Constants.UART.COMMAND: { - final String command = new String(messageEvent.getData()); - - final Intent intent = new Intent(UARTService.ACTION_SEND); - intent.putExtra(UARTService.EXTRA_SOURCE, UARTService.SOURCE_WEARABLE); - intent.putExtra(Intent.EXTRA_TEXT, command); - sendBroadcast(intent); - } - default: - super.onMessageReceived(messageEvent); - break; - } - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ClosableSpinner.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ClosableSpinner.java deleted file mode 100644 index baf19ed..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ClosableSpinner.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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 android.content.Context; -import android.util.AttributeSet; - -public class ClosableSpinner extends androidx.appcompat.widget.AppCompatSpinner { - public ClosableSpinner(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void close() { - super.onDetachedFromWindow(); - } -} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/DividerItemDecoration.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/DividerItemDecoration.java deleted file mode 100644 index 9d317f6..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/DividerItemDecoration.java +++ /dev/null @@ -1,111 +0,0 @@ -/************************************************************************************************************************************************* - * 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 android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import android.view.View; - -public class DividerItemDecoration extends RecyclerView.ItemDecoration { - - private static final int[] ATTRS = new int[]{ - android.R.attr.listDivider - }; - - public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; - - public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; - - private Drawable mDivider; - - private int mOrientation; - - public DividerItemDecoration(Context context, int orientation) { - final TypedArray a = context.obtainStyledAttributes(ATTRS); - mDivider = a.getDrawable(0); - a.recycle(); - setOrientation(orientation); - } - - public void setOrientation(int orientation) { - if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { - throw new IllegalArgumentException("invalid orientation"); - } - mOrientation = orientation; - } - - @Override - public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { - if (mOrientation == VERTICAL_LIST) { - drawVertical(c, parent); - } else { - drawHorizontal(c, parent); - } - } - - public void drawVertical(Canvas c, RecyclerView parent) { - final int left = parent.getPaddingLeft(); - final int right = parent.getWidth() - parent.getPaddingRight(); - - final int childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = parent.getChildAt(i); - final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child - .getLayoutParams(); - final int top = child.getBottom() + params.bottomMargin; - final int bottom = top + mDivider.getIntrinsicHeight(); - mDivider.setBounds(left, top, right, bottom); - mDivider.draw(c); - } - } - - public void drawHorizontal(Canvas c, RecyclerView parent) { - final int top = parent.getPaddingTop(); - final int bottom = parent.getHeight() - parent.getPaddingBottom(); - - final int childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { - final View child = parent.getChildAt(i); - final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child - .getLayoutParams(); - final int left = child.getRight() + params.rightMargin; - final int right = left + mDivider.getIntrinsicHeight(); - mDivider.setBounds(left, top, right, bottom); - mDivider.draw(c); - } - } - - @Override - public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { - if (mOrientation == VERTICAL_LIST) { - outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); - } else { - outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ForegroundLinearLayout.java b/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ForegroundLinearLayout.java deleted file mode 100644 index c6e9598..0000000 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ForegroundLinearLayout.java +++ /dev/null @@ -1,148 +0,0 @@ -/************************************************************************************************************************************************* - * 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 android.annotation.TargetApi; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.NinePatchDrawable; -import android.os.Build; -import androidx.annotation.NonNull; -import android.util.AttributeSet; -import android.widget.LinearLayout; - -import no.nordicsemi.android.nrftoolbox.R; - -public class ForegroundLinearLayout extends LinearLayout { - - private Drawable mForegroundSelector; - private Rect mRectPadding; - private boolean mUseBackgroundPadding = false; - - public ForegroundLinearLayout(Context context) { - super(context); - } - - public ForegroundLinearLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public ForegroundLinearLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundLinearLayout, - defStyle, 0); - - final Drawable d = a.getDrawable(R.styleable.ForegroundRelativeLayout_foreground); - if (d != null) { - setForeground(d); - } - - a.recycle(); - - if (this.getBackground() instanceof NinePatchDrawable) { - final NinePatchDrawable npd = (NinePatchDrawable) this.getBackground(); - mRectPadding = new Rect(); - if (npd.getPadding(mRectPadding)) { - mUseBackgroundPadding = true; - } - } - } - - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - - if (mForegroundSelector != null && mForegroundSelector.isStateful()) { - mForegroundSelector.setState(getDrawableState()); - } - } - - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - - if (mForegroundSelector != null) { - if (mUseBackgroundPadding) { - mForegroundSelector.setBounds(mRectPadding.left, mRectPadding.top, w - mRectPadding.right, h - mRectPadding.bottom); - } else { - mForegroundSelector.setBounds(0, 0, w, h); - } - } - } - - @Override - protected void dispatchDraw(@NonNull Canvas canvas) { - super.dispatchDraw(canvas); - - if (mForegroundSelector != null) { - mForegroundSelector.draw(canvas); - } - } - - @Override - protected boolean verifyDrawable(Drawable who) { - return super.verifyDrawable(who) || (who == mForegroundSelector); - } - - @Override - public void jumpDrawablesToCurrentState() { - super.jumpDrawablesToCurrentState(); - if (mForegroundSelector != null) mForegroundSelector.jumpToCurrentState(); - } - - public void setForeground(Drawable drawable) { - if (mForegroundSelector != drawable) { - if (mForegroundSelector != null) { - mForegroundSelector.setCallback(null); - unscheduleDrawable(mForegroundSelector); - } - - mForegroundSelector = drawable; - - if (drawable != null) { - setWillNotDraw(false); - drawable.setCallback(this); - if (drawable.isStateful()) { - drawable.setState(getDrawableState()); - } - } else { - setWillNotDraw(true); - } - requestLayout(); - invalidate(); - } - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public void drawableHotspotChanged(float x, float y) { - super.drawableHotspotChanged(x, y); - if (mForegroundSelector != null) { - mForegroundSelector.setHotspot(x, y); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/no/spca/android/iisc/DebugLogger.java b/app/src/main/java/no/spca/android/iisc/DebugLogger.java new file mode 100644 index 0000000..2945d15 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/DebugLogger.java @@ -0,0 +1,51 @@ + +package no.spca.android.iisc; + +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(final String tag, final 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(final String tag, final 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 e(final String tag, final String text, final Throwable e) { + if (BuildConfig.DEBUG) + Log.e(tag, text, e); + } + + public static void wtf(final String tag, final String text) { + if (BuildConfig.DEBUG) { + Log.wtf(tag, text); + } + } + + public static void wtf(final String tag, final String text, final Throwable e) { + if (BuildConfig.DEBUG) { + Log.wtf(tag, text, e); + } + } +} diff --git a/app/src/main/java/no/spca/android/iisc/FeaturesActivity.java b/app/src/main/java/no/spca/android/iisc/FeaturesActivity.java new file mode 100644 index 0000000..40b1b76 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/FeaturesActivity.java @@ -0,0 +1,95 @@ + +package no.spca.android.iisc; + +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.core.view.GravityCompat; +import androidx.drawerlayout.widget.DrawerLayout; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; + +import android.view.View; +import android.widget.GridView; +import android.widget.Toast; + +import no.spca.android.iisc.adapter.AppAdapter; + +public class FeaturesActivity extends AppCompatActivity { + public static final String EXTRA_APP = "application/vnd.no.nordicsemi.type.app"; + public static final String EXTRA_ADDRESS = "application/vnd.no.nordicsemi.type.address"; + + private DrawerLayout mDrawerLayout; + private ActionBarDrawerToggle mDrawerToggle; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_features); + + final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); + setSupportActionBar(toolbar); + + if (!ensureBLEExists()) + finish(); + + final DrawerLayout drawer = mDrawerLayout = findViewById(R.id.drawer_layout); + drawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); + + mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.drawer_open, R.string.drawer_close) { + @Override + public void onDrawerSlide(final View drawerView, final float slideOffset) { + super.onDrawerSlide(drawerView, 0); + } + }; + drawer.addDrawerListener(mDrawerToggle); + + //setupPluginsInDrawer(drawer.findViewById(R.id.plugin_container)); + + final GridView grid = findViewById(R.id.grid); + grid.setAdapter(new AppAdapter(this)); + grid.setEmptyView(findViewById(android.R.id.empty)); + + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + final Intent intent = getIntent(); + if (intent.hasExtra(EXTRA_APP) && intent.hasExtra(EXTRA_ADDRESS)) { + final String app = intent.getStringExtra(EXTRA_APP); + switch (app) { + + default: + break; + } + } + } + + + + @Override + protected void onPostCreate(final Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + mDrawerToggle.syncState(); + } + + @Override + public void onConfigurationChanged(@NonNull final Configuration newConfig) { + super.onConfigurationChanged(newConfig); + mDrawerToggle.onConfigurationChanged(newConfig); + } + + + + + + 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/spca/android/iisc/FontAwesome.java b/app/src/main/java/no/spca/android/iisc/FontAwesome.java new file mode 100644 index 0000000..9fdf1eb --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/FontAwesome.java @@ -0,0 +1,35 @@ +package no.spca.android.iisc; + + +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; + +import androidx.appcompat.widget.AppCompatTextView; + +public class FontAwesome extends AppCompatTextView { + + + public FontAwesome(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public FontAwesome(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public FontAwesome(Context context) { + super(context); + init(); + } + + private void init() { + + Typeface tf = Typeface.createFromAsset(getContext().getAssets(), + "fa-solid-900.ttf"); + setTypeface(tf); + } + +} \ No newline at end of file diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/ToolboxApplication.java b/app/src/main/java/no/spca/android/iisc/NotificationData.java similarity index 56% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/ToolboxApplication.java rename to app/src/main/java/no/spca/android/iisc/NotificationData.java index 4726754..2cbd996 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/ToolboxApplication.java +++ b/app/src/main/java/no/spca/android/iisc/NotificationData.java @@ -1,26 +1,6 @@ -/* - * Copyright (c) 2017, 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; + +package no.spca.android.iisc; import android.app.Application; import android.app.Notification; @@ -31,12 +11,14 @@ import android.os.Build; import no.nordicsemi.android.dfu.DfuServiceInitiator; -public class ToolboxApplication extends Application { +public class NotificationData extends Application { public static final String CONNECTED_DEVICE_CHANNEL = "connected_device_channel"; public static final String FILE_SAVED_CHANNEL = "file_saved_channel"; public static final String PROXIMITY_WARNINGS_CHANNEL = "proximity_warnings_channel"; @Override + + public void onCreate() { super.onCreate(); diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/PermissionRationaleFragment.java b/app/src/main/java/no/spca/android/iisc/PermissionRationaleFragment.java similarity index 52% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/PermissionRationaleFragment.java rename to app/src/main/java/no/spca/android/iisc/PermissionRationaleFragment.java index 5a13ca0..dc39f42 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/PermissionRationaleFragment.java +++ b/app/src/main/java/no/spca/android/iisc/PermissionRationaleFragment.java @@ -1,25 +1,5 @@ -/* - * 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; + +package no.spca.android.iisc; import android.app.Dialog; import android.content.Context; @@ -28,6 +8,7 @@ import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; import androidx.appcompat.app.AlertDialog; + public class PermissionRationaleFragment extends DialogFragment { private static final String ARG_PERMISSION = "ARG_PERMISSION"; private static final String ARG_TEXT = "ARG_TEXT"; diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/About.java b/app/src/main/java/no/spca/android/iisc/SPCA/About.java new file mode 100644 index 0000000..8951113 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/About.java @@ -0,0 +1,21 @@ +package no.spca.android.iisc.SPCA; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; + +import no.spca.android.iisc.R; + + +public class About extends NavigationTop { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_about, null, false); + draw.addView(contentView, 0); + + } +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/AddTest.java b/app/src/main/java/no/spca/android/iisc/SPCA/AddTest.java new file mode 100644 index 0000000..f236262 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/AddTest.java @@ -0,0 +1,870 @@ +package no.spca.android.iisc.SPCA; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.media.MediaPlayer; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import android.os.CountDownTimer; +import android.os.Handler; +import android.text.TextWatcher; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; + +import java.io.File; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.profile.BleProfileService; +import no.spca.android.iisc.profile.BleProfileServiceReadyActivity; + + + +public class AddTest extends BleProfileServiceReadyActivity { + @SuppressWarnings("unused") + private final String TAG = "AddTest"; + + private TextView mValueView; + private TextView mCycleView; + private EditText mFETempValueView; + private EditText mFETimeValueView; + + String acttime; + + private TextView mHeatingStatusView; + private int seconds1 ,seconds2; + private Switch mHeatingState ; + + private EditText mDTimeValueView; + private Integer mDSetTime ; + private EditText mLTimeValueView; + private Integer mLSetTime ; + private EditText mOTimeValueView; + private Integer mOSetTime ; + private String time1,time2,time3; + private Date date1,date2,date3; +private EditText prtocol; + + MediaPlayer msound; + + private final int valuedata=0; + private final int j=0; + private final Handler handler = new Handler(); + private Runnable runnable; + + + private EditText mATimeValueView; + private Integer mASetTime ; + private EditText mETimeValueView; + private Integer mESetTime ; + private TextWatcher txtwt; + + private Button next; + Button connect; + + + + + + private EditText mDTempValueView; + private Integer mDSetTemp ; + private EditText mATempValueView; + private Integer mASetTemp ; + private EditText mETempValueView; + private Integer mESetTemp ; + + private EditText mLTempValueView; + private Integer mLSetTemp ; + private EditText mOTempValueView; + private Integer mOSetTemp ; + private long diff=0; + private long diffSeconds=0; + private long diffMinutes=0; + private long diffHours=0; + private long diff1=0; + private long diffSeconds1=0; + private long diffMinutes1=0; + + private long diffHours1=0; + private Integer mSSetTemp ; + private Integer mSSetTime; + + private int FLAG=0; + + + private int count=0; + private int valuw=0; + + int i=0; + private DatabaseReference TestRef; + private ProgressDialog loadingBar; + private Button save; + private String TestRandomKey,saveCurrentDate, saveCurrentTime,number; + + + + private EditText mNPcrCView; + private Integer mNPcrC ; + private Timer T; + + + + @Override + protected void onCreateView(final Bundle savedInstanceState) { + setContentView(R.layout.activity_feature_template); + loadingBar = new ProgressDialog(this); + + setGUI(); + + next = findViewById(R.id.action_next); + connect = findViewById(R.id.action_connect); + msound= MediaPlayer.create(AddTest.this,R.raw.notification); + + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + connect.performClick(); + + + Intent intent = new Intent(AddTest.this, GraphActivity.class); + + + intent.putExtra("key6",acttime); + + startActivity(intent); + + } + }); + save=findViewById(R.id.action_save); + + save.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + ValidateProductData(); + } + }); + + + + } + + private void setGUI() { + mValueView = findViewById(R.id.Temp_Value); + mCycleView = findViewById(R.id.RemTime_Value); + + mDTempValueView = findViewById(R.id.D_Temp_Set); + mDTimeValueView = findViewById(R.id.D_Time_Set); + mATempValueView = findViewById(R.id.A_Temp_Set); + mATimeValueView = findViewById(R.id.A_Time_Set); + mETempValueView = findViewById(R.id.E_Temp_Set); + mETimeValueView = findViewById(R.id.E_Time_Set); + mLTempValueView=findViewById(R.id.L_Temp_Set); + mOTempValueView=findViewById(R.id.O_Temp_Set); + mLTimeValueView = findViewById(R.id.L_Time_Set); + + mOTimeValueView = findViewById(R.id.O_Time_Set); + mFETimeValueView=findViewById(R.id.S_Time_Set); + mFETempValueView=findViewById(R.id.S_Temp_Set); + + T=new Timer(); + + + SharedPreferences preferences689 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences689.getString("Phone", null); + + + + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + + + + + + + + + + + + + mNPcrCView = findViewById(R.id.N_Pcr_C); +prtocol=findViewById(R.id.protocol_name); + + mHeatingState = findViewById(R.id.heating_state); + mHeatingStatusView= findViewById(R.id.heating_status_text); + //mValueView.setText("fff"); + + + + mHeatingState.setOnCheckedChangeListener((buttonView, isChecked) -> { + if(connect.getText().equals("CONNECT")) + { + Toast.makeText(AddTest.this, "Please connect to device", Toast.LENGTH_SHORT).show(); + + } + else { + if (isChecked) { + startCounter(); + + + i = 1; + if (date2 != null && date1 != null) { + SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + try { + date1 = format.parse(time1); + date2 = format.parse(time2); + diff = (date2.getTime() - date1.getTime()); + diffSeconds = diff / 1000 % 60; + diffMinutes = diff / (60 * 1000) % 60; + diffHours = diff / (60 * 60 * 1000); + + + + } catch (ParseException e) { + e.printStackTrace(); + } + + + } + + Log.e("main", "error data inside " + valuedata); + + getService().heatingSwitch(1); + + mDSetTemp = Integer.parseInt(mDTempValueView.getText().toString()); + getService().sendDTemp(mDSetTemp); + + + mDSetTime = Integer.parseInt(mDTimeValueView.getText().toString()); + getService().sendDTime(mDSetTime); + + mLSetTemp = Integer.parseInt(mLTempValueView.getText().toString()); + getService().sendLTemp(mLSetTemp); + mLSetTime = Integer.parseInt(mLTimeValueView.getText().toString()); + getService().sendLTime(mLSetTime); + + mOSetTemp = Integer.parseInt(mOTempValueView.getText().toString()); + getService().sendOTemp(mOSetTemp); + mOSetTime = Integer.parseInt(mOTimeValueView.getText().toString()); + getService().sendOTime(mOSetTime); + + + mASetTemp = Integer.parseInt(mATempValueView.getText().toString()); + getService().sendATemp(mASetTemp); + mASetTime = Integer.parseInt(mATimeValueView.getText().toString()); + getService().sendATime(mASetTime); + + mESetTemp = Integer.parseInt(mETempValueView.getText().toString()); + getService().sendETemp(mESetTemp); + mESetTime = Integer.parseInt(mETimeValueView.getText().toString()); + getService().sendETime(mESetTime); + + + mSSetTemp = Integer.parseInt(mFETempValueView.getText().toString()); + getService().sendLTemp(mSSetTemp); + mSSetTime = Integer.parseInt(mFETimeValueView.getText().toString()); + getService().sendLTime(mSSetTime); + + + mNPcrC = Integer.parseInt(mNPcrCView.getText().toString()); + getService().sendNPcrN(mNPcrC); + Log.e("main", "error 34" + mDSetTemp); + + Log.e("main", "error 2 " + mDSetTemp); + Log.e("main", "error data box " + valuedata); + + + + + } else { + getService().heatingSwitch(0); + } + mHeatingStatusView.setText(isChecked ? R.string.Heating_block_on : R.string.Heating_block_off); + } + }); + + + + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + @Override + protected void setDefaultUI() { + mValueView.setText("wait"); + mCycleView.setText("wait"); + + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.template_feature_title; + } + + + + + @Override + protected int getDefaultDeviceName() { + return R.string.template_default_name; + } + + @Override + protected UUID getFilterUUID() { + return CycleManager.SERVICE_UUID; + } + + @Override + protected Class getServiceClass() { + return CycleService.class; + } + + @Override + protected void onServiceBound(final CycleService.TemplateBinder binder) { + } + + @Override + protected void onServiceUnbound() { + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + } + + @Override + public void onDeviceDisconnected(final BluetoothDevice device) { + super.onDeviceDisconnected(device); + } + + @SuppressWarnings("unused") + private void setValueOnView(@NonNull final BluetoothDevice device, int value) { + } + + + + + + @SuppressWarnings("unused") + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { + + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + final BluetoothDevice device = intent.getParcelableExtra(no.spca.android.iisc.SPCA.CycleService.EXTRA_DEVICE); + + if (no.spca.android.iisc.SPCA.CycleService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) { + int value = intent.getIntExtra(no.spca.android.iisc.SPCA.CycleService.EXTRA_DATA, 0); + setValueOnView(device, value); + valuw=value; + if(value==0) + { + DateFormat df = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + time1 = df.format(Calendar.getInstance().getTime()); + + + Log.e("main", "error 403 " +time1); + + + + //cycle 1 start + + + } + + else if(value ==1 ) + { + DateFormat df = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + time2 = df.format(Calendar.getInstance().getTime()); + + Log.e("main", "error 404 " +time2); + LocalDateTime date = LocalDateTime.now(); + seconds1 = date.toLocalTime().toSecondOfDay(); + + + + } + else if(value ==2 ) + { + DateFormat df = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + time3 = df.format(Calendar.getInstance().getTime()); + + try { + date1 = df.parse(time1); + date2 = df.parse(time2); + date3=df.parse(time3); + + } catch (ParseException e) { + e.printStackTrace(); + } + Log.e("main", "date 1 " + date2.getTime()); + Log.e("main", "date 2 " + date1.getTime()); + + + diff1 = date3.getTime() - date2.getTime(); + Log.e("main", "difference minute " + diffMinutes); + + + Log.e("main", "difference minute " + diffMinutes); + + diffSeconds1 = diff1 / 1000 % 60; + diffMinutes1 = diff1 / (60 * 1000) % 60; + diffHours1 = diff1/ (60 * 60 * 1000); + Log.e("main", "date difference " + diffMinutes1); + + + + Log.e("main", "error 404 " +time2); + + + + + } + + if(time1 !=null && time2 !=null &&diffSeconds1==1 ) { + + SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + try { + date1 = format.parse(time1); + date2 = format.parse(time2); + Log.e("main", "date 1 " + date2.getTime()); + Log.e("main", "date 2 " + date1.getTime()); + + + diff = date2.getTime() - date1.getTime(); + Log.e("main", "difference minute " + diffMinutes); + + diffSeconds = diff / 1000 % 60; + diffMinutes = diff / (60 * 1000) % 60; + diffHours = diff / (60 * 60 * 1000); + Log.e("main", "date difference " + diffMinutes); + FLAG=1; + + + + } catch (ParseException e) { + e.printStackTrace(); + } + + } + else + { + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + } else if (no.spca.android.iisc.SPCA.CycleService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int batteryLevel = intent.getIntExtra(no.spca.android.iisc.SPCA.CycleService.EXTRA_BATTERY_LEVEL, 0); + onBatteryLevelChanged(device, batteryLevel); + } + + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(no.spca.android.iisc.SPCA.CycleService.BROADCAST_TEMPLATE_MEASUREMENT); + intentFilter.addAction(no.spca.android.iisc.SPCA.CycleService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } + private void startCounter1() + { + T.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + runOnUiThread(new Runnable() { + @Override + public void run() { + + count++; + Log.e("main", "Currnet " + count); + + + } + }); + } + }, 10000, 10000); + + + } + + private void startCounter() + + { + + + + T.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + runOnUiThread(new Runnable() { + @Override + public void run() { + + if(FLAG==1) + { + mNPcrC=mNPcrC-1; + long cycle=mNPcrC.longValue(); + acttime=String.valueOf(diff*cycle); + //acttime="20444444" + connect.performClick(); + + + Intent intent = new Intent(AddTest.this, GraphActivity.class); + + + intent.putExtra("key6",acttime); + + startActivity(intent); + T.cancel(); + } + + + + } + }); + } + }, 1000, 1000); + + + + + } + private void countdown(long second) + { + new CountDownTimer(second, 1000) { + + public void onTick(long millisUntilFinished) { + next.setEnabled(true); + acttime=String.valueOf(second); + + //Log.d("LOGGER", "sec: " + millisUntilFinished / 1000); + //Log.d("LOGGER", "sec: " + millisUntilFinished / 1000); + long diffSecondsl = millisUntilFinished / 1000 % 60; + long diffMinutesl = millisUntilFinished / (60 * 1000) % 60; + long diffhourl = millisUntilFinished / (60 *60 * 1000) % 60; + mValueView.setText(diffhourl+"h"+diffMinutesl+"m"+diffSecondsl+"s"); + + int cyclecurrent=(mNPcrC-valuw)+1; + if(cyclecurrent<0) + { + + mCycleView.setText("Finish"); + + } + else { + + mCycleView.setText(String.valueOf(cyclecurrent)); + } + } + + public void onFinish() { + msound.start(); + msound.setLooping(true); + + mValueView.setText("Finish"); + mCycleView.setText("Finish"); + } + }.start(); + + } + private void countDownStart() { + new CountDownTimer(30000, 1000) { + + public void onTick(long millisUntilFinished) { + // Log.d("LOGGER", "seconds remaining: " + millisUntilFinished / 1000); + + mValueView.setText("sec " + millisUntilFinished / 1000); + } + + public void onFinish() { + mValueView.setText("Finish"); + } + }.start(); + + } + + @Override + public void onPointerCaptureChanged(boolean hasCapture) { + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } + private void ValidateProductData() + { + + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(AddTest.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } + else { + StoreProductInformation(); + } + + } + + + + + + + private void StoreProductInformation() + { + loadingBar.setTitle("Add Test"); + loadingBar.setMessage("Please wait while we are adding the Test Details ."); + loadingBar.setCanceledOnTouchOutside(false); + loadingBar.show(); + + Calendar calendar = Calendar.getInstance(); + + SimpleDateFormat currentDate = new SimpleDateFormat("MMM dd, yyyy"); + saveCurrentDate = currentDate.format(calendar.getTime()); + + SimpleDateFormat currentTime = new SimpleDateFormat("HH:mm:ss a"); + saveCurrentTime = currentTime.format(calendar.getTime()); + + TestRandomKey = saveCurrentDate + saveCurrentTime+number; + + + + + + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(AddTest.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } else { + + SaveProductInfoToDatabase(); + } + + + + } + private void SaveProductInfoToDatabase() + { + HashMap productMap = new HashMap<>(); + + + productMap.put("Time", saveCurrentTime); + productMap.put("rev_trans_temp",mLTempValueView.getText().toString()); + productMap.put("rev_trans_time",mLTimeValueView.getText().toString()); + productMap.put("intial_den_temp",mOTempValueView.getText().toString()); + + productMap.put("intial_den_time",mOTimeValueView.getText().toString()); + productMap.put("den_temp",mDTempValueView.getText().toString()); + productMap.put("den_time",mDTimeValueView.getText().toString()); + productMap.put("ann_temp",mATempValueView.getText().toString()); + productMap.put("ann_time",mATimeValueView.getText().toString()); + + productMap.put("ext_temp",mETempValueView.getText().toString()); + productMap.put("ext_time",mETimeValueView.getText().toString()); + + productMap.put("fext_temp",mFETempValueView.getText().toString()); + productMap.put("fext_time",mFETimeValueView.getText().toString()); + productMap.put("no_of_pcr_cycle",mNPcrCView.getText().toString()); +productMap.put("name_protocol",prtocol.getText().toString()); + productMap.put("date_protocol", saveCurrentDate); + + + + + + + + productMap.put("Sample_Date",saveCurrentDate ); + productMap.put("random_key",TestRandomKey); + + + + + TestRef.child(TestRandomKey).updateChildren(productMap) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) + { + if (task.isSuccessful()) { + loadingBar.dismiss(); + Toast.makeText(AddTest.this, "Protocol is added successfully ", Toast.LENGTH_SHORT).show(); + + } + else + { + loadingBar.dismiss(); + String message = task.getException().toString(); + Toast.makeText(AddTest.this, "Error: " + message, Toast.LENGTH_SHORT).show(); + } + } + }); + } + + + + @Override + public void onBackPressed() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setCancelable(false); + builder.setMessage("Do you want to Exit ?"); + + builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + Intent intent = new Intent(AddTest.this, MainActivity.class); + connect.performClick(); + + finish(); + startActivity(intent); + + + + + } + }); + builder.setNegativeButton("No", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } + + + + @Override + protected void onPause() { + super.onPause(); + msound.release(); + } + + + + @Override + public void onResume() { + super.onResume(); + msound=MediaPlayer.create(this,R.raw.notification); + } + + +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/CreatePassword.java b/app/src/main/java/no/spca/android/iisc/SPCA/CreatePassword.java new file mode 100644 index 0000000..d275c5d --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/CreatePassword.java @@ -0,0 +1,110 @@ +package no.spca.android.iisc.SPCA; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.SPCA.Model.RegisterHelper; + + +public class CreatePassword extends AppCompatActivity { + private Button next; + + String name,phonenumber,num1,num2; + private EditText passworddata; + private EditText ConfirmPassword; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create__password); + passworddata=findViewById(R.id.password); + ConfirmPassword=findViewById(R.id.confirmpassword); + next=findViewById(R.id.next); + + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + num1 = ConfirmPassword.getText().toString(); + num2 = passworddata.getText().toString(); + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(CreatePassword.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } else { + + + if (num1.equals(num2)) { + Intent intent = new Intent(CreatePassword.this, LoginScreen.class); + name = getIntent().getStringExtra("username"); + + String phonenumberk = getIntent().getStringExtra("mobile"); + phonenumber = phonenumberk; + + FirebaseDatabase rootNode = FirebaseDatabase.getInstance(); + DatabaseReference reference = rootNode.getReference("USERS"); + RegisterHelper addNewUser = new RegisterHelper(name, phonenumber, num1); + + reference.child(phonenumber).setValue(addNewUser); + intent.putExtra("mobile", phonenumber); + intent.putExtra("username", name); + + Toast.makeText(CreatePassword.this, "You are Registered Successfully ", Toast.LENGTH_SHORT).show(); + startActivity(intent); + + + } else { + ConfirmPassword.setError("Password does not match"); + } + } + } + + }); + + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/CycleManager.java b/app/src/main/java/no/spca/android/iisc/SPCA/CycleManager.java new file mode 100644 index 0000000..9e29383 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/CycleManager.java @@ -0,0 +1,357 @@ + +package no.spca.android.iisc.SPCA; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattService; +import android.content.Context; +import androidx.annotation.NonNull; + +import android.util.Log; + +import java.util.UUID; + +import no.nordicsemi.android.ble.data.Data; +import no.nordicsemi.android.log.LogContract; +import no.spca.android.iisc.battery.BatteryManager; +import no.spca.android.iisc.SPCA.callback.CycleDataCallback; +import no.spca.android.iisc.parser.CycleParser; + +public class CycleManager extends BatteryManager { + + static final UUID SERVICE_UUID = UUID.fromString("00001500-1212-efde-1523-785feabcd123"); private static final UUID TEMP_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001514-1212-efde-1523-785feabcd123"); private static final UUID CLOCK_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001514-1212-efde-1523-785feabcd123"); private static final UUID D_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001504-1212-efde-1523-785feabcd123"); private static final UUID A_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001506-1212-efde-1523-785feabcd123"); private static final UUID E_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001508-1212-efde-1523-785feabcd123"); private static final UUID L_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001515-1212-efde-1523-785feabcd123"); private static final UUID O_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001502-1212-efde-1523-785feabcd123"); private static final UUID S_TEMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001510-1212-efde-1523-785feabcd123"); private static final UUID D_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001505-1212-efde-1523-785feabcd123"); private static final UUID A_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001507-1212-efde-1523-785feabcd123"); private static final UUID E_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001509-1212-efde-1523-785feabcd123"); private static final UUID L_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001516-1212-efde-1523-785feabcd123"); private static final UUID O_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001503-1212-efde-1523-785feabcd123"); private static final UUID S_TIME_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001511-1212-efde-1523-785feabcd123"); private static final UUID N_PCR_C_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001512-1212-efde-1523-785feabcd123"); private static final UUID AMP_WRITABLE_CHARACTERISTIC_UUID = UUID.fromString("00001513-1212-efde-1523-785feabcd123"); private static final UUID OTHER_SERVICE_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb"); private BluetoothGattCharacteristic mReadBlockTempCharacteristic, mSetDTempCharacteristic, mSetDTimeCharacteristic, mSetATempCharacteristic, mSetATimeCharacteristic, mSetETempCharacteristic, mSetETimeCharacteristic, mSetNPcrCCharacteristic, mAmpStartStopCharacteristic, mDeviceNameCharacteristic, mRequiredCharacteristic, mOptionalCharacteristic + ,mReadclockCharacteristic,mSetLTempCharacteristic,mSetOTempCharacteristic,mSetLTimeCharacteristic,mSetOTimeCharacteristic,mSetSTimeCharacteristic, mSetSTempCharacteristic; + + public CycleManager(final Context context) { + super(context); + } + + @NonNull + @Override + protected BatteryManagerGattCallback getGattCallback() { + return mGattCallback; + } + + + private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { + + @Override + protected void initialize() { + super.initialize(); + requestMtu(43)//requestMtu(43) + .with((device, mtu) -> log(LogContract.Log.Level.APPLICATION, "MTU changed to " + mtu)) + .done(device -> { + }) + .fail((device, status) -> log(Log.WARN, "MTU change not supported")) + .enqueue(); + + setNotificationCallback(mReadBlockTempCharacteristic) + .with(new CycleDataCallback() { + @Override + public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + log(LogContract.Log.Level.APPLICATION, CycleParser.parse(data)); + super.onDataReceived(device, data); + } + + @Override + public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) { + mCallbacks.onSampleValueReceived(device, value); + } + + @Override + public void onInvalidDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + log(Log.WARN, "Invalid data received: " + data); + } + }); + + enableNotifications(mReadBlockTempCharacteristic) + .with((device, data) -> log(Log.DEBUG, "Data sent: " + data)) + .done(device -> log(LogContract.Log.Level.APPLICATION, "Notifications enabled successfully")) + .fail((device, status) -> log(Log.WARN, "Failed to enable notifications")) + .enqueue(); + + + } + + + + + + + + + + + + + + + + + + + + @Override + protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { + final BluetoothGattService service = gatt.getService(SERVICE_UUID); + if (service != null) { + mReadBlockTempCharacteristic = service.getCharacteristic(TEMP_READABLE_CHARACTERISTIC_UUID); + mReadclockCharacteristic=service.getCharacteristic(CLOCK_READABLE_CHARACTERISTIC_UUID); + mSetDTempCharacteristic = service.getCharacteristic(D_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetDTimeCharacteristic = service.getCharacteristic(D_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetATempCharacteristic = service.getCharacteristic(A_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetATimeCharacteristic = service.getCharacteristic(A_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetETempCharacteristic = service.getCharacteristic(E_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetETimeCharacteristic = service.getCharacteristic(E_TIME_WRITABLE_CHARACTERISTIC_UUID); + + mSetLTempCharacteristic = service.getCharacteristic(L_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetLTimeCharacteristic = service.getCharacteristic(L_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetOTempCharacteristic = service.getCharacteristic(O_TEMP_WRITABLE_CHARACTERISTIC_UUID); + mSetOTimeCharacteristic = service.getCharacteristic(O_TIME_WRITABLE_CHARACTERISTIC_UUID); +mSetSTimeCharacteristic=service.getCharacteristic(S_TIME_WRITABLE_CHARACTERISTIC_UUID); + mSetSTempCharacteristic=service.getCharacteristic(S_TEMP_WRITABLE_CHARACTERISTIC_UUID); + + + mSetNPcrCCharacteristic = service.getCharacteristic(N_PCR_C_WRITABLE_CHARACTERISTIC_UUID); + + mAmpStartStopCharacteristic = service.getCharacteristic(AMP_WRITABLE_CHARACTERISTIC_UUID); + } + final BluetoothGattService otherService = gatt.getService(OTHER_SERVICE_UUID); + if (otherService != null) { + mDeviceNameCharacteristic = otherService.getCharacteristic(READABLE_CHARACTERISTIC_UUID); + } + + return mReadBlockTempCharacteristic != null && mReadclockCharacteristic != null && mSetDTempCharacteristic != null && mSetDTimeCharacteristic!= null && mSetATempCharacteristic != null && mSetATimeCharacteristic!= null && mSetETempCharacteristic != null && mSetLTempCharacteristic != null && mSetETimeCharacteristic!= null && mSetOTempCharacteristic != null && mSetLTimeCharacteristic!= null && mSetSTimeCharacteristic!= null && mSetSTempCharacteristic!= null && mSetOTimeCharacteristic!= null && mSetNPcrCCharacteristic!= null && mAmpStartStopCharacteristic != null ; + } + + @Override + protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { + super.isOptionalServiceSupported(gatt); + + final BluetoothGattService service = gatt.getService(SERVICE_UUID); + if (service != null) { + mOptionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID); + } + return mOptionalCharacteristic != null; + } + + @Override + protected void onDeviceDisconnected() { + super.onDeviceDisconnected(); + + mRequiredCharacteristic = null; + mDeviceNameCharacteristic = null; + mOptionalCharacteristic = null; + } + + @Override + protected void onDeviceReady() { + super.onDeviceReady(); + + readCharacteristic(mReadBlockTempCharacteristic) + .with((device, data) -> { + if (data.size() > 0) { + final Integer value = data.getIntValue(Data.FORMAT_UINT8, 0); + log(LogContract.Log.Level.APPLICATION, "Value '" + value + "' has been read!"); + } else { + log(Log.WARN, "Value is empty!"); + } + }) + .enqueue(); + readCharacteristic(mReadclockCharacteristic) + .with((device, data) -> { + if (data.size() > 0) { + final Integer value = data.getIntValue(Data.FORMAT_UINT8, 0); + log(LogContract.Log.Level.APPLICATION, "Value '" + value + "' has been read!"); + } else { + log(Log.WARN, "Value is empty!"); + } + }) + .enqueue(); + } + + }; + + + + + + + + + + + + + + + + + + + + //Heating Switch + void heatingSwitch(int state) { + log(Log.WARN, "Write time duration \"" + state + "\""); + //final byte time_in_byte = time_duration.getBytes()[0]; + final byte state_in_byte = (byte) state; + writeCharacteristic(mAmpStartStopCharacteristic, Data.opCode(state_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Heating State")) + .split() + .enqueue(); + + } + + //Set Time + void sendDTime(int d_time) { + log(Log.WARN, "Write D Time Duration \"" + d_time + "\""); + final byte d_time_in_byte = (byte) d_time; + writeCharacteristic(mSetDTimeCharacteristic, Data.opCode(d_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + void sendATime(int a_time) { + log(Log.WARN, "Write A Time Duration \"" + a_time + "\""); + final byte a_time_in_byte = (byte) a_time; + writeCharacteristic(mSetATimeCharacteristic, Data.opCode(a_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + + void sendLTime(int l_time) { + log(Log.WARN, "Write A Time Duration \"" + l_time + "\""); + final byte l_time_in_byte = (byte) l_time; + writeCharacteristic(mSetLTimeCharacteristic, Data.opCode(l_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + void sendOTime(int o_time) { + log(Log.WARN, "Write A Time Duration \"" + o_time + "\""); + final byte a_time_in_byte = (byte) o_time; + writeCharacteristic(mSetOTimeCharacteristic, Data.opCode(a_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + void sendSTime(int s_time) { + log(Log.WARN, "Write A Time Duration \"" + s_time + "\""); + final byte s_time_in_byte = (byte) s_time; + writeCharacteristic(mSetSTimeCharacteristic, Data.opCode(s_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + + + void sendETime(int e_time) { + log(Log.WARN, "Write E Time Duration \"" + e_time + "\""); + final byte e_time_in_byte = (byte) e_time; + writeCharacteristic(mSetETimeCharacteristic, Data.opCode(e_time_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Time")) + .split() + .enqueue(); + } + + + //Set Temp + void sendDTemp(int d_temp) { + log(Log.WARN, "Write D temp \"" + d_temp + "\""); + final byte d_temp_in_byte = (byte) d_temp; + writeCharacteristic(mSetDTempCharacteristic, Data.opCode(d_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + void sendSTemp(int s_temp) { + log(Log.WARN, "Write D temp \"" + s_temp + "\""); + final byte s_temp_in_byte = (byte) s_temp; + writeCharacteristic(mSetSTempCharacteristic, Data.opCode(s_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + + + + + + + + + void sendLTemp(int l_temp) { + log(Log.WARN, "Write D temp \"" + l_temp + "\""); + final byte l_temp_in_byte = (byte) l_temp; + writeCharacteristic(mSetLTempCharacteristic, Data.opCode(l_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + + + void sendOTemp(int o_temp) { + log(Log.WARN, "Write D temp \"" + o_temp + "\""); + final byte d_temp_in_byte = (byte) o_temp; + writeCharacteristic(mSetOTempCharacteristic, Data.opCode(d_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + + + + + + + + + void sendATemp(int a_temp) { + log(Log.WARN, "Write A temp \"" + a_temp + "\""); + final byte a_temp_in_byte = (byte) a_temp; + writeCharacteristic(mSetATempCharacteristic, Data.opCode(a_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + void sendETemp(int e_temp) { + log(Log.WARN, "Write E temp \"" + e_temp + "\""); + final byte e_temp_in_byte = (byte) e_temp; + writeCharacteristic(mSetETempCharacteristic, Data.opCode(e_temp_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + void sendNPcrC(int n_pcr_c) { + log(Log.WARN, "Write E temp \"" + n_pcr_c + "\""); + final byte n_pcr_c_in_byte = (byte) n_pcr_c; + writeCharacteristic(mSetNPcrCCharacteristic, Data.opCode(n_pcr_c_in_byte)) + .with((device, data) -> log(LogContract.Log.Level.APPLICATION, + "\"" + data.size() + "\" Set Temp")) + .split() + .enqueue(); + } + + + +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/CycleService.java b/app/src/main/java/no/spca/android/iisc/SPCA/CycleService.java new file mode 100644 index 0000000..2ab0a26 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/CycleService.java @@ -0,0 +1,209 @@ + + +package no.spca.android.iisc.SPCA; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import no.nordicsemi.android.log.Logger; +import no.spca.android.iisc.FeaturesActivity; +import no.spca.android.iisc.R; +import no.spca.android.iisc.NotificationData; +import no.spca.android.iisc.profile.BleProfileService; +import no.spca.android.iisc.profile.LoggableBleManager; + +public class CycleService extends BleProfileService implements SPCAManagerCallbacks { + public static final String BROADCAST_TEMPLATE_MEASUREMENT = "no.spca.android.iisc.template.BROADCAST_MEASUREMENT"; + + public static final String EXTRA_DATA = "no.spca.android.iisc.template.EXTRA_DATA"; + + public static final String BROADCAST_BATTERY_LEVEL = "no.spca.android.iisc.BROADCAST_BATTERY_LEVEL"; + public static final String EXTRA_BATTERY_LEVEL = "no.spca.android.iisc.EXTRA_BATTERY_LEVEL"; + + private final static String ACTION_DISCONNECT = "no.spca.android.iisc.template.ACTION_DISCONNECT"; + + private final static int NOTIFICATION_ID = 864; + private final static int OPEN_ACTIVITY_REQ = 0; + private final static int DISCONNECT_REQ = 1; + + private CycleManager mManager; + + private final LocalBinder mBinder = new TemplateBinder(); + + class TemplateBinder extends LocalBinder { + + + public void heatingSwitch(int state){ + mManager.heatingSwitch(state); + } + public void sendDTemp(int d_temp) { + mManager.sendDTemp(d_temp); + } + public void sendATemp(int a_temp) { + mManager.sendATemp(a_temp); + } + public void sendETemp(int e_temp) { + mManager.sendETemp(e_temp); + } + + public void sendSTemp(int s_temp) { + mManager.sendSTemp(s_temp); + } + + + + public void sendLTemp(int l_temp) { + mManager.sendLTemp(l_temp); + } + public void sendOTemp(int o_temp) { + mManager.sendOTemp(o_temp); + } + + + + + public void sendDTime(int d_time) { + mManager.sendDTime(d_time); + } + public void sendATime(int a_time) { + mManager.sendATime(a_time); + } + public void sendETime(int e_time) { + mManager.sendETime(e_time); + } + + + + + + + + + public void sendSTime(int s_time) { + mManager.sendSTime(s_time); + } + + public void sendLTime(int l_time) { + mManager.sendLTime(l_time); + } + public void sendOTime(int o_time) { mManager.sendOTime(o_time); } + + + public void sendNPcrN(int n_pcr_c) { + mManager.sendNPcrC(n_pcr_c); + } + + } + + @Override + protected LocalBinder getBinder() { + return mBinder; + } + + @Override + protected LoggableBleManager initializeManager() { + return mManager = new CycleManager(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DISCONNECT); + registerReceiver(mDisconnectActionBroadcastReceiver, filter); + } + + @Override + public void onDestroy() { + cancelNotification(); + unregisterReceiver(mDisconnectActionBroadcastReceiver); + + super.onDestroy(); + } + + @Override + protected void onRebind() { + cancelNotification(); + } + + @Override + protected void onUnbind() { + createNotification(R.string.template_notification_connected_message, 0); + } + + @Override + public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) { + final Intent broadcast = new Intent(BROADCAST_TEMPLATE_MEASUREMENT); + broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); + broadcast.putExtra(EXTRA_DATA, value); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + if (!mBound) { + } + } + + + + + + + + + + + + + + + + + @Override + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { + + } + + + 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, AddTest.class); + + final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT); + final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationData.CONNECTED_DEVICE_CHANNEL); + builder.setContentIntent(pendingIntent); + builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); + builder.setSmallIcon(R.drawable.ic_stat_notify_template); + builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); + final Notification notification = builder.build(); + final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID, notification); + } + + + private void cancelNotification() { + final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + nm.cancel(NOTIFICATION_ID); + } + + + private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + Logger.i(getLogSession(), "[Notification] Disconnect action pressed"); + if (isConnected()) + getBinder().disconnect(); + else + stopSelf(); + } + }; +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/Datashow.java b/app/src/main/java/no/spca/android/iisc/SPCA/Datashow.java new file mode 100644 index 0000000..0b7d77f --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/Datashow.java @@ -0,0 +1,648 @@ + +package no.spca.android.iisc.SPCA; + +import android.app.ProgressDialog; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import android.os.CountDownTimer; +import android.os.Handler; +import android.util.Log; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Switch; +import android.widget.TextView; + + +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.ValueEventListener; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.SPCA.Model.Tests; +import no.spca.android.iisc.profile.BleProfileService; +import no.spca.android.iisc.profile.BleProfileServiceReadyActivity; + + + +public class Datashow extends BleProfileServiceReadyActivity { + @SuppressWarnings("unused") + private final String TAG = "AddTest"; + + private TextView mValueView; + private EditText mFETempValueView; + private EditText mFETimeValueView; + private String TestID = ""; + + private TextView mCycleView; + private ProgressDialog loadingBar; + private String number; + + + private DatabaseReference TestRef; + + private TextView mHeatingStatusView; + private int seconds1 ,seconds2; + private Switch mHeatingState ; + + private EditText mDTimeValueView; + private Integer mDSetTime ; + private EditText mLTimeValueView; + private Integer mLSetTime ; + private EditText mOTimeValueView; + private Integer mOSetTime ; + private String time1,time2,time3; + private Date date1,date2,date3; + + + + private final int valuedata=0; + private final int j=0; + private final Handler handler = new Handler(); + private Runnable runnable; + + + private EditText mATimeValueView; + private Integer mASetTime ; + private EditText mETimeValueView; + private Integer mESetTime ; + + private EditText mDTempValueView; + private Integer mDSetTemp ; + private EditText mATempValueView; + private Button save; + private Integer mASetTemp ; + private EditText mETempValueView; + private Integer mESetTemp ; + private EditText protocol_Name; + + + private EditText mLTempValueView; + private Integer mLSetTemp ; + private EditText mOTempValueView; + private Integer mOSetTemp ; + private long diff=0; + private long diffSeconds=0; + private long diffMinutes=0; + private long diffHours=0; + private long diff1=0; + private long diffSeconds1=0; + private long diffMinutes1=0; + + private long diffHours1=0; + private int FLAG=0; + + + private int count=0; + private int valuw=0; + + int i=0; + + private EditText mNPcrCView; + private Integer mNPcrC ; + private Timer T; + + + + @Override + protected void onCreateView(final Bundle savedInstanceState) { + setContentView(R.layout.activity_protocol); + loadingBar = new ProgressDialog(this); + + + setGUI(); + TestID = getIntent().getStringExtra("pid"); + + Log.e("main", "error id "+TestID); + getTestDetails(TestID); + + + + + + } + + private void setGUI() { + mValueView = findViewById(R.id.Temp_Value); + mCycleView = findViewById(R.id.RemTime_Value); +save=findViewById(R.id.action_save); + mFETempValueView=findViewById(R.id.S_Temp_Set); + mFETimeValueView=findViewById(R.id.S_Time_Set); + protocol_Name=findViewById(R.id.protocol_name); + + mDTempValueView = findViewById(R.id.D_Temp_Set); + mDTimeValueView = findViewById(R.id.D_Time_Set); + mATempValueView = findViewById(R.id.A_Temp_Set); + mATimeValueView = findViewById(R.id.A_Time_Set); + mETempValueView = findViewById(R.id.E_Temp_Set); + mETimeValueView = findViewById(R.id.E_Time_Set); + mLTempValueView=findViewById(R.id.L_Temp_Set); + mOTempValueView=findViewById(R.id.O_Temp_Set); + mLTimeValueView = findViewById(R.id.L_Time_Set); + + mOTimeValueView = findViewById(R.id.O_Time_Set); + + + + T=new Timer(); + + + SharedPreferences preferences689 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences689.getString("Phone", null); + + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + mNPcrCView = findViewById(R.id.N_Pcr_C); + + + mHeatingState = findViewById(R.id.heating_state); + mHeatingStatusView= findViewById(R.id.heating_status_text); + + mHeatingState.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + startCounter(); + + + i=1; + if(date2 !=null && date1 !=null) { + SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + try { + date1 = format.parse(time1); + date2 = format.parse(time2); + diff = (date2.getTime() - date1.getTime()); + diffSeconds = diff / 1000 % 60; + diffMinutes = diff / (60 * 1000) % 60; + diffHours = diff / (60 * 60 * 1000); + + + + } catch (ParseException e) { + e.printStackTrace(); + } + + + } + + Log.e("main", "error data inside " + valuedata); + + getService().heatingSwitch(1); + + mDSetTemp = Integer.parseInt(mDTempValueView.getText().toString()); + getService().sendDTemp(mDSetTemp); + + mDSetTime = Integer.parseInt(mDTimeValueView.getText().toString()); + getService().sendDTime(mDSetTime); + + mLSetTemp = Integer.parseInt(mLTempValueView.getText().toString()); + getService().sendLTemp(mLSetTemp); + mLSetTime = Integer.parseInt(mLTimeValueView.getText().toString()); + getService().sendLTime(mLSetTime); + + mOSetTemp = Integer.parseInt(mOTempValueView.getText().toString()); + getService().sendOTemp(mOSetTemp); + mOSetTime = Integer.parseInt(mOTimeValueView.getText().toString()); + getService().sendOTime(mOSetTime); + + + mASetTemp = Integer.parseInt(mATempValueView.getText().toString()); + getService().sendATemp(mASetTemp); + mASetTime = Integer.parseInt(mATimeValueView.getText().toString()); + getService().sendATime(mASetTime); + + mESetTemp = Integer.parseInt(mETempValueView.getText().toString()); + getService().sendETemp(mESetTemp); + mESetTime = Integer.parseInt(mETimeValueView.getText().toString()); + getService().sendETime(mESetTime); + + mNPcrC = Integer.parseInt(mNPcrCView.getText().toString()); + getService().sendNPcrN(mNPcrC); + Log.e("main", "error 34" + mDSetTemp); + + Log.e("main", "error 2 " + mDSetTemp); + Log.e("main", "error data box " + valuedata); + + + + + + } + else { + getService().heatingSwitch(0); + } + mHeatingStatusView.setText(isChecked ? R.string.Heating_block_on : R.string.Heating_block_off); + }); + + + + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + @Override + protected void setDefaultUI() { + mValueView.setText("wait"); + mCycleView.setText("wait"); + + + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.template_feature_title; + } + + + + @Override + protected int getDefaultDeviceName() { + return R.string.template_default_name; + } + + @Override + protected UUID getFilterUUID() { + return CycleManager.SERVICE_UUID; + } + + @Override + protected Class getServiceClass() { + return CycleService.class; + } + + @Override + protected void onServiceBound(final CycleService.TemplateBinder binder) { + } + + @Override + protected void onServiceUnbound() { + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + } + + @Override + public void onDeviceDisconnected(final BluetoothDevice device) { + super.onDeviceDisconnected(device); + } + + @SuppressWarnings("unused") + private void setValueOnView(@NonNull final BluetoothDevice device, int value) { + } + + + + + + + + + + + + + + + + + + @SuppressWarnings("unused") + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { + + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + final BluetoothDevice device = intent.getParcelableExtra(no.spca.android.iisc.SPCA.CycleService.EXTRA_DEVICE); + + if (no.spca.android.iisc.SPCA.CycleService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) { + int value = intent.getIntExtra(no.spca.android.iisc.SPCA.CycleService.EXTRA_DATA, 0); + setValueOnView(device, value); + valuw=value; + if(value==0) + { + DateFormat df = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + time1 = df.format(Calendar.getInstance().getTime()); + + + Log.e("main", "error 403 " +time1); + + + + + + } + + else if(value ==1 ) + { + DateFormat df = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + time2 = df.format(Calendar.getInstance().getTime()); + + + Log.e("main", "error 404 " +time2); + LocalDateTime date = LocalDateTime.now(); + seconds1 = date.toLocalTime().toSecondOfDay(); + + + } + else if(value ==2 ) + { + DateFormat df = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + time3 = df.format(Calendar.getInstance().getTime()); + + try { + date1 = df.parse(time1); + date2 = df.parse(time2); + date3=df.parse(time3); + + } catch (ParseException e) { + e.printStackTrace(); + } + Log.e("main", "date 1 " + date2.getTime()); + Log.e("main", "date 2 " + date1.getTime()); + + + diff1 = date3.getTime() - date2.getTime(); + Log.e("main", "difference minute " + diffMinutes); + + + Log.e("main", "difference minute " + diffMinutes); + + diffSeconds1 = diff1 / 1000 % 60; + diffMinutes1 = diff1 / (60 * 1000) % 60; + diffHours1 = diff1/ (60 * 60 * 1000); + Log.e("main", "date difference " + diffMinutes1); + + + + Log.e("main", "error 404 " +time2); + + + + } + + if(time1 !=null && time2 !=null &&diffSeconds1==1 ) { + + SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + try { + date1 = format.parse(time1); + date2 = format.parse(time2); + Log.e("main", "date 1 " + date2.getTime()); + Log.e("main", "date 2 " + date1.getTime()); + + + diff = date2.getTime() - date1.getTime(); + Log.e("main", "difference minute " + diffMinutes); + + diffSeconds = diff / 1000 % 60; + diffMinutes = diff / (60 * 1000) % 60; + diffHours = diff / (60 * 60 * 1000); + Log.e("main", "date difference " + diffMinutes); + FLAG=1; + + + + } catch (ParseException e) { + e.printStackTrace(); + } + + + } + else + { + } + + + } else if (no.spca.android.iisc.SPCA.CycleService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int batteryLevel = intent.getIntExtra(no.spca.android.iisc.SPCA.CycleService.EXTRA_BATTERY_LEVEL, 0); + onBatteryLevelChanged(device, batteryLevel); + } + + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(no.spca.android.iisc.SPCA.CycleService.BROADCAST_TEMPLATE_MEASUREMENT); + intentFilter.addAction(no.spca.android.iisc.SPCA.CycleService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } + private void startCounter1() + { + T.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + runOnUiThread(new Runnable() { + @Override + public void run() { + + count++; + Log.e("main", "Currnet " + count); + + } + }); + } + }, 10000, 10000); + + + } + + private void startCounter() + + { + + + + T.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + runOnUiThread(new Runnable() { + @Override + public void run() { + if(FLAG==1) + { + mNPcrC=mNPcrC-1; + long cycle=mNPcrC.longValue(); + countdown(diff *cycle); + + T.cancel(); + } + + + + } + }); + } + }, 1000, 1000); + + + + + } + private void countdown(long second) + { + new CountDownTimer(second, 1000) { + + public void onTick(long millisUntilFinished) { + + long diffSecondsl = millisUntilFinished / 1000 % 60; + long diffMinutesl = millisUntilFinished / (60 * 1000) % 60; + long diffhourl = millisUntilFinished / (60 *60 * 1000) % 60; + mValueView.setText(diffhourl+"h"+diffMinutesl+"m"+diffSecondsl+"s"); + int cyclecurrent=(mNPcrC-valuw)+1; + if(cyclecurrent<0) + { + mCycleView.setText("Finish"); + + } + else { + + mCycleView.setText(String.valueOf(cyclecurrent)); + } + } + + public void onFinish() { + mValueView.setText("Finish"); + mCycleView.setText("Finish"); + } + }.start(); + + } + + + @Override + public void onPointerCaptureChanged(boolean hasCapture) { + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } + + + + + +private void getTestDetails(String TestID) + { + DatabaseReference productsRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + + productsRef.child(TestID).addValueEventListener(new ValueEventListener() { +@Override +public void onDataChange(DataSnapshot dataSnapshot) + { + if (dataSnapshot.exists()) + { + + + Tests products = dataSnapshot.getValue(Tests.class); + + + mLTempValueView.setText(products.getRev_trans_temp()); + + mLTimeValueView.setText(products.getRev_trans_time()); + + mOTempValueView.setText(products.getIntial_den_temp()); + + mOTimeValueView.setText(products.getIntial_den_time()); + + mDTempValueView.setText(products.getDen_temp()); + + + mDTimeValueView.setText(products.getDen_time()); + + + mATempValueView.setText(products.getAnn_temp()); +protocol_Name.setText(products.getName_protocol()); + + + + mATimeValueView.setText(products.getAnn_time()); + + + + mETempValueView.setText(products.getExt_temp()); + + mETimeValueView.setText(products.getExt_time()); + + mFETempValueView.setText(products.getFext_temp()); + + mFETimeValueView.setText(products.getFext_time()); + + + mNPcrCView.setText(products.getNo_of_pcr_cycle()); + + + + + + + + + + + + mLTempValueView.setText(products.getRev_trans_temp()); + + mLTimeValueView.setText(products.getRev_trans_time()); + mATempValueView.setText(products.getAnn_temp()); + mATimeValueView.setText(products.getAnn_time()); + mDTempValueView.setText(products.getDen_temp()); + mDTimeValueView.setText(products.getDen_time()); + + + } + } + +@Override +public void onCancelled(DatabaseError databaseError) { + + } + }); + } + + } + + + + + + + diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/FontAwesome.java b/app/src/main/java/no/spca/android/iisc/SPCA/FontAwesome.java new file mode 100644 index 0000000..d618508 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/FontAwesome.java @@ -0,0 +1,35 @@ +package no.spca.android.iisc.SPCA; + + +import android.content.Context; +import android.graphics.Typeface; +import android.util.AttributeSet; + +import androidx.appcompat.widget.AppCompatTextView; + +public class FontAwesome extends AppCompatTextView { + + + public FontAwesome(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(); + } + + public FontAwesome(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + public FontAwesome(Context context) { + super(context); + init(); + } + + private void init() { + + Typeface tf = Typeface.createFromAsset(getContext().getAssets(), + "fa-solid-900.ttf"); + setTypeface(tf); + } + +} \ No newline at end of file diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/ForgetPassword.java b/app/src/main/java/no/spca/android/iisc/SPCA/ForgetPassword.java new file mode 100644 index 0000000..637240c --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/ForgetPassword.java @@ -0,0 +1,242 @@ +package no.spca.android.iisc.SPCA; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.chaos.view.PinView; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.android.gms.tasks.TaskExecutors; +import com.google.firebase.FirebaseException; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.PhoneAuthCredential; +import com.google.firebase.auth.PhoneAuthProvider; +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; +import com.google.firebase.database.ValueEventListener; +import com.hbb20.CountryCodePicker; + +import java.util.concurrent.TimeUnit; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.SPCA.VerifyOTP.VerifyOtpForgetPassword; + + +public class ForgetPassword extends AppCompatActivity { + + private String verificationid; + private FirebaseAuth mAuth; + private final int code = 91; + private Button nextactivity; + private ProgressBar progressBar; + CountryCodePicker ccp; + PinView pinFromUser; + String mobile; + private EditText editTextnumber; + boolean exists; + String phonenum; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_forget__password); + editTextnumber=findViewById(R.id.editTextMobile); + ccp=findViewById(R.id.ccp); + ccp.registerCarrierNumberEditText(editTextnumber); + mAuth = FirebaseAuth.getInstance(); + + + findViewById(R.id.buttonSignIn).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(ForgetPassword.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } else { + + mobile = editTextnumber.getText().toString().trim(); + mobile = mobile.replaceAll("[^0-9]", ""); + + + phonenum = ccp.getFullNumberWithPlus(); + if(mobile.equals("")) + { + editTextnumber.setError("Enter the contact number"); + } + + + Query chekuser = FirebaseDatabase.getInstance().getReference("USERS").orderByChild("number").equalTo(mobile); + chekuser.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + if (dataSnapshot.exists()) { + Intent intent = new Intent(ForgetPassword.this, VerifyOtpForgetPassword.class); + Toast.makeText(ForgetPassword.this, "We Have Sent the OTP to your mentioned Number", Toast.LENGTH_SHORT).show(); + intent.putExtra("mobilecode", phonenum); + intent.putExtra("mobile", mobile); + + startActivity(intent); + + + } else { + editTextnumber.setError("No Such User Exists"); + + } + + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + Log.e("Raman", "Received an exception check chexk " + databaseError.getMessage()); + + } + }); + + + } + } + + }); + + } + private void verifyCode(String code){ + PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationid, code); + signInWithCredential(credential); + } + + private void signInWithCredential(PhoneAuthCredential credential) { + mAuth.signInWithCredential(credential) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + + Intent intent = new Intent(ForgetPassword.this, ForgetPasswordReset.class); + intent.putExtra("mobile", mobile); + + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + + + startActivity(intent); + + } else { + Toast.makeText(ForgetPassword.this, task.getException().getMessage(), Toast.LENGTH_LONG).show(); + } + } + + }); + } + + private void sendVerificationCode(String number){ + + PhoneAuthProvider.getInstance().verifyPhoneNumber( + number, + 60, + TimeUnit.SECONDS, + (Activity) TaskExecutors.MAIN_THREAD, + mCallBack + ); + } + + private final PhoneAuthProvider.OnVerificationStateChangedCallbacks + mCallBack = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { + + @Override + public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) { + super.onCodeSent(s, forceResendingToken); + verificationid = s; + } + + @Override + public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) { + String code = phoneAuthCredential.getSmsCode(); + if (code != null){ + progressBar.setVisibility(View.VISIBLE); + pinFromUser.setText(code); + verifyCode(code); + } + } + + @Override + public void onVerificationFailed(FirebaseException e) { + Toast.makeText(ForgetPassword.this, e.getMessage(), Toast.LENGTH_LONG).show(); + + } + }; + + + + + private void checkuserexist(String number) + { + Query chekuser= FirebaseDatabase.getInstance().getReference("USERS").orderByChild("number").equalTo(number); + chekuser.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + exists= dataSnapshot.exists(); + + + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + Toast.makeText(ForgetPassword.this,databaseError.getMessage(), Toast.LENGTH_SHORT).show(); + + } + }); + + + + + + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } + +} \ No newline at end of file diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/ForgetPasswordReset.java b/app/src/main/java/no/spca/android/iisc/SPCA/ForgetPasswordReset.java new file mode 100644 index 0000000..976f8cb --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/ForgetPasswordReset.java @@ -0,0 +1,69 @@ +package no.spca.android.iisc.SPCA; + + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; + +import no.spca.android.iisc.R; + +public class ForgetPasswordReset extends AppCompatActivity { + private Button next; + + String phonenumber,num1,num2; + private EditText passworddata; + private EditText ConfirmPassword; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_create__password); + passworddata=findViewById(R.id.password); + ConfirmPassword=findViewById(R.id.confirmpassword); + next=findViewById(R.id.next); + + + + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + num1 = ConfirmPassword.getText().toString(); + num2=passworddata.getText().toString(); + if(num1.equals(num2)) { + + Intent intent = new Intent(ForgetPasswordReset.this, LoginScreen.class); + + String phonenumberk = getIntent().getStringExtra("mobile"); + phonenumber = phonenumberk; + + FirebaseDatabase rootNode = FirebaseDatabase.getInstance(); + DatabaseReference reference = rootNode.getReference("USERS"); + + + reference.child(phonenumber).child("password").setValue(num1); + Toast.makeText(ForgetPasswordReset.this, "Password Reset Successfully ", Toast.LENGTH_SHORT).show(); + startActivity(intent); + + } + else + { + ConfirmPassword.setError("Password does not match"); + } + } + }); + + + } +} + diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/GraphActivity.java b/app/src/main/java/no/spca/android/iisc/SPCA/GraphActivity.java new file mode 100644 index 0000000..08a4757 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/GraphActivity.java @@ -0,0 +1,488 @@ + +package no.spca.android.iisc.SPCA; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.hardware.Sensor; +import android.hardware.SensorManager; +import android.media.MediaPlayer; +import android.os.Bundle; + +import com.github.mikephil.charting.charts.LineChart; + + +import android.graphics.Color; +import android.util.Log; + + +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.os.CountDownTimer; +import android.os.Handler; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import com.github.mikephil.charting.components.Legend; +import com.github.mikephil.charting.components.XAxis; +import com.github.mikephil.charting.components.YAxis; +import com.github.mikephil.charting.data.Entry; +import com.github.mikephil.charting.data.LineData; +import com.github.mikephil.charting.data.LineDataSet; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.profile.BleProfileService; +import no.spca.android.iisc.profile.BleProfileServiceReadyActivity; + + + +public class GraphActivity extends BleProfileServiceReadyActivity { + @SuppressWarnings("unused") + private final String TAG = "AddTest"; + + private TextView mValueView; + private TextView mCycleView; + private ProgressDialog loadingBar; + + private Button save; + private String TestRandomKey, saveCurrentDate, saveCurrentTime,number; + + + + private LineChart mChart; + private Thread thread; + private final boolean plotData = true; + File filePath3 = null; + private DatabaseReference TestRef; + + + + + private TextView mHeatingStatusView; + private int seconds1 ,seconds2; + private Switch mHeatingState ; + + + + + private final Handler handler = new Handler(); + private Runnable runnable; + + + + + MediaPlayer msound; + + long l; + + + private int count=0; + private final int valuw=0; + + int i=0; + + private EditText mNPcrCView; + private Integer mNPcrC ; + private Timer T; + private Button connect ; + private Date currentf,currentTime; +String tim; + + + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + protected void onCreateView(final Bundle savedInstanceState) { + setContentView(R.layout.activity_graph); + String value1 = getIntent().getExtras().getString("key6"); + Log.e("time", "time " + value1); + Toast.makeText(GraphActivity.this, "Please Connect to Bluetooth to check Temp Graph", Toast.LENGTH_SHORT).show(); + + msound= MediaPlayer.create(GraphActivity.this,R.raw.notification); + + + + connect = findViewById(R.id.action_connect); + + loadingBar = new ProgressDialog(this); + + setGUI(); + Log.e("time", "time " + tim); + + l=Long.parseLong(String.valueOf(value1)); + Log.e("time", "time " + l); + + startCounter(); + + + + + + mChart = (LineChart) findViewById(R.id.chart1); + + mChart.setDescription(""); + mChart.setNoDataText("No data for the moment "); + + mChart.setTouchEnabled(true); + mChart.setDefaultFocusHighlightEnabled(true); + mChart.setHighlightEnabled(true); + mChart.setDragEnabled(true); + mChart.setScaleEnabled(true); + mChart.setDrawGridBackground(false); + + mChart.setPinchZoom(true); + + mChart.setBackgroundColor(Color.WHITE); + + LineData data = new LineData(); + data.setValueTextColor(Color.BLACK); + + mChart.setData(data); + + Legend l = mChart.getLegend(); + + l.setForm(Legend.LegendForm.LINE); + l.setTextColor(Color.BLACK); + + XAxis xl = mChart.getXAxis(); + xl.setTextColor(Color.BLACK); + xl.setDrawGridLines(false); + xl.setAvoidFirstLastClipping(true); + YAxis yl = mChart.getAxisLeft(); + yl.setTextColor(Color.BLACK); + yl.setDrawGridLines(true); + yl.setAxisMaxValue(100f); + + YAxis yl2 = mChart.getAxisRight(); + yl2.setEnabled(false); + + + + + + + + + + + + + + + + + + + + + } + + private void setGUI() { + mValueView = findViewById(R.id.Temp_Value); + mCycleView = findViewById(R.id.RemTime_Value); + + T=new Timer(); + + + SharedPreferences preferences689 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences689.getString("Phone", null); + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + mNPcrCView = findViewById(R.id.N_Pcr_C); + mHeatingState = findViewById(R.id.heating_state); + mHeatingStatusView= findViewById(R.id.heating_status_text); + //mValueView.setText("fff"); + + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + + } + + + @Override + protected void onDestroy() { + super.onDestroy(); + + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + @Override + protected void setDefaultUI() { + mValueView.setText("wait"); + mCycleView.setText("wait"); + + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.template_feature_title; + } + + + + @Override + protected int getDefaultDeviceName() { + return R.string.template_default_name; + } + + @Override + protected UUID getFilterUUID() { + return TemperatureManager.SERVICE_UUID; + } + + @Override + protected Class getServiceClass() { + return TemperatureService.class; + } + + @Override + protected void onServiceBound(final TemperatureService.TemplateBinder binder) { + } + + @Override + protected void onServiceUnbound() { + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + } + + @Override + public void onDeviceDisconnected(final BluetoothDevice device) { + super.onDeviceDisconnected(device); + } + + @SuppressWarnings("unused") + private void setValueOnView(@NonNull final BluetoothDevice device, int value) { + } + + + + @SuppressWarnings("unused") + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { + + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + final BluetoothDevice device = intent.getParcelableExtra(TemperatureService.EXTRA_DEVICE); + + if (TemperatureService.BROADCAST_TEMPLATE_MEASUREMENT1.equals(action)) { + int value = intent.getIntExtra(TemperatureService.EXTRA_DATA1, 0); + addEntry(Float.parseFloat(String.valueOf(value))); + mCycleView.setText(String.valueOf(value)); + + + + + } else if (TemperatureService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int batteryLevel = intent.getIntExtra(TemperatureService.EXTRA_BATTERY_LEVEL, 0); + onBatteryLevelChanged(device, batteryLevel); + } + + } + }; + + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(TemperatureService.BROADCAST_TEMPLATE_MEASUREMENT1); + intentFilter.addAction(TemperatureService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } + private static IntentFilter makeIntentFilter1() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(TemperatureService.BROADCAST_TEMPLATE_MEASUREMENT1); + intentFilter.addAction(TemperatureService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } + + + + + private void startCounter() + + { + + + + T.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + runOnUiThread(new Runnable() { + @Override + public void run() { + + + countdown(l); + + T.cancel(); + + + + + } + }); + } + }, 1000, 1000); + + + + + } + private void countdown(long second) + { + new CountDownTimer(second, 1000) { + + public void onTick(long millisUntilFinished) { + //Log.d("LOGGER", "sec: " + millisUntilFinished / 1000); + //Log.d("LOGGER", "sec: " + millisUntilFinished / 1000); + long diffSecondsl = millisUntilFinished / 1000 % 60; + long diffMinutesl = millisUntilFinished / (60 * 1000) % 60; + long diffhourl = millisUntilFinished / (60 *60 * 1000) % 60; + + mValueView.setText(diffhourl+"h"+diffMinutesl+"m"+diffSecondsl+"s"); + + + + } + + public void onFinish() { + msound.start(); + msound.setLooping(true); + + mValueView.setText("Finish"); + mCycleView.setText("Finish"); + } + }.start(); + + } + + + @Override + public void onPointerCaptureChanged(boolean hasCapture) { + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } + + + + + private void addEntry(float value) + + { + LineData data=mChart.getData(); + if(data!=null) + { + LineDataSet set=data.getDataSetByIndex(0); + if (set == null) { + set = createSet(); + data.addDataSet(set); + } + data.addXValue(""); + data.addEntry(new Entry((float) value , + set.getEntryCount()), + 0); + mChart.notifyDataSetChanged(); + mChart.setVisibleXRange(6); + mChart.moveViewToX(data.getXValCount()-7); + } + + } + + + + private LineDataSet createSet() { + + LineDataSet set = new LineDataSet(null, "SPL Db"); + set.setDrawCubic(true); + set.setCubicIntensity(0.2f); + + set.setAxisDependency(YAxis.AxisDependency.LEFT); + set.setLineWidth(2f); + set.setColor(Color.BLUE); + set.setCircleColor(Color.BLUE); + set.setCircleSize(4f); + set.setFillAlpha(100); + set.setFillColor(Color.BLUE); + set.setHighLightColor(Color.rgb(244,117,177)); + set.setValueTextColor(Color.BLACK); + set.setValueTextSize(10f); + + + return set; + } + + + + @Override + public void onBackPressed() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setCancelable(false); + builder.setMessage("Do you want to Exit ?"); + + builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + Intent intent = new Intent(GraphActivity.this, MainActivity.class); + connect.performClick(); + finish(); + startActivity(intent); + + + + + } + }); + builder.setNegativeButton("No", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } + @Override + protected void onPause() { + super.onPause(); + msound.release(); + } +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/Interface/ItemClickListner.java b/app/src/main/java/no/spca/android/iisc/SPCA/Interface/ItemClickListner.java new file mode 100644 index 0000000..66abb07 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/Interface/ItemClickListner.java @@ -0,0 +1,9 @@ +package no.spca.android.iisc.SPCA.Interface; + + +import android.view.View; + +public interface ItemClickListner +{ + void onClick(View view, int position, boolean isLongClick); +} \ No newline at end of file diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/LoginScreen.java b/app/src/main/java/no/spca/android/iisc/SPCA/LoginScreen.java new file mode 100644 index 0000000..54d34f8 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/LoginScreen.java @@ -0,0 +1,215 @@ +package no.spca.android.iisc.SPCA; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.text.method.HideReturnsTransformationMethod; +import android.text.method.PasswordTransformationMethod; +import android.util.Patterns; +import android.view.View; +import android.view.animation.Animation; +import android.widget.Button; +import android.widget.CompoundButton; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.AppCompatCheckBox; + +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; +import com.google.firebase.database.ValueEventListener; + +import no.spca.android.iisc.R; + + +public class LoginScreen extends AppCompatActivity { + + private TextView createaccount, forgetpassword; + private Button login; + private DatabaseReference databaseReference; + private EditText phonenumber, password; + String passworddata, phonenum, phonenumbers, name; + private ProgressDialog loadingBar; + public static final String Name = "nameKey"; + public static final String Phone = "phoneKey"; + + private AppCompatCheckBox checkbox; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_login__screen); + createaccount = findViewById(R.id.createaccount); + phonenumber = findViewById(R.id.contactnumber); + checkbox = (AppCompatCheckBox) findViewById(R.id.showpassword); + + password = findViewById(R.id.password); + checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) { + if (isChecked) { + password.setTransformationMethod(HideReturnsTransformationMethod.getInstance()); + } else { + password.setTransformationMethod(PasswordTransformationMethod.getInstance()); + } + } + }); + + loadingBar = new ProgressDialog(this); + + login = findViewById(R.id.login); + forgetpassword = findViewById(R.id.forgetpassword); + forgetpassword.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(LoginScreen.this, ForgetPassword.class); + startActivity(intent); + + } + }); + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(LoginScreen.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + //Builder Retry Button + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } else { + String mobile = phonenumber.getText().toString().trim(); + phonenum = mobile; + final String passwordj = password.getText().toString().trim(); + + + if (mobile.equals("") || passwordj.equals("")) { + Toast.makeText(LoginScreen.this, "Please enter all the required fields", Toast.LENGTH_SHORT).show(); + + } else if (!Patterns.PHONE.matcher(mobile).matches()) { + + phonenumber.setError("Enter a valid number"); + + } else { + loadingBar.setTitle("Login Account"); + loadingBar.setMessage("Please wait, while we are checking the credentials."); + loadingBar.setCanceledOnTouchOutside(false); + loadingBar.show(); + + Query chekuser = FirebaseDatabase.getInstance().getReference("USERS").orderByChild("number").equalTo(phonenum); + chekuser.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + if (dataSnapshot.exists()) { + String systempassword = dataSnapshot.child(phonenum).child("password").getValue(String.class); + + if (systempassword.equals(passwordj)) { + + Toast.makeText(LoginScreen.this, "logged in Successfully...", Toast.LENGTH_SHORT).show(); + loadingBar.dismiss(); + String name = dataSnapshot.child(phonenum).child("name").getValue(String.class); + + + SharedPreferences preferences = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + editor.putString("Phone", phonenum); + editor.putString("Name", name); + + + editor.commit(); + + + Intent intent = new Intent(LoginScreen.this, MainActivity.class); + + + intent.putExtra("mobile", phonenum); + + startActivity(intent); + + } else { + loadingBar.dismiss(); + + Toast.makeText(LoginScreen.this, "Wrong Password", Toast.LENGTH_SHORT).show(); + } + } else { + loadingBar.dismiss(); + + Toast.makeText(LoginScreen.this, "No such user exists", Toast.LENGTH_SHORT).show(); + } + + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + Toast.makeText(LoginScreen.this, databaseError.getMessage(), Toast.LENGTH_SHORT).show(); + + } + }); + + + } + } + } + }); + createaccount.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(LoginScreen.this, Register.class); + startActivity(intent); + } + }); + } + + + @Override + public void onBackPressed() { + + finishAffinity(); + finish(); + } + + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } + + + + + +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/MainActivity.java b/app/src/main/java/no/spca/android/iisc/SPCA/MainActivity.java new file mode 100644 index 0000000..e745b14 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/MainActivity.java @@ -0,0 +1,220 @@ +package no.spca.android.iisc.SPCA; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.util.DisplayMetrics; +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.SearchView; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.firebase.ui.database.FirebaseRecyclerAdapter; +import com.firebase.ui.database.FirebaseRecyclerOptions; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.SPCA.Model.Tests; + + +public class MainActivity extends NavigationTop { + private DatabaseReference TestRef; + private RecyclerView recyclerView; + + private TextView info; + FloatingActionButton fasbs; + + String number; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + LayoutInflater inflater = (LayoutInflater) this + .getSystemService(LAYOUT_INFLATER_SERVICE); + View contentView = inflater.inflate(R.layout.activity_main, null, false); + draw.addView(contentView, 0); + + SharedPreferences preferences6 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences6.getString("Phone", null); + fasbs=findViewById(R.id.fab); +info=findViewById(R.id.info); + Log.e("main", "error "+number); + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + recyclerView = findViewById(R.id.recycler_view); + fasbs.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(MainActivity.this, AddTest.class); + startActivity(intent); + + } + }); + + LinearLayoutManager layoutManager1=new LinearLayoutManager(this); + + recyclerView.setLayoutManager(new GridLayoutManager(this, 1)); + + DisplayMetrics displayMetrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); + int height = displayMetrics.heightPixels / 8; + int spaceInPixel = 4; + recyclerView.addItemDecoration(new SpaceDecoration(spaceInPixel)); + + } + @Override + protected void onStart() + { + super.onStart(); + + + FirebaseRecyclerOptions options = + new FirebaseRecyclerOptions.Builder() + .setQuery(TestRef, Tests.class) + .build(); + + + FirebaseRecyclerAdapter adapter = + new FirebaseRecyclerAdapter(options) { + @Override + protected void onBindViewHolder(@NonNull TestViewHolder holder, int position, @NonNull final Tests model) + { + + holder.ProtocolName.setText(""+model.getName_protocol()); + holder.cycleNumber.setText("Number of Cycles : "+model.getNo_of_pcr_cycle()); +holder.txttimestamp.setText(model.getDate_protocol()); + + + //holder.txtProductDescription.setText(model.getSample()); + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(MainActivity.this, TempDataShow.class); + Log.e("main", "error id"+model.getDen_temp()); + Log.e("main", "TestID"+model.getAnn_time()); + + intent.putExtra("pid",model.getRandom_key()); + startActivity(intent); + + } + }); + } + + @NonNull + @Override + public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); + TestViewHolder holder = new TestViewHolder(view); + return holder; + } + }; + recyclerView.setAdapter(adapter); + adapter.startListening(); + } + private void firebasesearch(String data) + { + { + Query firebaseSearchQuery = TestRef.orderByChild("name_protocol").startAt(data).endAt(data + "\uf8ff"); + FirebaseRecyclerOptions options = + new FirebaseRecyclerOptions.Builder() + .setQuery(firebaseSearchQuery, Tests.class) + .build(); + + + FirebaseRecyclerAdapter adapter = + new FirebaseRecyclerAdapter(options) { + @Override + protected void onBindViewHolder(@NonNull final TestViewHolder holder, int position, @NonNull final Tests model) + { + holder.ProtocolName.setText(""+model.getName_protocol()); + holder.cycleNumber.setText("Number of Cycles : "+model.getNo_of_pcr_cycle()); + holder.txttimestamp.setText(model.getDate_protocol()); + //holder.txtProductDescription.setText(model.getSample()); + + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent=new Intent(MainActivity.this, Datashow.class); + Log.e("main", "error id"+model.getDen_temp()); + Log.e("main", "TestID"+model.getAnn_time()); + + intent.putExtra("pid",model.getIntial_den_temp()); + startActivity(intent); + + + + } + + }); + } + + @NonNull + @Override + public TestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) + { + View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); + TestViewHolder holder = new TestViewHolder(view); + return holder; + } + }; + recyclerView.setAdapter(adapter); + adapter.startListening(); + } + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater=getMenuInflater(); + inflater.inflate(R.menu.searchmenu,menu); + MenuItem item = menu.findItem(R.id.search); + SearchView searchView = (SearchView) item.getActionView(); + //searchView.setIconified(false); + //searchView.setIconifiedByDefault(false); + searchView.setQueryHint("Search Protocol"); + + + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + query=query.toLowerCase(); + + firebasesearch(query); + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + newText=newText.toLowerCase(); + + firebasesearch(newText); + + return false; + } + }); + return super.onCreateOptionsMenu(menu); + } + @Override + public void onBackPressed() { + + finishAffinity(); + finish(); + } +} + + diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/Model/RegisterHelper.java b/app/src/main/java/no/spca/android/iisc/SPCA/Model/RegisterHelper.java new file mode 100644 index 0000000..7ec9900 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/Model/RegisterHelper.java @@ -0,0 +1,41 @@ +package no.spca.android.iisc.SPCA.Model; + +import java.io.Serializable; + +public class RegisterHelper implements Serializable { + + public String name, number, password; + + public RegisterHelper(String name, String number, String password) { + this.name = name; + this.number = number; + this.password = password; + } + public RegisterHelper() { + + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/Model/Tests.java b/app/src/main/java/no/spca/android/iisc/SPCA/Model/Tests.java new file mode 100644 index 0000000..d307992 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/Model/Tests.java @@ -0,0 +1,167 @@ +package no.spca.android.iisc.SPCA.Model; + +public class Tests { + + private String Time, rev_trans_temp, rev_trans_time, intial_den_temp, intial_den_time,den_temp,den_time,ann_temp,ann_time,ext_temp,ext_time,fext_temp,fext_time,no_of_pcr_cycle,random_key,name_protocol,date_protocol; + + public Tests() { + + + } + + public Tests(String time, String rev_trans_temp, String rev_trans_time, String intial_den_temp, String intial_den_time, String den_temp, String den_time, String ann_temp, String ann_time, String ext_temp, String ext_time, String fext_temp, String fext_time, String no_of_pcr_cycle, String random_key, String name_protocol, String date_protocol) { + Time = time; + this.rev_trans_temp = rev_trans_temp; + this.rev_trans_time = rev_trans_time; + this.intial_den_temp = intial_den_temp; + this.intial_den_time = intial_den_time; + this.den_temp = den_temp; + this.den_time = den_time; + this.ann_temp = ann_temp; + this.ann_time = ann_time; + this.ext_temp = ext_temp; + this.ext_time = ext_time; + this.fext_temp = fext_temp; + this.fext_time = fext_time; + this.no_of_pcr_cycle = no_of_pcr_cycle; + this.random_key = random_key; + this.name_protocol = name_protocol; + this.date_protocol = date_protocol; + } + + public String getTime() { + return Time; + } + + public void setTime(String time) { + Time = time; + } + + public String getRev_trans_temp() { + return rev_trans_temp; + } + + public void setRev_trans_temp(String rev_trans_temp) { + this.rev_trans_temp = rev_trans_temp; + } + + public String getRev_trans_time() { + return rev_trans_time; + } + + public void setRev_trans_time(String rev_trans_time) { + this.rev_trans_time = rev_trans_time; + } + + public String getIntial_den_temp() { + return intial_den_temp; + } + + public void setIntial_den_temp(String intial_den_temp) { + this.intial_den_temp = intial_den_temp; + } + + public String getIntial_den_time() { + return intial_den_time; + } + + public void setIntial_den_time(String intial_den_time) { + this.intial_den_time = intial_den_time; + } + + public String getDen_temp() { + return den_temp; + } + + public void setDen_temp(String den_temp) { + this.den_temp = den_temp; + } + + public String getDen_time() { + return den_time; + } + + public void setDen_time(String den_time) { + this.den_time = den_time; + } + + public String getAnn_temp() { + return ann_temp; + } + + public void setAnn_temp(String ann_temp) { + this.ann_temp = ann_temp; + } + + public String getAnn_time() { + return ann_time; + } + + public void setAnn_time(String ann_time) { + this.ann_time = ann_time; + } + + public String getExt_temp() { + return ext_temp; + } + + public void setExt_temp(String ext_temp) { + this.ext_temp = ext_temp; + } + + public String getExt_time() { + return ext_time; + } + + public void setExt_time(String ext_time) { + this.ext_time = ext_time; + } + + public String getFext_temp() { + return fext_temp; + } + + public void setFext_temp(String fext_temp) { + this.fext_temp = fext_temp; + } + + public String getFext_time() { + return fext_time; + } + + public void setFext_time(String fext_time) { + this.fext_time = fext_time; + } + + public String getNo_of_pcr_cycle() { + return no_of_pcr_cycle; + } + + public void setNo_of_pcr_cycle(String no_of_pcr_cycle) { + this.no_of_pcr_cycle = no_of_pcr_cycle; + } + + public String getRandom_key() { + return random_key; + } + + public void setRandom_key(String random_key) { + this.random_key = random_key; + } + + public String getName_protocol() { + return name_protocol; + } + + public void setName_protocol(String name_protocol) { + this.name_protocol = name_protocol; + } + + public String getDate_protocol() { + return date_protocol; + } + + public void setDate_protocol(String date_protocol) { + this.date_protocol = date_protocol; + } +} \ No newline at end of file diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/NavigationTop.java b/app/src/main/java/no/spca/android/iisc/SPCA/NavigationTop.java new file mode 100644 index 0000000..b3d8f01 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/NavigationTop.java @@ -0,0 +1,109 @@ +package no.spca.android.iisc.SPCA; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.drawerlayout.widget.DrawerLayout; + +import com.google.android.material.navigation.NavigationView; + +import no.spca.android.iisc.R; + + +public class NavigationTop extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { + + protected DrawerLayout draw; + private LinearLayout line; + private Toolbar tool; + + @Override + public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) { + switch (menuItem.getItemId()) + { + + case R.id.nav_contact_us: + Intent intent1=new Intent(this,About.class); + startActivity(intent1); + break; + case R.id.nav_result: + Intent intent2=new Intent(this, MainActivity.class); + startActivity(intent2); + break; + case R.id.nav_add_Test: + Intent intent3=new Intent(this, AddTest.class); + startActivity(intent3); + break; + case R.id.nav_logout: + Intent intent8=new Intent(this, LoginScreen.class); + SharedPreferences preferences = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + SharedPreferences.Editor editor = preferences.edit(); + + editor.putString("Phone", null); + editor.putString("Name",null); + + + editor.commit(); + + startActivity(intent8); + break; + + } + return true; + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + + setContentView(R.layout.activity_navigation__top); + + + draw = findViewById(R.id.Drawer); + line = findViewById(R.id.line); + tool = findViewById(R.id.tollbar); + NavigationView navigationView = findViewById(R.id.navigation); + navigationView.setNavigationItemSelectedListener(this); + + setSupportActionBar(tool); + + Window window = getWindow(); + window.setFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); + + + ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, draw, tool, R.string.open_navigation_drawer, R.string.close_navigation_drawer) { + @Override + public void onDrawerSlide(View drawerView, float slideOffset) { + super.onDrawerSlide(drawerView, slideOffset); + float sidebar = drawerView.getWidth() * slideOffset; + line.setTranslationX(sidebar); + } + }; + + draw.addDrawerListener(toggle); + toggle.syncState(); + View headerView = navigationView.getHeaderView(0); + TextView textView=headerView.findViewById(R.id.text); + TextView textView1=headerView.findViewById(R.id.not_sign_in); + + SharedPreferences preferences=getSharedPreferences("PhoneBook_number",MODE_PRIVATE); + + String string1 = preferences.getString("Phone", null); + String string2 = preferences.getString("Name", null); + textView.setText(string2); + textView1.setText(string1); + + } +} + diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/Register.java b/app/src/main/java/no/spca/android/iisc/SPCA/Register.java new file mode 100644 index 0000000..129b853 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/Register.java @@ -0,0 +1,190 @@ +package no.spca.android.iisc.SPCA; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Bundle; +import android.util.Log; +import android.util.Patterns; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.Query; +import com.google.firebase.database.ValueEventListener; +import com.hbb20.CountryCodePicker; +import no.spca.android.iisc.R; + +import no.spca.android.iisc.SPCA.VerifyOTP.VerifyOtp; + + +public class Register extends AppCompatActivity { +String numberwithcode; + private Button next; + private EditText editTextMobile; + private ProgressDialog loadingBar; + + private TextView login; + CountryCodePicker ccp; + String mobile,name; + + private EditText editTextname; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_register); + next=findViewById(R.id.buttonContinue); + editTextMobile = findViewById(R.id.editTextMobile); + + ccp=findViewById(R.id.ccp); + + ccp.registerCarrierNumberEditText(editTextMobile); + loadingBar = new ProgressDialog(this); + login=findViewById(R.id.login_account); + login.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(Register.this, LoginScreen.class); + startActivity(intent); + + } + }); + + editTextname=findViewById(R.id.editTextName); + + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mobile = editTextMobile.getText().toString().trim(); + mobile = mobile.replaceAll("[^0-9]", ""); + + name = editTextname.getText().toString().trim(); + + + if (!isOnline()) { + //Create an alertdialog + AlertDialog.Builder Checkbuilder = new AlertDialog.Builder(Register.this); + Checkbuilder.setTitle("No Internet Connection !"); + Checkbuilder.setMessage("Check Your Internet Connection."); + + Checkbuilder.setPositiveButton("Retry", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + + dialog.cancel(); + } + }); + + Checkbuilder.setNegativeButton("Exit", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + finish(); + } + }); + + AlertDialog alert = Checkbuilder.create(); + alert.show(); + + } + + else { + if (mobile.equals("") || name.equals("")) { + Toast.makeText(Register.this, "please enter all the required fields", Toast.LENGTH_SHORT).show(); + + } else if (!Patterns.PHONE.matcher(mobile).matches()) { + editTextMobile.setError("Enter a valid Phone "); + + } + else if (mobile.length() <9 ) { + Toast.makeText(Register.this, "Enter a valid Phone", Toast.LENGTH_SHORT).show(); + + } + else if (mobile.length() >=11 ) { + Toast.makeText(Register.this, "Enter a valid Phone", Toast.LENGTH_SHORT).show(); + + }else { + + Query chekuser = FirebaseDatabase.getInstance().getReference("USERS").orderByChild("number").equalTo(mobile); + chekuser.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + if (dataSnapshot.exists()) { + Toast.makeText(Register.this, "User Already Exist", Toast.LENGTH_SHORT).show(); + + } else { + Intent intent = new Intent(Register.this, VerifyOtp.class); + Log.e("main", "error " + mobile); + + numberwithcode = ccp.getFullNumberWithPlus(); + Log.e("main", "error " + numberwithcode); + + if (mobile.equals("") || name.equals("")) { + Toast.makeText(Register.this, "please enter all the required fields", Toast.LENGTH_SHORT).show(); + + } else if (!Patterns.PHONE.matcher(mobile).matches()) { + editTextMobile.setError("Enter a valid Phone "); + } else { + loadingBar.setTitle("Create Account"); + loadingBar.setMessage("Please wait "); + loadingBar.setCanceledOnTouchOutside(false); + loadingBar.show(); + + + intent.putExtra("numberwithcode", numberwithcode); + + intent.putExtra("mobile", mobile); + intent.putExtra("username", name); + + startActivity(intent); + } + + + } + + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + Log.e("Raman", "Received an exception check chexk " + databaseError.getMessage()); + + } + }); + } + } + + } + }); + + + + + } + @Override + public void onBackPressed() { + + Intent intent = new Intent(Register.this, LoginScreen.class); + startActivity(intent); + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/SPCAManagerCallbacks.java b/app/src/main/java/no/spca/android/iisc/SPCA/SPCAManagerCallbacks.java new file mode 100644 index 0000000..a0181d0 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/SPCAManagerCallbacks.java @@ -0,0 +1,10 @@ + +package no.spca.android.iisc.SPCA; + +import no.spca.android.iisc.SPCA.callback.CycleCharacteristicCallback; +import no.spca.android.iisc.battery.BatteryManagerCallbacks; + + +interface SPCAManagerCallbacks extends BatteryManagerCallbacks, CycleCharacteristicCallback { + +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/SpaceDecoration.java b/app/src/main/java/no/spca/android/iisc/SPCA/SpaceDecoration.java new file mode 100644 index 0000000..e06c770 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/SpaceDecoration.java @@ -0,0 +1,20 @@ +package no.spca.android.iisc.SPCA; + +import android.graphics.Rect; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +public class SpaceDecoration extends RecyclerView.ItemDecoration { + private final int space; + + public SpaceDecoration(int space) { + this.space = space; + } + + @Override + public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) { + outRect.left=outRect.bottom=outRect.right=outRect.top=space; + } +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/TempDataShow.java b/app/src/main/java/no/spca/android/iisc/SPCA/TempDataShow.java new file mode 100644 index 0000000..6144237 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/TempDataShow.java @@ -0,0 +1,650 @@ +package no.spca.android.iisc.SPCA; + +import android.app.AlertDialog; +import android.app.ProgressDialog; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.os.Build; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Handler; +import android.text.TextWatcher; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.Switch; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.database.DataSnapshot; +import com.google.firebase.database.DatabaseError; +import com.google.firebase.database.DatabaseReference; +import com.google.firebase.database.FirebaseDatabase; +import com.google.firebase.database.ValueEventListener; + +import java.io.File; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Timer; +import java.util.TimerTask; +import java.util.UUID; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.SPCA.Model.Tests; +import no.spca.android.iisc.profile.BleProfileService; +import no.spca.android.iisc.profile.BleProfileServiceReadyActivity; + + + +public class TempDataShow extends BleProfileServiceReadyActivity { + @SuppressWarnings("unused") + private final String TAG = "AddTest"; + + private TextView mValueView; + private TextView mCycleView; + private EditText mFETempValueView; + private EditText mFETimeValueView; + + String acttime; + + private TextView mHeatingStatusView; + private int seconds1 ,seconds2; + private Switch mHeatingState ; +private EditText prtocol; + + private EditText mDTimeValueView; + private Integer mDSetTime ; + private EditText mLTimeValueView; + private Integer mLSetTime ; + private EditText mOTimeValueView; + private Integer mOSetTime ; + private String time1,time2,time3; + private Date date1,date2,date3; + + + private final int valuedata=0; + private final int j=0; + private final Handler handler = new Handler(); + private Runnable runnable; + + + private EditText mATimeValueView; + private Integer mASetTime ; + private EditText mETimeValueView; + private Integer mESetTime ; + private TextWatcher txtwt; + + private Button next; + Button connect; + + + + + + private EditText mDTempValueView; + private Integer mDSetTemp ; + private EditText mATempValueView; + private Integer mASetTemp ; + private EditText mETempValueView; + private Integer mESetTemp ; + + private EditText mLTempValueView; + private Integer mLSetTemp ; + private EditText mOTempValueView; + private Integer mOSetTemp ; + private long diff=0; + private long diffSeconds=0; + private long diffMinutes=0; + private long diffHours=0; + private long diff1=0; + private long diffSeconds1=0; + private long diffMinutes1=0; + + private long diffHours1=0; + private Integer mSSetTemp ; + private Integer mSSetTime; + + private int FLAG=0; + + + private int count=0; + private int valuw=0; + + int i=0; + File filePath3 = null; + private DatabaseReference TestRef; + private ProgressDialog loadingBar; + private Button save; + private String TestRandomKey, downloadImageUrl1,saveCurrentDate, saveCurrentTime,number; + + + + private EditText mNPcrCView; + private Integer mNPcrC ; + private Timer T; + + private String TestID = ""; + + + @Override + protected void onCreateView(final Bundle savedInstanceState) { + setContentView(R.layout.activity_protocol); + loadingBar = new ProgressDialog(this); + + setGUI(); + TestID = getIntent().getStringExtra("pid"); + + Log.e("main", "error id "+TestID); + getTestDetails(TestID); + + next = findViewById(R.id.action_next); + connect = findViewById(R.id.action_connect); + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + connect.performClick(); + + + Intent intent = new Intent(TempDataShow.this, GraphActivity.class); + + + intent.putExtra("key6",acttime); + + startActivity(intent); + + } + }); + + + + + } + + private void setGUI() { + mValueView = findViewById(R.id.Temp_Value); + mCycleView = findViewById(R.id.RemTime_Value); + + mDTempValueView = findViewById(R.id.D_Temp_Set); + mDTimeValueView = findViewById(R.id.D_Time_Set); + mATempValueView = findViewById(R.id.A_Temp_Set); + mATimeValueView = findViewById(R.id.A_Time_Set); + mETempValueView = findViewById(R.id.E_Temp_Set); + mETimeValueView = findViewById(R.id.E_Time_Set); + mLTempValueView=findViewById(R.id.L_Temp_Set); + mOTempValueView=findViewById(R.id.O_Temp_Set); + mLTimeValueView = findViewById(R.id.L_Time_Set); + + mOTimeValueView = findViewById(R.id.O_Time_Set); + mFETimeValueView=findViewById(R.id.S_Time_Set); + mFETempValueView=findViewById(R.id.S_Temp_Set); + + T=new Timer(); + + + SharedPreferences preferences689 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences689.getString("Phone", null); + + + TestRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + + mNPcrCView = findViewById(R.id.N_Pcr_C); +prtocol=findViewById(R.id.protocol_name); + + mHeatingState = findViewById(R.id.heating_state); + mHeatingStatusView= findViewById(R.id.heating_status_text); + //mValueView.setText("fff"); + + + + mHeatingState.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + startCounter(); + + + i=1; + if(date2 !=null && date1 !=null) { + SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + try { + date1 = format.parse(time1); + date2 = format.parse(time2); + diff = (date2.getTime() - date1.getTime()); + diffSeconds = diff / 1000 % 60; + diffMinutes = diff / (60 * 1000) % 60; + diffHours = diff / (60 * 60 * 1000); + + + + } catch (ParseException e) { + e.printStackTrace(); + } + + + + + + } + + Log.e("main", "error data inside " + valuedata); + + getService().heatingSwitch(1); + + mDSetTemp = Integer.parseInt(mDTempValueView.getText().toString()); + getService().sendDTemp(mDSetTemp); + + + mDSetTime = Integer.parseInt(mDTimeValueView.getText().toString()); + getService().sendDTime(mDSetTime); + + mLSetTemp = Integer.parseInt(mLTempValueView.getText().toString()); + getService().sendLTemp(mLSetTemp); + mLSetTime = Integer.parseInt(mLTimeValueView.getText().toString()); + getService().sendLTime(mLSetTime); + + mOSetTemp = Integer.parseInt(mOTempValueView.getText().toString()); + getService().sendOTemp(mOSetTemp); + mOSetTime = Integer.parseInt(mOTimeValueView.getText().toString()); + getService().sendOTime(mOSetTime); + + + mASetTemp = Integer.parseInt(mATempValueView.getText().toString()); + getService().sendATemp(mASetTemp); + mASetTime = Integer.parseInt(mATimeValueView.getText().toString()); + getService().sendATime(mASetTime); + + mESetTemp = Integer.parseInt(mETempValueView.getText().toString()); + getService().sendETemp(mESetTemp); + mESetTime = Integer.parseInt(mETimeValueView.getText().toString()); + getService().sendETime(mESetTime); + + + mSSetTemp = Integer.parseInt(mFETempValueView.getText().toString()); + getService().sendLTemp(mSSetTemp); + mSSetTime = Integer.parseInt(mFETimeValueView.getText().toString()); + getService().sendLTime(mSSetTime); + + + mNPcrC = Integer.parseInt(mNPcrCView.getText().toString()); + getService().sendNPcrN(mNPcrC); + Log.e("main", "error 34" + mDSetTemp); + + Log.e("main", "error 2 " + mDSetTemp); + Log.e("main", "error data box " + valuedata); + + } + else { + getService().heatingSwitch(0); + } + mHeatingStatusView.setText(isChecked ? R.string.Heating_block_on : R.string.Heating_block_off); + }); + + + + } + + @Override + protected void onInitialize(final Bundle savedInstanceState) { + LocalBroadcastManager.getInstance(this).registerReceiver(mBroadcastReceiver, makeIntentFilter()); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + LocalBroadcastManager.getInstance(this).unregisterReceiver(mBroadcastReceiver); + } + + @Override + protected void setDefaultUI() { + mValueView.setText("wait"); + mCycleView.setText("wait"); + + } + + @Override + protected int getLoggerProfileTitle() { + return R.string.template_feature_title; + } + + + + + @Override + protected int getDefaultDeviceName() { + return R.string.template_default_name; + } + + @Override + protected UUID getFilterUUID() { + return CycleManager.SERVICE_UUID; + } + + @Override + protected Class getServiceClass() { + return CycleService.class; + } + + @Override + protected void onServiceBound(final CycleService.TemplateBinder binder) { + } + + @Override + protected void onServiceUnbound() { + } + + @Override + public void onServicesDiscovered(final BluetoothDevice device, final boolean optionalServicesFound) { + } + + @Override + public void onDeviceDisconnected(final BluetoothDevice device) { + super.onDeviceDisconnected(device); + } + + @SuppressWarnings("unused") + private void setValueOnView(@NonNull final BluetoothDevice device, int value) { + } + + + + @SuppressWarnings("unused") + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int value) { + + } + + private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @RequiresApi(api = Build.VERSION_CODES.O) + @Override + public void onReceive(final Context context, final Intent intent) { + final String action = intent.getAction(); + final BluetoothDevice device = intent.getParcelableExtra(no.spca.android.iisc.SPCA.CycleService.EXTRA_DEVICE); + + if (no.spca.android.iisc.SPCA.CycleService.BROADCAST_TEMPLATE_MEASUREMENT.equals(action)) { + int value = intent.getIntExtra(no.spca.android.iisc.SPCA.CycleService.EXTRA_DATA, 0); + setValueOnView(device, value); + valuw=value; + if(value==0) + { + DateFormat df = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + time1 = df.format(Calendar.getInstance().getTime()); + + + Log.e("main", "error 403 " +time1); + + + + //cycle 1 start + + + } + + else if(value ==1 ) + { + DateFormat df = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + time2 = df.format(Calendar.getInstance().getTime()); + + Log.e("main", "error 404 " +time2); + LocalDateTime date = LocalDateTime.now(); + seconds1 = date.toLocalTime().toSecondOfDay(); + + + + } + else if(value ==2 ) + { + DateFormat df = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + time3 = df.format(Calendar.getInstance().getTime()); + + try { + date1 = df.parse(time1); + date2 = df.parse(time2); + date3=df.parse(time3); + + } catch (ParseException e) { + e.printStackTrace(); + } + Log.e("main", "date 1 " + date2.getTime()); + Log.e("main", "date 2 " + date1.getTime()); + + + diff1 = date3.getTime() - date2.getTime(); + Log.e("main", "difference minute " + diffMinutes); + + + Log.e("main", "difference minute " + diffMinutes); + + diffSeconds1 = diff1 / 1000 % 60; + diffMinutes1 = diff1 / (60 * 1000) % 60; + diffHours1 = diff1/ (60 * 60 * 1000); + Log.e("main", "date difference " + diffMinutes1); + + + + Log.e("main", "error 404 " +time2); + + + + + } + + if(time1 !=null && time2 !=null &&diffSeconds1==1 ) { + + SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss"); + try { + date1 = format.parse(time1); + date2 = format.parse(time2); + Log.e("main", "date 1 " + date2.getTime()); + Log.e("main", "date 2 " + date1.getTime()); + + + diff = date2.getTime() - date1.getTime(); + Log.e("main", "difference minute " + diffMinutes); + + diffSeconds = diff / 1000 % 60; + diffMinutes = diff / (60 * 1000) % 60; + diffHours = diff / (60 * 60 * 1000); + Log.e("main", "date difference " + diffMinutes); + FLAG=1; + + + + } catch (ParseException e) { + e.printStackTrace(); + } + + + } + else + { + } + + } else if (no.spca.android.iisc.SPCA.CycleService.BROADCAST_BATTERY_LEVEL.equals(action)) { + final int batteryLevel = intent.getIntExtra(no.spca.android.iisc.SPCA.CycleService.EXTRA_BATTERY_LEVEL, 0); + onBatteryLevelChanged(device, batteryLevel); + } + + } + }; + + private static IntentFilter makeIntentFilter() { + final IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(no.spca.android.iisc.SPCA.CycleService.BROADCAST_TEMPLATE_MEASUREMENT); + intentFilter.addAction(no.spca.android.iisc.SPCA.CycleService.BROADCAST_BATTERY_LEVEL); + return intentFilter; + } + + + private void startCounter() + + { + + + + T.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + runOnUiThread(new Runnable() { + @Override + public void run() { + + if(FLAG==1) + { + mNPcrC=mNPcrC-1; + long cycle=mNPcrC.longValue(); + acttime=String.valueOf(diff*cycle); + //acttime="20444444" + connect.performClick(); + + + Intent intent = new Intent(TempDataShow.this, GraphActivity.class); + + + intent.putExtra("key6",acttime); + + startActivity(intent); + //acttime="20444444"; + // countdown(diff *cycle); + + T.cancel(); + } + + + + } + }); + } + }, 1000, 1000); + + + + + } + + + + @Override + public void onPointerCaptureChanged(boolean hasCapture) { + + } + public boolean isOnline() { + ConnectivityManager connMgr = (ConnectivityManager) + getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); + return (networkInfo != null && networkInfo.isConnected()); + + } + private void getTestDetails(String TestID) + { + DatabaseReference productsRef = FirebaseDatabase.getInstance().getReference().child("Test_Data").child(number); + + productsRef.child(TestID).addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) + { + if (dataSnapshot.exists()) + { + + + Tests products = dataSnapshot.getValue(Tests.class); + + + mLTempValueView.setText(products.getRev_trans_temp()); + + mLTimeValueView.setText(products.getRev_trans_time()); + + mOTempValueView.setText(products.getIntial_den_temp()); + + mOTimeValueView.setText(products.getIntial_den_time()); + + mDTempValueView.setText(products.getDen_temp()); + + + mDTimeValueView.setText(products.getDen_time()); + + + mATempValueView.setText(products.getAnn_temp()); + prtocol.setText(products.getName_protocol()); + + + + mATimeValueView.setText(products.getAnn_time()); + + + + mETempValueView.setText(products.getExt_temp()); + + mETimeValueView.setText(products.getExt_time()); + + mFETempValueView.setText(products.getFext_temp()); + + mFETimeValueView.setText(products.getFext_time()); + + + mNPcrCView.setText(products.getNo_of_pcr_cycle()); + + mLTempValueView.setText(products.getRev_trans_temp()); + + mLTimeValueView.setText(products.getRev_trans_time()); + mATempValueView.setText(products.getAnn_temp()); + mATimeValueView.setText(products.getAnn_time()); + mDTempValueView.setText(products.getDen_temp()); + mDTimeValueView.setText(products.getDen_time()); + + + } + } + + @Override + public void onCancelled(DatabaseError databaseError) { + + } + }); + } + @Override + public void onBackPressed() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setCancelable(false); + builder.setMessage("Do you want to Exit ?"); + + builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + Intent intent = new Intent(TempDataShow.this, MainActivity.class); + finish(); + startActivity(intent); + + + + + } + }); + builder.setNegativeButton("No", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/TemperatureManager.java b/app/src/main/java/no/spca/android/iisc/SPCA/TemperatureManager.java new file mode 100644 index 0000000..562f591 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/TemperatureManager.java @@ -0,0 +1,156 @@ + +package no.spca.android.iisc.SPCA; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattService; +import android.content.Context; +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.util.UUID; + +import no.nordicsemi.android.ble.data.Data; +import no.nordicsemi.android.log.LogContract; +import no.spca.android.iisc.SPCA.callback.CycleDataCallback; +import no.spca.android.iisc.battery.BatteryManager; +import no.spca.android.iisc.parser.TemperatureParser; + + +public class TemperatureManager extends BatteryManager { + + + static final UUID SERVICE_UUID = UUID.fromString("00001500-1212-efde-1523-785feabcd123"); private static final UUID TEMP_READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001501-1212-efde-1523-785feabcd123"); private static final UUID OTHER_SERVICE_UUID = UUID.fromString("00001800-0000-1000-8000-00805f9b34fb"); private static final UUID READABLE_CHARACTERISTIC_UUID = UUID.fromString("00001801-0000-1000-8000-00805f9b34fb"); private BluetoothGattCharacteristic mReadBlockTempCharacteristic, mDeviceNameCharacteristic, mRequiredCharacteristic, mOptionalCharacteristic ; + + public TemperatureManager(final Context context) { + super(context); + } + + @NonNull + @Override + protected BatteryManagerGattCallback getGattCallback() { + return mGattCallback; + } + + + private final BatteryManagerGattCallback mGattCallback = new BatteryManagerGattCallback() { + + @Override + protected void initialize() { + + super.initialize(); + + + requestMtu(43)//requestMtu(43) + .with((device, mtu) -> log(LogContract.Log.Level.APPLICATION, "MTU changed to " + mtu)) + .done(device -> { + + }) + .fail((device, status) -> log(Log.WARN, "MTU change not supported")) + .enqueue(); + + setNotificationCallback(mReadBlockTempCharacteristic) + .with(new CycleDataCallback() { + @Override + public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + log(LogContract.Log.Level.APPLICATION, TemperatureParser.parse(data)); + super.onDataReceived(device, data); + } + + @Override + public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) { + mCallbacks.onSampleValueReceived(device, value); + } + + @Override + public void onInvalidDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + log(Log.WARN, "Invalid data received: " + data); + } + }); + + enableNotifications(mReadBlockTempCharacteristic) + .with((device, data) -> log(Log.DEBUG, "Data sent: " + data)) + .done(device -> log(LogContract.Log.Level.APPLICATION, "Notifications enabled successfully")) + .fail((device, status) -> log(Log.WARN, "Failed to enable notifications")) + .enqueue(); + } + + @Override + protected boolean isRequiredServiceSupported(@NonNull final BluetoothGatt gatt) { + final BluetoothGattService service = gatt.getService(SERVICE_UUID); + if (service != null) { + mReadBlockTempCharacteristic = service.getCharacteristic(TEMP_READABLE_CHARACTERISTIC_UUID); + + } + final BluetoothGattService otherService = gatt.getService(OTHER_SERVICE_UUID); + if (otherService != null) { + mDeviceNameCharacteristic = otherService.getCharacteristic(READABLE_CHARACTERISTIC_UUID); + } + + return mReadBlockTempCharacteristic != null ; + } + + @Override + protected boolean isOptionalServiceSupported(@NonNull final BluetoothGatt gatt) { + super.isOptionalServiceSupported(gatt); + + final BluetoothGattService service = gatt.getService(SERVICE_UUID); + if (service != null) { + mOptionalCharacteristic = service.getCharacteristic(READABLE_CHARACTERISTIC_UUID); + } + return mOptionalCharacteristic != null; + } + + @Override + protected void onDeviceDisconnected() { + super.onDeviceDisconnected(); + + mRequiredCharacteristic = null; + mDeviceNameCharacteristic = null; + mOptionalCharacteristic = null; + } + + @Override + protected void onDeviceReady() { + super.onDeviceReady(); + + readCharacteristic(mReadBlockTempCharacteristic) + .with((device, data) -> { + if (data.size() > 0) { + final Integer value = data.getIntValue(Data.FORMAT_UINT8, 0); + log(LogContract.Log.Level.APPLICATION, "Value '" + value + "' has been read!"); + } else { + log(Log.WARN, "Value is empty!"); + } + }) + .enqueue(); + } + }; + + + + + + + + + + + + + + + + + + + + + + + + + +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/TemperatureService.java b/app/src/main/java/no/spca/android/iisc/SPCA/TemperatureService.java new file mode 100644 index 0000000..288233c --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/TemperatureService.java @@ -0,0 +1,142 @@ + + +package no.spca.android.iisc.SPCA; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.bluetooth.BluetoothDevice; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; + +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + +import no.nordicsemi.android.log.Logger; +import no.spca.android.iisc.FeaturesActivity; +import no.spca.android.iisc.NotificationData; +import no.spca.android.iisc.R; +import no.spca.android.iisc.profile.BleProfileService; +import no.spca.android.iisc.profile.LoggableBleManager; + +import static no.spca.android.iisc.SPCA.CycleService.BROADCAST_TEMPLATE_MEASUREMENT; + +public class TemperatureService extends BleProfileService implements SPCAManagerCallbacks { + public static final String BROADCAST_TEMPLATE_MEASUREMENT1 = "no.spca.android.iisc.template.BROADCAST_MEASUREMENT"; + + public static final String EXTRA_DATA1 = "no.spca.android.iisc.template.EXTRA_DATA1"; + + public static final String BROADCAST_BATTERY_LEVEL = "no.spca.android.iisc.BROADCAST_BATTERY_LEVEL"; + public static final String EXTRA_BATTERY_LEVEL = "no.spca.android.iisc.EXTRA_BATTERY_LEVEL"; + + private final static String ACTION_DISCONNECT = "no.spca.android.iisc.template.ACTION_DISCONNECT"; + + private final static int NOTIFICATION_ID = 864; + private final static int OPEN_ACTIVITY_REQ = 0; + private final static int DISCONNECT_REQ = 1; + + private TemperatureManager mManager; + + + private final LocalBinder mBinder = new TemplateBinder(); + + + class TemplateBinder extends LocalBinder { + } + + @Override + protected LocalBinder getBinder() { + return mBinder; + } + + @Override + protected LoggableBleManager initializeManager() { + return mManager = new TemperatureManager(this); + } + + @Override + public void onCreate() { + super.onCreate(); + + final IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_DISCONNECT); + registerReceiver(mDisconnectActionBroadcastReceiver, filter); + } + + @Override + public void onDestroy() { + cancelNotification(); + unregisterReceiver(mDisconnectActionBroadcastReceiver); + + super.onDestroy(); + } + + @Override + protected void onRebind() { + cancelNotification(); + } + + @Override + protected void onUnbind() { + createNotification(R.string.template_notification_connected_message, 0); + } + + @Override + public void onSampleValueReceived(@NonNull final BluetoothDevice device, final int value) { + final Intent broadcast = new Intent(BROADCAST_TEMPLATE_MEASUREMENT); + broadcast.putExtra(EXTRA_DEVICE, getBluetoothDevice()); + broadcast.putExtra(EXTRA_DATA1, value); + LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); + + if (!mBound) { + } + } + + @Override + public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { + + } + + + 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, AddTest.class); + + final Intent disconnect = new Intent(ACTION_DISCONNECT); + final PendingIntent disconnectAction = PendingIntent.getBroadcast(this, DISCONNECT_REQ, disconnect, PendingIntent.FLAG_UPDATE_CURRENT); + + final PendingIntent pendingIntent = PendingIntent.getActivities(this, OPEN_ACTIVITY_REQ, new Intent[]{parentIntent, targetIntent}, PendingIntent.FLAG_UPDATE_CURRENT); + final NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationData.CONNECTED_DEVICE_CHANNEL); + builder.setContentIntent(pendingIntent); + builder.setContentTitle(getString(R.string.app_name)).setContentText(getString(messageResId, getDeviceName())); + builder.setSmallIcon(R.drawable.ic_stat_notify_template); + builder.setShowWhen(defaults != 0).setDefaults(defaults).setAutoCancel(true).setOngoing(true); + builder.addAction(new NotificationCompat.Action(R.drawable.ic_action_bluetooth, getString(R.string.template_notification_action_disconnect), disconnectAction)); + + final Notification notification = builder.build(); + final NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID, notification); + } + + + private void cancelNotification() { + final NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + nm.cancel(NOTIFICATION_ID); + } + + + private final BroadcastReceiver mDisconnectActionBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(final Context context, final Intent intent) { + Logger.i(getLogSession(), "[Notification] Disconnect action pressed"); + if (isConnected()) + getBinder().disconnect(); + else + stopSelf(); + } + }; +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/TestViewHolder.java b/app/src/main/java/no/spca/android/iisc/SPCA/TestViewHolder.java new file mode 100644 index 0000000..8977924 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/TestViewHolder.java @@ -0,0 +1,47 @@ +package no.spca.android.iisc.SPCA; + +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.SPCA.Interface.ItemClickListner; + + +public class TestViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener +{ + public TextView ProtocolName, txttimestamp, cycleNumber,iconfinder,txtsampletype; + public ImageView imageView; + public ItemClickListner listner; + + + public TestViewHolder(View itemView) + { + super(itemView); + + + + + imageView = (ImageView) itemView.findViewById(R.id.icon_profile); + iconfinder=(TextView) itemView.findViewById(R.id.icon_text); + + ProtocolName = (TextView) itemView.findViewById(R.id.protocol_id); + txtsampletype = (TextView) itemView.findViewById(R.id.sample_type); + txttimestamp=itemView.findViewById(R.id.timestamp); + cycleNumber =itemView.findViewById(R.id.pro_data); + + } + + public void setItemClickListner(ItemClickListner listner) + { + this.listner = listner; + } + + @Override + public void onClick(View view) + { + listner.onClick(view, getAdapterPosition(), false); + } +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/VerifyOTP/VerifyOtp.java b/app/src/main/java/no/spca/android/iisc/SPCA/VerifyOTP/VerifyOtp.java new file mode 100644 index 0000000..b69ba01 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/VerifyOTP/VerifyOtp.java @@ -0,0 +1,150 @@ +package no.spca.android.iisc.SPCA.VerifyOTP; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.chaos.view.PinView; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.FirebaseException; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.PhoneAuthCredential; +import com.google.firebase.auth.PhoneAuthOptions; +import com.google.firebase.auth.PhoneAuthProvider; + +import java.util.concurrent.TimeUnit; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.SPCA.CreatePassword; + + +public class VerifyOtp extends AppCompatActivity { + + private String verificationid; + private FirebaseAuth mAuth; + private Button nextactivity; + private ProgressBar progressBar; + PinView pinFromUser; + private EditText editText; + String name; + String phonenumber; + String phonenumberke; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_verify__o_t_p); + pinFromUser = findViewById(R.id.firstPinView); + nextactivity = findViewById(R.id.buttonSignIn); + + mAuth = FirebaseAuth.getInstance(); + + + String phonenumberk = getIntent().getStringExtra("numberwithcode"); + phonenumberke = getIntent().getStringExtra("mobile"); + + phonenumber = phonenumberk; + + name = getIntent().getStringExtra("username"); + + + + sendVerificationCode(phonenumber); + findViewById(R.id.buttonSignIn).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + String code = pinFromUser.getText().toString().trim(); + + if ((code.isEmpty() || code.length() < 6)) { + + editText.setError("Enter code..."); + editText.requestFocus(); + return; + } + verifyCode(code); + + } + }); + + } + private void verifyCode(String code){ + PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationid, code); + signInWithCredential(credential); + } + + private void signInWithCredential(PhoneAuthCredential credential) { + mAuth.signInWithCredential(credential) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + + Intent intent = new Intent(VerifyOtp.this, CreatePassword.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + intent.putExtra("mobile", phonenumberke); + intent.putExtra("username", name); + + + startActivity(intent); + + } else { + } + } + + }); + } + + private void sendVerificationCode(String number){ + + PhoneAuthOptions options = + PhoneAuthOptions.newBuilder(mAuth) + .setPhoneNumber(number) .setTimeout(60L, TimeUnit.SECONDS) .setActivity(this) .setCallbacks(mCallBack) .build(); + PhoneAuthProvider.verifyPhoneNumber(options); + + } + + private final PhoneAuthProvider.OnVerificationStateChangedCallbacks + mCallBack = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { + + @Override + public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) { + super.onCodeSent(s, forceResendingToken); + verificationid = s; + } + + @Override + public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) { + String code = phoneAuthCredential.getSmsCode(); + if (code != null){ + pinFromUser.setText(code); + verifyCode(code); + } + } + + @Override + public void onVerificationFailed(FirebaseException e) { + Toast.makeText(VerifyOtp.this, e.getMessage(),Toast.LENGTH_LONG).show(); + + } + }; + + + + + + + + +} \ No newline at end of file diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/VerifyOTP/VerifyOtpForgetPassword.java b/app/src/main/java/no/spca/android/iisc/SPCA/VerifyOTP/VerifyOtpForgetPassword.java new file mode 100644 index 0000000..20931a6 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/VerifyOTP/VerifyOtpForgetPassword.java @@ -0,0 +1,149 @@ +package no.spca.android.iisc.SPCA.VerifyOTP; + +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ProgressBar; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; + +import com.chaos.view.PinView; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.FirebaseException; +import com.google.firebase.auth.AuthResult; +import com.google.firebase.auth.FirebaseAuth; +import com.google.firebase.auth.PhoneAuthCredential; +import com.google.firebase.auth.PhoneAuthOptions; +import com.google.firebase.auth.PhoneAuthProvider; + +import java.util.concurrent.TimeUnit; + +import no.spca.android.iisc.R; +import no.spca.android.iisc.SPCA.ForgetPassword; +import no.spca.android.iisc.SPCA.ForgetPasswordReset; + + +public class VerifyOtpForgetPassword extends AppCompatActivity { + + private String verificationid; + private FirebaseAuth mAuth; + private Button nextactivity; + private ProgressBar progressBar; + PinView pinFromUser; + private EditText editText; + String codeBySystem; + String phonenumber,mobile; + + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_verify__o_t_p); + pinFromUser = findViewById(R.id.firstPinView); + nextactivity = findViewById(R.id.buttonSignIn); + + mAuth = FirebaseAuth.getInstance(); + + + String phonenumberk = getIntent().getStringExtra("mobilecode"); + phonenumber = phonenumberk; + mobile= getIntent().getStringExtra("mobile"); + + + + + sendVerificationCode(phonenumber); + findViewById(R.id.buttonSignIn).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + + String code = pinFromUser.getText().toString().trim(); + + if ((code.isEmpty() || code.length() < 6)) { + + editText.setError("Enter code..."); + editText.requestFocus(); + return; + } + verifyCode(code); + + } + }); + + } + private void verifyCode(String code){ + PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationid, code); + signInWithCredential(credential); + } + + private void signInWithCredential(PhoneAuthCredential credential) { + mAuth.signInWithCredential(credential) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (task.isSuccessful()) { + + Intent intent = new Intent(VerifyOtpForgetPassword.this, ForgetPasswordReset.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + intent.putExtra("mobile", mobile); + + + startActivity(intent); + + } else { + Toast.makeText(VerifyOtpForgetPassword.this, task.getException().getMessage(), Toast.LENGTH_LONG).show(); + } + } + + }); + } + + private void sendVerificationCode(String number){ + PhoneAuthOptions options = + PhoneAuthOptions.newBuilder(mAuth) + .setPhoneNumber(number) .setTimeout(60L, TimeUnit.SECONDS) .setActivity(this) .setCallbacks(mCallBack) .build(); + PhoneAuthProvider.verifyPhoneNumber(options); + + + } + + private final PhoneAuthProvider.OnVerificationStateChangedCallbacks + mCallBack = new PhoneAuthProvider.OnVerificationStateChangedCallbacks() { + + @Override + public void onCodeSent(String s, PhoneAuthProvider.ForceResendingToken forceResendingToken) { + super.onCodeSent(s, forceResendingToken); + verificationid = s; + } + + @Override + public void onVerificationCompleted(PhoneAuthCredential phoneAuthCredential) { + String code = phoneAuthCredential.getSmsCode(); + if (code != null){ + pinFromUser.setText(code); + verifyCode(code); + } + } + + @Override + public void onVerificationFailed(FirebaseException e) { + Toast.makeText(VerifyOtpForgetPassword.this, e.getMessage(),Toast.LENGTH_LONG).show(); + + } + }; + @Override + public void onBackPressed() { + + Intent intent = new Intent(VerifyOtpForgetPassword.this, ForgetPassword.class); + startActivity(intent); + + } + + +} \ No newline at end of file diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/callback/CycleCharacteristicCallback.java b/app/src/main/java/no/spca/android/iisc/SPCA/callback/CycleCharacteristicCallback.java new file mode 100644 index 0000000..30a6557 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/callback/CycleCharacteristicCallback.java @@ -0,0 +1,12 @@ +package no.spca.android.iisc.SPCA.callback; + +import android.bluetooth.BluetoothDevice; +import androidx.annotation.NonNull; + + +public interface CycleCharacteristicCallback { + + + void onSampleValueReceived(@NonNull final BluetoothDevice device, int value); + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/callback/TemplateDataCallback.java b/app/src/main/java/no/spca/android/iisc/SPCA/callback/CycleDataCallback.java similarity index 54% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/template/callback/TemplateDataCallback.java rename to app/src/main/java/no/spca/android/iisc/SPCA/callback/CycleDataCallback.java index 1ec05f9..2667bbf 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/template/callback/TemplateDataCallback.java +++ b/app/src/main/java/no/spca/android/iisc/SPCA/callback/CycleDataCallback.java @@ -1,4 +1,4 @@ -package no.nordicsemi.android.nrftoolbox.template.callback; +package no.spca.android.iisc.SPCA.callback; import android.bluetooth.BluetoothDevice; import androidx.annotation.NonNull; @@ -6,16 +6,9 @@ import androidx.annotation.NonNull; import no.nordicsemi.android.ble.callback.profile.ProfileDataCallback; import no.nordicsemi.android.ble.data.Data; -/** - * This is a sample data callback, that's based on Heart Rate Measurement characteristic. - * It parses the HR value and ignores other optional data for simplicity. - * Check {@link no.nordicsemi.android.ble.common.callback.hr.HeartRateMeasurementDataCallback} - * for full implementation. - * - * TODO Modify the content to parse your data. - */ + @SuppressWarnings("ConstantConditions") -public abstract class TemplateDataCallback implements ProfileDataCallback, TemplateCharacteristicCallback { +public abstract class CycleDataCallback implements ProfileDataCallback, CycleCharacteristicCallback { @Override public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { @@ -24,24 +17,17 @@ public abstract class TemplateDataCallback implements ProfileDataCallback, Templ return; } - // Read flags int offset = 0; final int flags = data.getIntValue(Data.FORMAT_UINT8, offset); final int hearRateType = (flags & 0x01) == 0 ? Data.FORMAT_UINT8 : Data.FORMAT_UINT16; offset += 1; - // Validate packet length. The type's lower nibble is its length. if (data.size() < 1 + (hearRateType & 0x0F)) { onInvalidDataReceived(device, data); return; } final int value = data.getIntValue(hearRateType, offset); - // offset += hearRateType & 0xF; - - // ... - - // Report the parsed value(s) onSampleValueReceived(device, value); } } diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/callback/TemperatureCharacteristicCallback.java b/app/src/main/java/no/spca/android/iisc/SPCA/callback/TemperatureCharacteristicCallback.java new file mode 100644 index 0000000..ceddcde --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/callback/TemperatureCharacteristicCallback.java @@ -0,0 +1,12 @@ +package no.spca.android.iisc.SPCA.callback; + +import android.bluetooth.BluetoothDevice; + +import androidx.annotation.NonNull; + + +public interface TemperatureCharacteristicCallback { + + + void onSampleValueReceived1(@NonNull final BluetoothDevice device, int value); +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/callback/TemperatureDataCallback.java b/app/src/main/java/no/spca/android/iisc/SPCA/callback/TemperatureDataCallback.java new file mode 100644 index 0000000..eedee0c --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/callback/TemperatureDataCallback.java @@ -0,0 +1,36 @@ +package no.spca.android.iisc.SPCA.callback; + +import android.bluetooth.BluetoothDevice; + +import androidx.annotation.NonNull; + +import no.nordicsemi.android.ble.callback.profile.ProfileDataCallback; +import no.nordicsemi.android.ble.data.Data; + + +@SuppressWarnings("ConstantConditions") +public abstract class TemperatureDataCallback implements ProfileDataCallback, TemperatureCharacteristicCallback { + + @Override + public void onDataReceived(@NonNull final BluetoothDevice device, @NonNull final Data data) { + if (data.size() < 2) { + onInvalidDataReceived(device, data); + return; + } + + int offset = 0; + final int flags = data.getIntValue(Data.FORMAT_UINT8, offset); + final int hearRateType = (flags & 0x01) == 0 ? Data.FORMAT_UINT8 : Data.FORMAT_UINT16; + offset += 1; + + if (data.size() < 1 + (hearRateType & 0x0F)) { + onInvalidDataReceived(device, data); + return; + } + + final int value = data.getIntValue(hearRateType, offset); + onSampleValueReceived1(device, value); + } + + public abstract void onDataReceived1(@NonNull BluetoothDevice device, @NonNull Data data); +} diff --git a/app/src/main/java/no/spca/android/iisc/SPCA/settings/SettingsActivity.java b/app/src/main/java/no/spca/android/iisc/SPCA/settings/SettingsActivity.java new file mode 100644 index 0000000..e26e211 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/settings/SettingsActivity.java @@ -0,0 +1,35 @@ + + +package no.spca.android.iisc.SPCA.settings; + +import android.os.Bundle; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import android.view.MenuItem; + +import no.spca.android.iisc.R; + +public class SettingsActivity extends AppCompatActivity { + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_settings); + + final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + + getSupportFragmentManager().beginTransaction().replace(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/spca/android/iisc/SPCA/settings/SettingsFragment.java b/app/src/main/java/no/spca/android/iisc/SPCA/settings/SettingsFragment.java new file mode 100644 index 0000000..34396e9 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SPCA/settings/SettingsFragment.java @@ -0,0 +1,19 @@ + + +package no.spca.android.iisc.SPCA.settings; + +import android.os.Bundle; + +import androidx.preference.PreferenceFragmentCompat; +import no.spca.android.iisc.R; + +public class SettingsFragment extends PreferenceFragmentCompat { + public static final String SETTINGS_DATA = "settings_template_data"; public static final int SETTINGS_VARIANT_A = 0; + public static final int SETTINGS_VARIANT_B = 1; + public static final int SETTINGS_VARIANT_DEFAULT = SETTINGS_VARIANT_A; + + @Override + public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { + addPreferencesFromResource(R.xml.settings_template); + } +} diff --git a/app/src/main/java/no/spca/android/iisc/SplashscreenActivity.java b/app/src/main/java/no/spca/android/iisc/SplashscreenActivity.java new file mode 100644 index 0000000..33262e7 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/SplashscreenActivity.java @@ -0,0 +1,104 @@ + +package no.spca.android.iisc; + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.nfc.NdefMessage; +import android.nfc.NdefRecord; +import android.nfc.NfcAdapter; +import android.os.Bundle; +import android.os.Parcelable; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.Button; + +import no.spca.android.iisc.SPCA.LoginScreen; +import no.spca.android.iisc.SPCA.MainActivity; + +public class SplashscreenActivity extends Activity { + + private static final int DELAY = 1000; + Animation btnAnim ; + Button btnGetStarted; + private static final int SPLASH_TIME_OUT=3000; + String number; + + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splashscreen); + SharedPreferences preferences6 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences6.getString("Phone", null); + + btnGetStarted=findViewById(R.id.started); + btnGetStarted.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + + if (number == null ) { + + + Intent home = new Intent(SplashscreenActivity.this, LoginScreen.class); + startActivity(home); + finish(); + } + else { + final Intent newIntent = new Intent(SplashscreenActivity.this, MainActivity.class); + newIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + // btnGetStarted.setAnimation(btnAnim); + + + final Intent intent = getIntent(); + if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { + final Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + if (rawMsgs != null) { + for (Parcelable rawMsg : rawMsgs) { + final NdefMessage msg = (NdefMessage) rawMsg; + final NdefRecord[] records = msg.getRecords(); + + for (NdefRecord record : records) { + if (record.getTnf() == NdefRecord.TNF_MIME_MEDIA) { + switch (record.toMimeType()) { + case FeaturesActivity.EXTRA_APP: + newIntent.putExtra(FeaturesActivity.EXTRA_APP, new String(record.getPayload())); + break; + case FeaturesActivity.EXTRA_ADDRESS: + newIntent.putExtra(FeaturesActivity.EXTRA_ADDRESS, invertEndianness(record.getPayload())); + break; + } + } + } + } + } + } + startActivity(newIntent); + finish(); + + } + } + }); + btnAnim = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.button_animation); + // btnGetStarted.setAnimation(btnAnim); + + + } + + @Override + public void onBackPressed() { + } + + + private byte[] invertEndianness(final byte[] bytes) { + if (bytes == null) + return null; + final int length = bytes.length; + final byte[] result = new byte[length]; + for (int i = 0; i < length; i++) + result[i] = bytes[length - i - 1]; + return result; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/adapter/AppAdapter.java b/app/src/main/java/no/spca/android/iisc/adapter/AppAdapter.java similarity index 58% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/adapter/AppAdapter.java rename to app/src/main/java/no/spca/android/iisc/adapter/AppAdapter.java index d9116d0..60582c9 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/adapter/AppAdapter.java +++ b/app/src/main/java/no/spca/android/iisc/adapter/AppAdapter.java @@ -1,25 +1,5 @@ -/* - * 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; + +package no.spca.android.iisc.adapter; import android.content.ComponentName; import android.content.Context; @@ -37,10 +17,11 @@ import java.util.Collections; import java.util.List; import java.util.Locale; -import no.nordicsemi.android.nrftoolbox.R; +import no.spca.android.iisc.R; + public class AppAdapter extends BaseAdapter { - private static final String CATEGORY = "no.nordicsemi.android.nrftoolbox.LAUNCHER"; + private static final String CATEGORY = "no.spca.android.iisc.LAUNCHER"; private static final String NRF_CONNECT_PACKAGE = "no.nordicsemi.android.mcp"; private final Context mContext; @@ -52,13 +33,11 @@ public class AppAdapter extends BaseAdapter { 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 (NRF_CONNECT_PACKAGE.equals(info.activityInfo.packageName)) { appList.remove(info); diff --git a/app/src/main/java/no/spca/android/iisc/app/ExpandableListActivity.java b/app/src/main/java/no/spca/android/iisc/app/ExpandableListActivity.java new file mode 100644 index 0000000..71b08f2 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/app/ExpandableListActivity.java @@ -0,0 +1,132 @@ + + +package no.spca.android.iisc.app; + +import android.app.Activity; +import android.database.Cursor; +import android.os.Bundle; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AppCompatActivity; +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; + +import java.util.List; +import java.util.Map; + +import no.spca.android.iisc.R; + + + +public class ExpandableListActivity extends AppCompatActivity implements + OnCreateContextMenuListener, + ExpandableListView.OnChildClickListener, ExpandableListView.OnGroupCollapseListener, + ExpandableListView.OnGroupExpandListener { + ExpandableListAdapter mAdapter; + ExpandableListView mList; + boolean mFinishedStart = false; + + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { + } + + + @Override + public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, + int childPosition, long id) { + return false; + } + + + @Override + public void onGroupCollapse(int groupPosition) { + } + + + @Override + public void onGroupExpand(int groupPosition) { + } + + + @Override + protected void onRestoreInstanceState(@NonNull Bundle state) { + ensureList(); + super.onRestoreInstanceState(state); + } + + + @Override + public void onContentChanged() { + super.onContentChanged(); + View emptyView ; + mList = findViewById(R.id.list); + if (mList == null) { + throw new RuntimeException( + "Your content must have a ExpandableListView whose id attribute is " + + "'R.id.list'"); + } + + mList.setOnChildClickListener(this); + mList.setOnGroupExpandListener(this); + mList.setOnGroupCollapseListener(this); + + if (mFinishedStart) { + setListAdapter(mAdapter); + } + mFinishedStart = true; + } + + + public void setListAdapter(ExpandableListAdapter adapter) { + synchronized (this) { + ensureList(); + mAdapter = adapter; + mList.setAdapter(adapter); + } + } + + + public ExpandableListView getExpandableListView() { + ensureList(); + return mList; + } + + + public ExpandableListAdapter getExpandableListAdapter() { + return mAdapter; + } + + private void ensureList() { + if (mList != null) { + return; + } + setContentView(R.layout.expandable_list_content); + } + + + public long getSelectedId() { + return mList.getSelectedId(); + } + + + public long getSelectedPosition() { + return mList.getSelectedPosition(); + } + + + public boolean setSelectedChild(int groupPosition, int childPosition, boolean shouldExpandGroup) { + return mList.setSelectedChild(groupPosition, childPosition, shouldExpandGroup); + } + + + public void setSelectedGroup(int groupPosition) { + mList.setSelectedGroup(groupPosition); + } + +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManager.java b/app/src/main/java/no/spca/android/iisc/battery/BatteryManager.java similarity index 80% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManager.java rename to app/src/main/java/no/spca/android/iisc/battery/BatteryManager.java index 5d5d6e6..2599eb1 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManager.java +++ b/app/src/main/java/no/spca/android/iisc/battery/BatteryManager.java @@ -1,4 +1,4 @@ -package no.nordicsemi.android.nrftoolbox.battery; +package no.spca.android.iisc.battery; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; @@ -15,35 +15,26 @@ import no.nordicsemi.android.ble.callback.DataReceivedCallback; import no.nordicsemi.android.ble.common.callback.battery.BatteryLevelDataCallback; import no.nordicsemi.android.ble.data.Data; import no.nordicsemi.android.log.LogContract; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; +import no.spca.android.iisc.profile.LoggableBleManager; + -/** - * The Ble Manager with Battery Service support. - * - * @param The profile callbacks type. - * @see BleManager - */ @SuppressWarnings("WeakerAccess") public abstract class BatteryManager extends LoggableBleManager { - /** Battery Service UUID. */ + private final static UUID BATTERY_SERVICE_UUID = UUID.fromString("0000180F-0000-1000-8000-00805f9b34fb"); - /** Battery Level characteristic UUID. */ + private final static UUID BATTERY_LEVEL_CHARACTERISTIC_UUID = UUID.fromString("00002A19-0000-1000-8000-00805f9b34fb"); private BluetoothGattCharacteristic mBatteryLevelCharacteristic; - /** Last received Battery Level value. */ + private Integer mBatteryLevel; - /** - * The manager constructor. - * - * @param context context. - */ + public BatteryManager(final Context context) { super(context); } - private DataReceivedCallback mBatteryLevelDataCallback = new BatteryLevelDataCallback() { + private final DataReceivedCallback mBatteryLevelDataCallback = new BatteryLevelDataCallback() { @Override public void onBatteryLevelChanged(@NonNull final BluetoothDevice device, final int batteryLevel) { log(LogContract.Log.Level.APPLICATION,"Battery Level received: " + batteryLevel + "%"); @@ -68,7 +59,6 @@ public abstract class BatteryManager extends public void enableBatteryLevelCharacteristicNotifications() { if (isConnected()) { - // If the Battery Level characteristic is null, the request will be ignored setNotificationCallback(mBatteryLevelCharacteristic) .with(mBatteryLevelDataCallback); enableNotifications(mBatteryLevelCharacteristic) @@ -78,9 +68,7 @@ public abstract class BatteryManager extends } } - /** - * Disables Battery Level notifications on the Server. - */ + public void disableBatteryLevelCharacteristicNotifications() { if (isConnected()) { disableNotifications(mBatteryLevelCharacteristic) @@ -89,11 +77,7 @@ public abstract class BatteryManager extends } } - /** - * Returns the last received Battery Level value. - * The value is set to null when the device disconnects. - * @return Battery Level value, in percent. - */ + public Integer getBatteryLevel() { return mBatteryLevel; } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManagerCallbacks.java b/app/src/main/java/no/spca/android/iisc/battery/BatteryManagerCallbacks.java similarity index 82% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManagerCallbacks.java rename to app/src/main/java/no/spca/android/iisc/battery/BatteryManagerCallbacks.java index 26a2905..a0478e3 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/battery/BatteryManagerCallbacks.java +++ b/app/src/main/java/no/spca/android/iisc/battery/BatteryManagerCallbacks.java @@ -1,4 +1,4 @@ -package no.nordicsemi.android.nrftoolbox.battery; +package no.spca.android.iisc.battery; import no.nordicsemi.android.ble.BleManagerCallbacks; import no.nordicsemi.android.ble.common.profile.battery.BatteryLevelCallback; diff --git a/app/src/main/java/no/spca/android/iisc/parser/CycleParser.java b/app/src/main/java/no/spca/android/iisc/parser/CycleParser.java new file mode 100644 index 0000000..281c748 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/parser/CycleParser.java @@ -0,0 +1,19 @@ +package no.spca.android.iisc.parser; + +import no.nordicsemi.android.ble.data.Data; + +public class CycleParser { + private static final byte HEART_RATE_VALUE_FORMAT = 0x01; @SuppressWarnings("UnusedAssignment") + public static String parse(final Data data) { + int offset = 0; + final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); + + + final boolean value16bit = (flags & HEART_RATE_VALUE_FORMAT) > 0; + + int value = data.getIntValue(value16bit ? Data.FORMAT_UINT16 : Data.FORMAT_UINT8, offset++); if (value16bit) + offset++; + + return "Cycle: " + value + " bpm"; + } +} diff --git a/app/src/main/java/no/spca/android/iisc/parser/TemperatureParser.java b/app/src/main/java/no/spca/android/iisc/parser/TemperatureParser.java new file mode 100644 index 0000000..f3f0bde --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/parser/TemperatureParser.java @@ -0,0 +1,23 @@ + +package no.spca.android.iisc.parser; + +import no.nordicsemi.android.ble.data.Data; + + + +@SuppressWarnings("ConstantConditions") +public class TemperatureParser { + private static final byte HEART_RATE_VALUE_FORMAT = 0x01; @SuppressWarnings("UnusedAssignment") + public static String parse(final Data data) { + int offset = 0; + final int flags = data.getIntValue(Data.FORMAT_UINT8, offset++); + + + final boolean value16bit = (flags & HEART_RATE_VALUE_FORMAT) > 0; + + int value = data.getIntValue(value16bit ? Data.FORMAT_UINT16 : Data.FORMAT_UINT8, offset++); if (value16bit) + offset++; + + return "Temprature: " + value + " bpm"; + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java b/app/src/main/java/no/spca/android/iisc/profile/BleProfileActivity.java similarity index 51% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java rename to app/src/main/java/no/spca/android/iisc/profile/BleProfileActivity.java index e9ea7ee..3661f42 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileActivity.java +++ b/app/src/main/java/no/spca/android/iisc/profile/BleProfileActivity.java @@ -1,25 +1,5 @@ -/* - * 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; + +package no.spca.android.iisc.profile; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -32,8 +12,7 @@ import android.os.Bundle; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; + import android.view.View; import android.widget.Button; import android.widget.TextView; @@ -45,10 +24,9 @@ import no.nordicsemi.android.ble.BleManagerCallbacks; 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; +import no.spca.android.iisc.R; +import no.spca.android.iisc.scanner.ScannerFragment; +import no.spca.android.iisc.DebugLogger; @SuppressWarnings("unused") public abstract class BleProfileActivity extends AppCompatActivity implements BleManagerCallbacks, ScannerFragment.OnDeviceSelectedListener { @@ -76,59 +54,32 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl 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(); - // In onInitialize method a final class may register local broadcast receivers that will listen for events from the service onInitialize(savedInstanceState); - // The onCreateView class should... create the view onCreateView(savedInstanceState); final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); setSupportActionBar(toolbar); - // Common nRF Toolbox view references are obtained here setUpView(); - // View is ready to be used 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, i.e. using {@link #setContentView(int)}. - * Use to obtain references to views. Connect/Disconnect button and the device name view are manager automatically. - * - * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. - * Note: Otherwise it is null. - */ + protected void onInitialize(final Bundle savedInstanceState) { + } + + 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 void onViewCreated(final Bundle savedInstanceState) { - // empty default implementation - } - /** - * Called after the view and the toolbar has been created. - */ + protected void onViewCreated(final Bundle savedInstanceState) { + } + + protected final void setUpView() { - // set GUI getSupportActionBar().setDisplayHomeAsUpEnabled(true); mConnectButton = findViewById(R.id.action_connect); mDeviceNameView = findViewById(R.id.device_name); @@ -136,8 +87,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl @Override public void onBackPressed() { - mBleManager.disconnect().enqueue(); - super.onBackPressed(); + } @Override @@ -160,43 +110,16 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl } } - @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(getSupportFragmentManager(), "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) { @@ -210,29 +133,17 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl } } - /** - * 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; } - /** - * This method returns whether autoConnect option should be used. - * - * @return true to use autoConnect feature, false (default) otherwise. - */ + protected boolean shouldAutoConnect() { return false; } @@ -242,7 +153,6 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl 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); } @@ -257,8 +167,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl @Override public void onDialogCanceled() { - // do nothing - } + } @Override public void onDeviceConnecting(@NonNull final BluetoothDevice device) { @@ -296,13 +205,11 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl @Override public void onServicesDiscovered(@NonNull final BluetoothDevice device, boolean optionalServicesFound) { - // this may notify user or show some views - } + } @Override public void onDeviceReady(@NonNull final BluetoothDevice device) { - // empty default implementation - } + } @Override public void onBondingRequired(@NonNull final BluetoothDevice device) { @@ -330,80 +237,42 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl 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(() -> 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(() -> 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 LoggableBleManager 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(); - /** - * 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 - * @see #getFilterUUID() - */ + private void showDeviceScanningDialog(final UUID filter) { runOnUiThread(() -> { final ScannerFragment dialog = ScannerFragment.getInstance(filter); @@ -411,11 +280,7 @@ public abstract class BleProfileActivity extends AppCompatActivity implements Bl }); } - /** - * 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 - */ + protected ILogSession getLogSession() { return mLogSession; } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java b/app/src/main/java/no/spca/android/iisc/profile/BleProfileExpandableListActivity.java similarity index 52% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java rename to app/src/main/java/no/spca/android/iisc/profile/BleProfileExpandableListActivity.java index a7058bc..010f9ce 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileExpandableListActivity.java +++ b/app/src/main/java/no/spca/android/iisc/profile/BleProfileExpandableListActivity.java @@ -1,25 +1,5 @@ -/* - * 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; + +package no.spca.android.iisc.profile; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; @@ -31,8 +11,7 @@ import android.net.Uri; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.appcompat.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; + import android.view.View; import android.widget.Button; import android.widget.TextView; @@ -44,11 +23,10 @@ import no.nordicsemi.android.ble.BleManagerCallbacks; 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.app.ExpandableListActivity; -import no.nordicsemi.android.nrftoolbox.scanner.ScannerFragment; -import no.nordicsemi.android.nrftoolbox.utility.DebugLogger; +import no.spca.android.iisc.R; +import no.spca.android.iisc.app.ExpandableListActivity; +import no.spca.android.iisc.scanner.ScannerFragment; +import no.spca.android.iisc.DebugLogger; @SuppressWarnings("unused") public abstract class BleProfileExpandableListActivity extends ExpandableListActivity implements BleManagerCallbacks, ScannerFragment.OnDeviceSelectedListener { @@ -76,61 +54,34 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct 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(); - // In onInitialize method a final class may register local broadcast receivers that will listen for events from the service onInitialize(savedInstanceState); - // The onCreateView class should... create the view onCreateView(savedInstanceState); final Toolbar toolbar = findViewById(R.id.toolbar_actionbar); setSupportActionBar(toolbar); - // Common nRF Toolbox view references are obtained here setUpView(); - // View is ready to be used onViewCreated(savedInstanceState); } - /** - * You may do some initialization here. This method is called from {@link #onCreate(Bundle)} before the view was created. - */ + @SuppressWarnings("unused") protected void onInitialize(final Bundle savedInstanceState) { - // empty default implementation - } + } + - /** - * Called from {@link #onCreate(Bundle)}. This method should build the activity UI, i.e. using {@link #setContentView(int)}. - * Use to obtain references to views. Connect/Disconnect button and the device name 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. - */ + @SuppressWarnings("unused") protected void onViewCreated(final Bundle savedInstanceState) { - // empty default implementation - } + } + - /** - * Called after the view and the toolbar has been created. - */ protected final void setUpView() { - // set GUI getSupportActionBar().setDisplayHomeAsUpEnabled(true); mConnectButton = findViewById(R.id.action_connect); mDeviceNameView = findViewById(R.id.device_name); @@ -138,8 +89,7 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct @Override public void onBackPressed() { - mBleManager.disconnect().enqueue(); - super.onBackPressed(); + } @Override @@ -162,44 +112,17 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct } } - @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 - */ + + @SuppressWarnings("unused") 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(getSupportFragmentManager(), "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) { @@ -213,29 +136,17 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct } } - /** - * 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; } - /** - * This method returns whether autoConnect option should be used. - * - * @return true to use autoConnect feature, false (default) otherwise. - */ + protected boolean shouldAutoConnect() { return false; } @@ -245,7 +156,6 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct 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); } @@ -260,8 +170,7 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct @Override public void onDialogCanceled() { - // do nothing - } + } @Override public void onDeviceConnecting(@NonNull final BluetoothDevice device) { @@ -299,13 +208,11 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct @Override public void onServicesDiscovered(@NonNull final BluetoothDevice device, boolean optionalServicesFound) { - // this may notify user or show some views - } + } @Override public void onDeviceReady(@NonNull final BluetoothDevice device) { - // empty default implementation - } + } @Override public void onBondingRequired(@NonNull final BluetoothDevice device) { @@ -333,80 +240,42 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct 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(() -> 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(() -> 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 LoggableBleManager 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(); - /** - * 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 - * @see #getFilterUUID() - */ + private void showDeviceScanningDialog(final UUID filter) { runOnUiThread(() -> { final ScannerFragment dialog = ScannerFragment.getInstance(filter); @@ -414,11 +283,7 @@ public abstract class BleProfileExpandableListActivity extends ExpandableListAct }); } - /** - * 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 - */ + protected ILogSession getLogSession() { return mLogSession; } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java b/app/src/main/java/no/spca/android/iisc/profile/BleProfileService.java similarity index 56% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java rename to app/src/main/java/no/spca/android/iisc/profile/BleProfileService.java index e63c377..0490b2d 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileService.java +++ b/app/src/main/java/no/spca/android/iisc/profile/BleProfileService.java @@ -1,25 +1,5 @@ -/* - * 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; + +package no.spca.android.iisc.profile; import android.app.Service; import android.bluetooth.BluetoothAdapter; @@ -50,28 +30,28 @@ public abstract class BleProfileService extends Service implements BleManagerCal @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_DEVICE_READY = "no.nordicsemi.android.nrftoolbox.DEVICE_READY"; - public static final String BROADCAST_BOND_STATE = "no.nordicsemi.android.nrftoolbox.BROADCAST_BOND_STATE"; + public static final String BROADCAST_CONNECTION_STATE = "no.spca.android.iisc.BROADCAST_CONNECTION_STATE"; + public static final String BROADCAST_SERVICES_DISCOVERED = "no.spca.android.iisc.BROADCAST_SERVICES_DISCOVERED"; + public static final String BROADCAST_DEVICE_READY = "no.spca.android.iisc.DEVICE_READY"; + public static final String BROADCAST_BOND_STATE = "no.spca.android.iisc.BROADCAST_BOND_STATE"; @Deprecated - 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"; + public static final String BROADCAST_BATTERY_LEVEL = "no.spca.android.iisc.BROADCAST_BATTERY_LEVEL"; + public static final String BROADCAST_ERROR = "no.spca.android.iisc.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_DEVICE = "no.nordicsemi.android.nrftoolbox.EXTRA_DEVICE"; - 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_DEVICE_ADDRESS = "no.spca.android.iisc.EXTRA_DEVICE_ADDRESS"; + + public static final String EXTRA_DEVICE_NAME = "no.spca.android.iisc.EXTRA_DEVICE_NAME"; + public static final String EXTRA_DEVICE = "no.spca.android.iisc.EXTRA_DEVICE"; + public static final String EXTRA_LOG_URI = "no.spca.android.iisc.EXTRA_LOG_URI"; + public static final String EXTRA_CONNECTION_STATE = "no.spca.android.iisc.EXTRA_CONNECTION_STATE"; + public static final String EXTRA_BOND_STATE = "no.spca.android.iisc.EXTRA_BOND_STATE"; + public static final String EXTRA_SERVICE_PRIMARY = "no.spca.android.iisc.EXTRA_SERVICE_PRIMARY"; + public static final String EXTRA_SERVICE_SECONDARY = "no.spca.android.iisc.EXTRA_SERVICE_SECONDARY"; @Deprecated - 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 String EXTRA_BATTERY_LEVEL = "no.spca.android.iisc.EXTRA_BATTERY_LEVEL"; + public static final String EXTRA_ERROR_MESSAGE = "no.spca.android.iisc.EXTRA_ERROR_MESSAGE"; + public static final String EXTRA_ERROR_CODE = "no.spca.android.iisc.EXTRA_ERROR_CODE"; public static final int STATE_LINK_LOSS = -1; public static final int STATE_DISCONNECTED = 0; @@ -125,9 +105,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal }; public class LocalBinder extends Binder implements ILogger { - /** - * Disconnects from the sensor. - */ + public final void disconnect() { final int state = mBleManager.getConnectionState(); if (state == BluetoothGatt.STATE_DISCONNECTED || state == BluetoothGatt.STATE_DISCONNECTING) { @@ -139,67 +117,38 @@ public abstract class BleProfileService extends Service implements BleManagerCal mBleManager.disconnect().enqueue(); } - /** - * Sets whether the bound activity if changing configuration or not. - * If false, we will turn off battery level notifications in onUnbind(..) method below. - * @param changing true if the bound activity is finishing - */ + public void setActivityIsChangingConfiguration(final boolean changing) { mActivityIsChangingConfiguration = changing; } - /** - * Returns the device address - * - * @return device address - */ + public String getDeviceAddress() { return mBluetoothDevice.getAddress(); } - /** - * Returns the device name - * - * @return the device name - */ + public String getDeviceName() { return mDeviceName; } - /** - * Returns the Bluetooth device - * - * @return the Bluetooth device - */ + public BluetoothDevice getBluetoothDevice() { return mBluetoothDevice; } - /** - * 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 mBleManager.isConnected(); } - /** - * Returns the connection state of given device. - * @return the connection state, as in {@link BleManager#getConnectionState()}. - */ + public int getConnectionState() { return mBleManager.getConnectionState(); } - /** - * 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 - */ + public ILogSession getLogSession() { return mLogSession; } @@ -215,21 +164,13 @@ public abstract class BleProfileService extends Service implements BleManagerCal } } - /** - * Returns a handler that is created in onCreate(). - * The handler may be used to postpone execution of some operations or to run them in UI thread. - */ + protected Handler getHandler() { return mHandler; } - /** - * Returns the binder implementation. This must return class implementing the additional manager interface that may be used in the bound 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(); } @@ -247,14 +188,9 @@ public abstract class BleProfileService extends Service implements BleManagerCal onRebind(); } - /** - * Called when the activity has rebound to the service after being recreated. - * This method is not called when the activity was killed to be recreated when the phone orientation changed - * if prior to being killed called {@link BleProfileService.LocalBinder#setActivityIsChangingConfiguration(boolean)} with parameter true. - */ + protected void onRebind() { - // empty default implementation - } + } @Override public final boolean onUnbind(final Intent intent) { @@ -263,17 +199,12 @@ public abstract class BleProfileService extends Service implements BleManagerCal if (!mActivityIsChangingConfiguration) onUnbind(); - // We want the onRebind method be called if anything else binds to it again return true; } - /** - * Called when the activity has unbound from the service before being finished. - * This method is not called when the activity is killed to be recreated when the phone orientation changed. - */ + protected void onUnbind() { - // empty default implementation - } + } @SuppressWarnings("unchecked") @Override @@ -282,42 +213,28 @@ public abstract class BleProfileService extends Service implements BleManagerCal mHandler = new Handler(); - // Initialize the manager mBleManager = initializeManager(); mBleManager.setGattCallbacks(this); - // Register broadcast receivers registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); - // Service has now been created onServiceCreated(); - // Call onBluetoothEnabled if Bluetooth enabled final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter.isEnabled()) { onBluetoothEnabled(); } } - /** - * Called when the service has been created, before the {@link #onBluetoothEnabled()} is called. - */ - protected void onServiceCreated() { - // empty default implementation - } - /** - * Initializes the Ble Manager responsible for connecting to a single device. - * @return a new BleManager object - */ + protected void onServiceCreated() { + } + + @SuppressWarnings("rawtypes") protected abstract LoggableBleManager initializeManager(); - /** - * This method returns whether autoConnect option should be used. - * - * @return true to use autoConnect feature, false (default) otherwise. - */ + protected boolean shouldAutoConnect() { return false; } @@ -346,30 +263,21 @@ public abstract class BleProfileService extends Service implements BleManagerCal return START_REDELIVER_INTENT; } - /** - * Called when the service has been started. The device name and address are set. - * The BLE Manager will try to connect to the device after this method finishes. - */ + protected void onServiceStarted() { - // empty default implementation - } + } @Override public void onTaskRemoved(final Intent rootIntent) { super.onTaskRemoved(rootIntent); - // This method is called when user removed the app from Recents. - // By default, the service will be killed and recreated immediately after that. - // However, all managed devices will be lost and devices will be disconnected. stopSelf(); } @Override public void onDestroy() { super.onDestroy(); - // Unregister broadcast receivers unregisterReceiver(mBluetoothStateBroadcastReceiver); - // shutdown the manager mBleManager.close(); Logger.i(mLogSession, "Service destroyed"); mBleManager = null; @@ -379,21 +287,13 @@ public abstract class BleProfileService extends Service implements BleManagerCal mHandler = null; } - /** - * Method called when Bluetooth Adapter has been disabled. - */ - protected void onBluetoothDisabled() { - // empty default implementation - } - /** - * This method is called when Bluetooth Adapter has been enabled and - * after the service was created if Bluetooth Adapter was enabled at that moment. - * This method could initialize all Bluetooth related features, for example open the GATT server. - */ + protected void onBluetoothDisabled() { + } + + protected void onBluetoothEnabled() { - // empty default implementation - } + } @Override public void onDeviceConnecting(@NonNull final BluetoothDevice device) { @@ -414,30 +314,19 @@ public abstract class BleProfileService extends Service implements BleManagerCal @Override public void onDeviceDisconnecting(@NonNull final BluetoothDevice device) { - // Notify user about changing the state to DISCONNECTING final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING); LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); } - /** - * This method should return false if the service needs to do some asynchronous work after if has disconnected from the device. - * In that case the {@link #stopService()} method must be called when done. - * @return true (default) to automatically stop the service when device is disconnected. False otherwise. - */ + protected boolean stopWhenDisconnected() { return true; } @Override public void onDeviceDisconnected(@NonNull final BluetoothDevice device) { - // Note 1: Do not use the device argument here unless you change calling onDeviceDisconnected from the binder above - - // Note 2: if BleManager#shouldAutoConnect() for this device returned true, this callback will be - // invoked ONLY when user requested disconnection (using Disconnect button). If the device - // disconnects due to a link loss, the onLinkLossOccurred(BluetoothDevice) method will be called instead. - final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED); @@ -448,7 +337,6 @@ public abstract class BleProfileService extends Service implements BleManagerCal } protected void stopService() { - // user requested disconnection. We must stop the service Logger.v(mLogSession, "Stopping service..."); stopSelf(); } @@ -485,8 +373,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal 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(@NonNull final BluetoothDevice device, final int value) { @@ -498,7 +385,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal @Override public void onBondingRequired(@NonNull final BluetoothDevice device) { - showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding); + showToast(no.spca.android.iisc.R.string.bonding); final Intent broadcast = new Intent(BROADCAST_BOND_STATE); broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); @@ -508,7 +395,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal @Override public void onBonded(@NonNull final BluetoothDevice device) { - showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded); + showToast(no.spca.android.iisc.R.string.bonding); final Intent broadcast = new Intent(BROADCAST_BOND_STATE); broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); @@ -518,7 +405,7 @@ public abstract class BleProfileService extends Service implements BleManagerCal @Override public void onBondingFailed(@NonNull final BluetoothDevice device) { - showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding_failed); + showToast(no.spca.android.iisc.R.string.bonding_failed); final Intent broadcast = new Intent(BROADCAST_BOND_STATE); broadcast.putExtra(EXTRA_DEVICE, mBluetoothDevice); @@ -535,68 +422,37 @@ public abstract class BleProfileService extends Service implements BleManagerCal LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); } - /** - * 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(() -> 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(() -> 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 mBluetoothDevice.getAddress(); } - /** - * Returns the Bluetooth device object - * - * @return bluetooth device - */ + protected BluetoothDevice getBluetoothDevice() { return mBluetoothDevice; } - /** - * 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 mBleManager != null && mBleManager.isConnected(); } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java b/app/src/main/java/no/spca/android/iisc/profile/BleProfileServiceReadyActivity.java similarity index 55% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java rename to app/src/main/java/no/spca/android/iisc/profile/BleProfileServiceReadyActivity.java index ce2069b..1823d72 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/BleProfileServiceReadyActivity.java +++ b/app/src/main/java/no/spca/android/iisc/profile/BleProfileServiceReadyActivity.java @@ -1,25 +1,5 @@ -/* - * 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; + +package no.spca.android.iisc.profile; import android.app.Service; import android.bluetooth.BluetoothAdapter; @@ -38,9 +18,7 @@ import android.os.IBinder; import androidx.annotation.NonNull; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; + import android.view.View; import android.widget.Button; import android.widget.TextView; @@ -52,25 +30,13 @@ import no.nordicsemi.android.ble.BleManagerCallbacks; 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; +import no.spca.android.iisc.R; +import no.spca.android.iisc.scanner.ScannerFragment; +import no.spca.android.iisc.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. - *

- */ @SuppressWarnings("unused") -public abstract class BleProfileServiceReadyActivity extends AppCompatActivity implements +public abstract class BleProfileServiceReadyActivity extends AppCompatActivity implements ScannerFragment.OnDeviceSelectedListener, BleManagerCallbacks { private static final String TAG = "BleProfileServiceReadyActivity"; @@ -91,7 +57,6 @@ public abstract class BleProfileServiceReadyActivity 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 E 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, i.e. using {@link #setContentView(int)}. - * Use to obtain references to views. Connect/Disconnect button, the device name view are manager automatically. - * - * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. - * Note: Otherwise it is null. - */ + protected void onInitialize(final Bundle savedInstanceState) { + } + + 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 void onViewCreated(final Bundle savedInstanceState) { - // empty default implementation - } - /** - * Called after the view and the toolbar has been created. - */ + protected void onViewCreated(final Bundle savedInstanceState) { + } + + protected final void setUpView() { - // set GUI - getSupportActionBar().setDisplayHomeAsUpEnabled(true); mConnectButton = findViewById(R.id.action_connect); mDeviceNameView = findViewById(R.id.device_name); } @@ -384,43 +285,15 @@ public abstract class BleProfileServiceReadyActivitytrue 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(getSupportFragmentManager(), "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) { @@ -434,20 +307,12 @@ public abstract class BleProfileServiceReadyActivity 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); } @@ -465,7 +329,6 @@ public abstract class BleProfileServiceReadyActivity 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(() -> 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 && mService.isConnected(); } - /** - * 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(); - /** - * Checks the {@link BleProfileService#EXTRA_DEVICE} in the given intent and compares it with the connected BluetoothDevice object. - * @param intent intent received via a broadcast from the service - * @return true if the data in the intent apply to the connected device, false otherwise - */ + protected boolean isBroadcastForThisDevice(final Intent intent) { final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(BleProfileService.EXTRA_DEVICE); return mBluetoothDevice != null && mBluetoothDevice.equals(bluetoothDevice); } - /** - * 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 - * @see #getFilterUUID() - */ + private void showDeviceScanningDialog(final UUID filter) { final ScannerFragment dialog = ScannerFragment.getInstance(filter); dialog.show(getSupportFragmentManager(), "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 - */ + protected ILogSession getLogSession() { return mLogSession; } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/LoggableBleManager.java b/app/src/main/java/no/spca/android/iisc/profile/LoggableBleManager.java similarity index 62% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/LoggableBleManager.java rename to app/src/main/java/no/spca/android/iisc/profile/LoggableBleManager.java index 1b4685c..91a628e 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/LoggableBleManager.java +++ b/app/src/main/java/no/spca/android/iisc/profile/LoggableBleManager.java @@ -1,4 +1,4 @@ -package no.nordicsemi.android.nrftoolbox.profile; +package no.spca.android.iisc.profile; import android.content.Context; import androidx.annotation.NonNull; @@ -11,31 +11,16 @@ import no.nordicsemi.android.log.ILogSession; import no.nordicsemi.android.log.LogContract; import no.nordicsemi.android.log.Logger; -/** - * The manager that logs to nRF Logger. If nRF Logger is not installed, logs are ignored. - * - * @param the callbacks class. - */ + public abstract class LoggableBleManager extends BleManager { private ILogSession mLogSession; - /** - * The manager constructor. - *

- * After constructing the manager, the callbacks object must be set with - * {@link #setGattCallbacks(BleManagerCallbacks)}. - * - * @param context the context. - */ + public LoggableBleManager(@NonNull final Context context) { super(context); } - /** - * Sets the log session to log into. - * - * @param session nRF Logger log session to log inti, or null, if nRF Logger is not installed. - */ + public void setLogger(@Nullable final ILogSession session) { mLogSession = session; } diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileService.java b/app/src/main/java/no/spca/android/iisc/profile/multiconnect/BleMulticonnectProfileService.java similarity index 54% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileService.java rename to app/src/main/java/no/spca/android/iisc/profile/multiconnect/BleMulticonnectProfileService.java index 9d651f8..bb83817 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileService.java +++ b/app/src/main/java/no/spca/android/iisc/profile/multiconnect/BleMulticonnectProfileService.java @@ -1,25 +1,5 @@ -/* - * 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.multiconnect; + +package no.spca.android.iisc.profile.multiconnect; import android.app.Service; import android.bluetooth.BluetoothAdapter; @@ -47,29 +27,30 @@ import no.nordicsemi.android.ble.BleManager; import no.nordicsemi.android.ble.BleManagerCallbacks; import no.nordicsemi.android.ble.utils.ILogger; import no.nordicsemi.android.log.ILogSession; -import no.nordicsemi.android.nrftoolbox.profile.LoggableBleManager; +import no.spca.android.iisc.R; +import no.spca.android.iisc.profile.LoggableBleManager; public abstract class BleMulticonnectProfileService extends Service implements BleManagerCallbacks { @SuppressWarnings("unused") private static final String TAG = "BleMultiProfileService"; - 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_DEVICE_READY = "no.nordicsemi.android.nrftoolbox.DEVICE_READY"; - public static final String BROADCAST_BOND_STATE = "no.nordicsemi.android.nrftoolbox.BROADCAST_BOND_STATE"; + public static final String BROADCAST_CONNECTION_STATE = "no.spca.android.iisc.BROADCAST_CONNECTION_STATE"; + public static final String BROADCAST_SERVICES_DISCOVERED = "no.spca.android.iisc.BROADCAST_SERVICES_DISCOVERED"; + public static final String BROADCAST_DEVICE_READY = "no.spca.android.iisc.DEVICE_READY"; + public static final String BROADCAST_BOND_STATE = "no.spca.android.iisc.BROADCAST_BOND_STATE"; @Deprecated - 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"; + public static final String BROADCAST_BATTERY_LEVEL = "no.spca.android.iisc.BROADCAST_BATTERY_LEVEL"; + public static final String BROADCAST_ERROR = "no.spca.android.iisc.BROADCAST_ERROR"; - public static final String EXTRA_DEVICE = "no.nordicsemi.android.nrftoolbox.EXTRA_DEVICE"; - 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_DEVICE = "no.spca.android.iisc.EXTRA_DEVICE"; + public static final String EXTRA_CONNECTION_STATE = "no.spca.android.iisc.EXTRA_CONNECTION_STATE"; + public static final String EXTRA_BOND_STATE = "no.spca.android.iisc.EXTRA_BOND_STATE"; + public static final String EXTRA_SERVICE_PRIMARY = "no.spca.android.iisc.EXTRA_SERVICE_PRIMARY"; + public static final String EXTRA_SERVICE_SECONDARY = "no.spca.android.iisc.EXTRA_SERVICE_SECONDARY"; @Deprecated - 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 String EXTRA_BATTERY_LEVEL = "no.spca.android.iisc.EXTRA_BATTERY_LEVEL"; + public static final String EXTRA_ERROR_MESSAGE = "no.spca.android.iisc.EXTRA_ERROR_MESSAGE"; + public static final String EXTRA_ERROR_CODE = "no.spca.android.iisc.EXTRA_ERROR_CODE"; public static final int STATE_LINK_LOSS = -1; public static final int STATE_DISCONNECTED = 0; @@ -92,9 +73,6 @@ public abstract class BleMulticonnectProfileService extends Service implements B switch (state) { case BluetoothAdapter.STATE_ON: - // On older phones (tested on Nexus 4 with Android 5.0.1) the Bluetooth requires some time - // after it has been enabled before some operations can start. Starting the GATT server here - // without a delay is very likely to cause a DeadObjectException from BluetoothManager#openGattServer(...). mHandler.postDelayed(() -> onBluetoothEnabled(), 600); break; case BluetoothAdapter.STATE_TURNING_OFF: @@ -107,33 +85,19 @@ public abstract class BleMulticonnectProfileService extends Service implements B }; public class LocalBinder extends Binder implements ILogger, IDeviceLogger { - /** - * Returns an unmodifiable list of devices managed by the service. - * The returned devices do not need to be connected at tha moment. Each of them was however created - * using {@link #connect(BluetoothDevice)} method so they might have been connected before and disconnected. - * @return unmodifiable list of devices managed by the service - */ + public final List getManagedDevices() { return Collections.unmodifiableList(mManagedDevices); } - /** - * Connects to the given device. If the device is already connected this method does nothing. - * @param device target Bluetooth device - */ + public void connect(final BluetoothDevice device) { connect(device, null); } - /** - * Adds the given device to managed and stars connecting to it. If the device is already connected this method does nothing. - * @param device target Bluetooth device - * @param session log session that has to be used by the device - */ + @SuppressWarnings("unchecked") public void connect(final BluetoothDevice device, final ILogSession session) { - // If a device is in managed devices it means that it's already connected, or was connected - // using autoConnect and the link was lost but Android is already trying to connect to it. if (mManagedDevices.contains(device)) return; mManagedDevices.add(device); @@ -156,12 +120,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B } } - /** - * Disconnects the given device and removes the associated BleManager object. - * If the list of BleManagers is empty while the last activity unbinds from the service, - * the service will stop itself. - * @param device target device to disconnect and forget - */ + public void disconnect(final BluetoothDevice device) { final BleManager manager = mBleManagers.get(device); if (manager != null && manager.isConnected()) { @@ -170,54 +129,32 @@ public abstract class BleMulticonnectProfileService extends Service implements B mManagedDevices.remove(device); } - /** - * Returns true if the device is connected to the sensor. - * @param device the target device - * @return true if device is connected to the sensor, false otherwise - */ + public final boolean isConnected(final BluetoothDevice device) { final BleManager manager = mBleManagers.get(device); return manager != null && manager.isConnected(); } - /** - * Returns true if the device has finished initializing. - * @param device the target device - * @return true if device is connected to the sensor and has finished - * initializing. False otherwise. - */ + public final boolean isReady(final BluetoothDevice device) { final BleManager manager = mBleManagers.get(device); return manager != null && manager.isReady(); } - /** - * Returns the connection state of given device. - * @param device the target device - * @return the connection state, as in {@link BleManager#getConnectionState()}. - */ + public final int getConnectionState(final BluetoothDevice device) { final BleManager manager = mBleManagers.get(device); return manager != null ? manager.getConnectionState() : BluetoothGatt.STATE_DISCONNECTED; } - /** - * Returns the last received battery level value. - * @param device the device of which battery level should be returned - * @return battery value or -1 if no value was received or Battery Level characteristic was not found - * @deprecated Keep battery value in your manager instead. - */ + @Deprecated public int getBatteryValue(final BluetoothDevice device) { final BleManager manager = mBleManagers.get(device); return manager.getBatteryValue(); } - /** - * Sets whether the bound activity if changing configuration or not. - * If false, we will turn off battery level notifications in onUnbind(..) method below. - * @param changing true if the bound activity is finishing - */ + public final void setActivityIsChangingConfiguration(final boolean changing) { mActivityIsChangingConfiguration = changing; } @@ -249,21 +186,13 @@ public abstract class BleMulticonnectProfileService extends Service implements B } } - /** - * Returns a handler that is created in onCreate(). - * The handler may be used to postpone execution of some operations or to run them in UI thread. - */ + protected Handler getHandler() { return mHandler; } - /** - * Returns the binder implementation. This must return class implementing the additional manager interface that may be used in the bound 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(); } @@ -282,14 +211,9 @@ public abstract class BleMulticonnectProfileService extends Service implements B } } - /** - * Called when the activity has rebound to the service after being recreated. - * This method is not called when the activity was killed to be recreated when the phone orientation changed - * if prior to being killed called {@link LocalBinder#setActivityIsChangingConfiguration(boolean)} with parameter true. - */ + protected void onRebind() { - // empty default implementation - } + } @Override public final boolean onUnbind(final Intent intent) { @@ -299,22 +223,16 @@ public abstract class BleMulticonnectProfileService extends Service implements B if (!mManagedDevices.isEmpty()) { onUnbind(); } else { - // The last activity has disconnected from the service and there are no devices to manage. The service may be stopped. stopSelf(); } } - // We want the onRebind method be called if anything else binds to it again return true; } - /** - * Called when the activity has unbound from the service before being finished. - * This method is not called when the activity is killed to be recreated when the phone orientation changed. - */ + protected void onUnbind() { - // empty default implementation - } + } @Override public void onCreate() { @@ -322,58 +240,40 @@ public abstract class BleMulticonnectProfileService extends Service implements B mHandler = new Handler(); - // Initialize the map of BLE managers mBleManagers = new HashMap<>(); mManagedDevices = new ArrayList<>(); - // Register broadcast receivers registerReceiver(mBluetoothStateBroadcastReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); - // Service has now been created onServiceCreated(); - // Call onBluetoothEnabled if Bluetooth enabled final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); if (bluetoothAdapter.isEnabled()) { onBluetoothEnabled(); } } - /** - * Called when the service has been created, before the {@link #onBluetoothEnabled()} is called. - */ - protected void onServiceCreated() { - // empty default implementation - } - /** - * Initializes the Ble Manager responsible for connecting to a single device. - * @return a new BleManager object - */ + protected void onServiceCreated() { + } + + @SuppressWarnings("rawtypes") protected abstract LoggableBleManager initializeManager(); @Override public int onStartCommand(final Intent intent, final int flags, final int startId) { onServiceStarted(); - // The service does not save addresses of managed devices. - // A bound activity will be required to add connections again. return START_NOT_STICKY; } - /** - * Called when the service has been started. - */ + protected void onServiceStarted() { - // empty default implementation - } + } @Override public void onTaskRemoved(final Intent rootIntent) { super.onTaskRemoved(rootIntent); - // This method is called when user removed the app from Recents. - // By default, the service will be killed and recreated immediately after that. - // However, all managed devices will be lost and devices will be disconnected. stopSelf(); } @@ -384,16 +284,11 @@ public abstract class BleMulticonnectProfileService extends Service implements B mHandler = null; } - /** - * Called when the service has been stopped. - */ + protected void onServiceStopped() { - // Unregister broadcast receivers unregisterReceiver(mBluetoothStateBroadcastReceiver); - // The managers map may not be empty if the service was killed by the system for (final BleManager manager : mBleManagers.values()) { - // Service is being destroyed, no need to disconnect manually. manager.close(); manager.log(Log.INFO, "Service destroyed"); } @@ -403,20 +298,11 @@ public abstract class BleMulticonnectProfileService extends Service implements B mManagedDevices = null; } - /** - * Method called when Bluetooth Adapter has been disabled. - */ - protected void onBluetoothDisabled() { - // do nothing, BleManagers have their own Bluetooth State broadcast received and will close themselves - } - /** - * This method is called when Bluetooth Adapter has been enabled. It is also called - * after the service was created if Bluetooth Adapter was enabled at that moment. - * This method could initialize all Bluetooth related features, for example open the GATT server. - * Make sure you call super.onBluetoothEnabled() at this methods reconnects to - * devices that were connected before the Bluetooth was turned off. - */ + protected void onBluetoothDisabled() { + } + + protected void onBluetoothEnabled() { for (final BluetoothDevice device : mManagedDevices) { final BleManager manager = mBleManagers.get(device); @@ -451,22 +337,12 @@ public abstract class BleMulticonnectProfileService extends Service implements B @Override public void onDeviceDisconnected(final BluetoothDevice device) { - // Note: if BleManager#shouldAutoConnect() for this device returned true, this callback will be - // invoked ONLY when user requested disconnection (using Disconnect button). If the device - // disconnects due to a link loss, the onLinkLossOccurred(BluetoothDevice) method will be called instead. - - // We no longer want to keep the device in the service mManagedDevices.remove(device); - // The BleManager is not removed from the HashMap in order to keep the device's log session. - // mBleManagers.remove(device); - - // Do not use the device argument here unless you change calling onDeviceDisconnected from the binder above final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE); broadcast.putExtra(EXTRA_DEVICE, device); broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED); LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); - // When user disconnected the last device while the activity was not bound the service can be stopped if (!mBound && mManagedDevices.isEmpty()) { stopSelf(); } @@ -498,7 +374,6 @@ public abstract class BleMulticonnectProfileService extends Service implements B @Override public void onDeviceNotSupported(final BluetoothDevice device) { - // We don't like this device, remove it from both collections mManagedDevices.remove(device); mBleManagers.remove(device); @@ -508,8 +383,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B 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 BluetoothDevice device, final int value) { @@ -521,7 +395,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B @Override public void onBondingRequired(final BluetoothDevice device) { - showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding); + showToast(no.spca.android.iisc.R.string.bonding); final Intent broadcast = new Intent(BROADCAST_BOND_STATE); broadcast.putExtra(EXTRA_DEVICE, device); @@ -531,7 +405,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B @Override public void onBonded(final BluetoothDevice device) { - showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonded); + showToast(R.string.bonded); final Intent broadcast = new Intent(BROADCAST_BOND_STATE); broadcast.putExtra(EXTRA_DEVICE, device); @@ -541,7 +415,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B @Override public void onBondingFailed(final BluetoothDevice device) { - showToast(no.nordicsemi.android.nrftoolbox.common.R.string.bonding_failed); + showToast(R.string.bonding_failed); final Intent broadcast = new Intent(BROADCAST_BOND_STATE); broadcast.putExtra(EXTRA_DEVICE, device); @@ -558,48 +432,27 @@ public abstract class BleMulticonnectProfileService extends Service implements B LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast); } - /** - * 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(() -> Toast.makeText(BleMulticonnectProfileService.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(() -> Toast.makeText(BleMulticonnectProfileService.this, message, Toast.LENGTH_SHORT).show()); } - /** - * Returns the {@link BleManager} object associated with given device, or null if such has not been created. - * To create a BleManager call the {@link LocalBinder#connect(BluetoothDevice)} method must be called. - * @param device the target device - * @return the BleManager or null - */ + protected BleManager getBleManager(final BluetoothDevice device) { return mBleManagers.get(device); } - /** - * Returns unmodifiable list of all managed devices. They don't have to be connected at the moment. - * @return list of managed devices - */ + protected List getManagedDevices() { return Collections.unmodifiableList(mManagedDevices); } - /** - * Returns a list of those managed devices that are connected at the moment. - * @return list of connected devices - */ + protected List getConnectedDevices() { final List list = new ArrayList<>(); for (BluetoothDevice device : mManagedDevices) { @@ -609,11 +462,7 @@ public abstract class BleMulticonnectProfileService extends Service implements B return Collections.unmodifiableList(list); } - /** - * Returns true if the device is connected to the sensor. - * @param device the target device - * @return true if device is connected to the sensor, false otherwise - */ + protected boolean isConnected(final BluetoothDevice device) { final BleManager manager = mBleManagers.get(device); return manager != null && manager.isConnected(); diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java b/app/src/main/java/no/spca/android/iisc/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java similarity index 54% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java rename to app/src/main/java/no/spca/android/iisc/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java index d3bad57..e03b331 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java +++ b/app/src/main/java/no/spca/android/iisc/profile/multiconnect/BleMulticonnectProfileServiceReadyActivity.java @@ -1,25 +1,5 @@ -/* - * 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.multiconnect; + +package no.spca.android.iisc.profile.multiconnect; import android.app.Service; import android.bluetooth.BluetoothAdapter; @@ -39,8 +19,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; import android.view.View; import android.widget.Toast; @@ -53,26 +31,13 @@ import no.nordicsemi.android.ble.BleManagerCallbacks; 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; +import no.spca.android.iisc.R; +import no.spca.android.iisc.scanner.ScannerFragment; +import no.spca.android.iisc.DebugLogger; + -/** - *

- * The {@link BleMulticonnectProfileServiceReadyActivity} activity is designed to be the base class for profile activities that uses services in order to connect - * more than one device at the same time. A service extending {@link BleMulticonnectProfileService} is created when the activity is created, and the activity binds to it. - * The service returns a binder that may be used to connect, disconnect or manage devices, and notifies the - * activity using Local Broadcasts ({@link LocalBroadcastManager}). See {@link BleMulticonnectProfileService} for messages. If the device is not in range it will listen for - * it and connect when it become visible. The service exists until all managed devices have been disconnected and unmanaged and the last activity unbinds from it. - *

- *

- * When user closes the activity (e.g. by pressing Back button) while being connected, the Service remains working. It's remains connected to the devices or still - * listens for updates from them. When entering back to the activity, activity will to bind to the service and refresh UI. - *

- */ public abstract class BleMulticonnectProfileServiceReadyActivity extends AppCompatActivity implements - ScannerFragment.OnDeviceSelectedListener, BleManagerCallbacks { + ScannerFragment.OnDeviceSelectedListener, BleManagerCallbacks { private static final String TAG = "BleMulticonnectProfileServiceReadyActivity"; protected static final int REQUEST_ENABLE_BT = 2; @@ -111,7 +76,6 @@ public abstract class BleMulticonnectProfileServiceReadyActivity 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 E 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, i.e. using {@link #setContentView(int)}. - * Use to obtain references to views. Connect/Disconnect button and the device name view are manager automatically. - * - * @param savedInstanceState contains the data it most recently supplied in {@link #onSaveInstanceState(Bundle)}. - * Note: Otherwise it is null. - */ + protected void onInitialize(final Bundle savedInstanceState) { + } + + 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 void onViewCreated(final Bundle savedInstanceState) { - // empty default implementation - } - /** - * Called after the view and the toolbar has been created. - */ + protected void onViewCreated(final Bundle savedInstanceState) { + } + + protected final void setUpView() { - // set GUI getSupportActionBar().setDisplayHomeAsUpEnabled(true); } - @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(getSupportFragmentManager(), "help_fragment"); - break; - default: - return onOptionsItemSelected(id); - } - return true; - } - /** - * Called when user press ADD DEVICE button. See layout files -> onClick attribute. - */ + + + + public void onAddDeviceClicked(final View view) { if (isBLEEnabled()) { showDeviceScanningDialog(getFilterUUID()); @@ -366,20 +255,12 @@ public abstract class BleMulticonnectProfileServiceReadyActivity 0) { logSession = Logger.newSession(getApplicationContext(), getString(titleId), device.getAddress(), name); - // If nRF Logger is not installed we may want to use local logger if (logSession == null && getLocalAuthorityLogger() != null) { logSession = LocalLogSession.newSession(getApplicationContext(), getLocalAuthorityLogger(), device.getAddress(), name); } @@ -401,48 +281,39 @@ public abstract class BleMulticonnectProfileServiceReadyActivity Toast.makeText(BleMulticonnectProfileServiceReadyActivity.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(() -> Toast.makeText(BleMulticonnectProfileServiceReadyActivity.this, messageResId, Toast.LENGTH_SHORT).show()); } - /** - * 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(); - /** - * Returns unmodifiable list of managed devices. Managed device is a device the was selected on ScannerFragment until it's removed from the managed list. - * It does not have to be connected at that moment. - * @return unmodifiable list of managed devices - */ + protected List getManagedDevices() { return Collections.unmodifiableList(mManagedDevices); } - /** - * Returns true if the device is connected. Services may not have been discovered yet. - * @param device the device to check if it's connected - */ + protected boolean isDeviceConnected(final BluetoothDevice device) { return mService != null && mService.isConnected(device); } - /** - * 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 - * @see #getFilterUUID() - */ + private void showDeviceScanningDialog(final UUID filter) { final ScannerFragment dialog = ScannerFragment.getInstance(filter); dialog.show(getSupportFragmentManager(), "scan_fragment"); diff --git a/app/src/main/java/no/spca/android/iisc/profile/multiconnect/IDeviceLogger.java b/app/src/main/java/no/spca/android/iisc/profile/multiconnect/IDeviceLogger.java new file mode 100644 index 0000000..5a20c59 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/profile/multiconnect/IDeviceLogger.java @@ -0,0 +1,14 @@ + + +package no.spca.android.iisc.profile.multiconnect; + +import android.bluetooth.BluetoothDevice; +import androidx.annotation.StringRes; + +public interface IDeviceLogger { + + void log(final BluetoothDevice device, final int level, final String message); + + + void log(final BluetoothDevice device, final int level, @StringRes final int messageRes, final Object... params); +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java b/app/src/main/java/no/spca/android/iisc/scanner/DeviceListAdapter.java similarity index 67% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java rename to app/src/main/java/no/spca/android/iisc/scanner/DeviceListAdapter.java index cae8572..785726f 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/DeviceListAdapter.java +++ b/app/src/main/java/no/spca/android/iisc/scanner/DeviceListAdapter.java @@ -1,25 +1,5 @@ -/* - * 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; + +package no.spca.android.iisc.scanner; import android.bluetooth.BluetoothDevice; import android.content.Context; @@ -34,12 +14,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Set; -import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.support.v18.scanner.ScanResult; +import no.spca.android.iisc.R; + -/** - * 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; @@ -53,10 +31,7 @@ public class DeviceListAdapter extends BaseAdapter { mContext = context; } - /** - * Sets a list of bonded devices. - * @param devices list of bonded devices. - */ + public void addBondedDevices(final Set devices) { final List bondedDevices = mListBondedValues; for (BluetoothDevice device : devices) { @@ -65,10 +40,7 @@ public class DeviceListAdapter extends BaseAdapter { notifyDataSetChanged(); } - /** - * Updates the list of not bonded devices. - * @param results list of results from the scanner - */ + public void update(final List results) { for (final ScanResult result : results) { final ExtendedBluetoothDevice device = findDevice(result); @@ -99,17 +71,14 @@ public class DeviceListAdapter extends BaseAdapter { @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) + final int bondedCount = mListBondedValues.size() + 1; final int availableCount = mListValues.isEmpty() ? 2 : mListValues.size() + 1; 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()) { + final int bondedCount = mListBondedValues.size() + 1; if (mListBondedValues.isEmpty()) { if (position == 0) return R.string.scanner_subtitle_not_bonded; else diff --git a/app/src/main/java/no/spca/android/iisc/scanner/ExtendedBluetoothDevice.java b/app/src/main/java/no/spca/android/iisc/scanner/ExtendedBluetoothDevice.java new file mode 100644 index 0000000..0f9f082 --- /dev/null +++ b/app/src/main/java/no/spca/android/iisc/scanner/ExtendedBluetoothDevice.java @@ -0,0 +1,33 @@ + +package no.spca.android.iisc.scanner; + +import android.bluetooth.BluetoothDevice; + +import no.nordicsemi.android.support.v18.scanner.ScanResult; + +public class ExtendedBluetoothDevice { + static final int NO_RSSI = -1000; + public final BluetoothDevice device; + + public String name; + public int rssi; + public boolean isBonded; + + public ExtendedBluetoothDevice(final ScanResult scanResult) { + this.device = scanResult.getDevice(); + this.name = scanResult.getScanRecord() != null ? scanResult.getScanRecord().getDeviceName() : null; + this.rssi = scanResult.getRssi(); + this.isBonded = false; + } + + public ExtendedBluetoothDevice(final BluetoothDevice device) { + this.device = device; + this.name = device.getName(); + this.rssi = NO_RSSI; + this.isBonded = true; + } + + public boolean matches(final ScanResult scanResult) { + return device.getAddress().equals(scanResult.getDevice().getAddress()); + } +} diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java b/app/src/main/java/no/spca/android/iisc/scanner/ScannerFragment.java similarity index 60% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java rename to app/src/main/java/no/spca/android/iisc/scanner/ScannerFragment.java index 65727d2..8bb87cc 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/scanner/ScannerFragment.java +++ b/app/src/main/java/no/spca/android/iisc/scanner/ScannerFragment.java @@ -1,25 +1,5 @@ -/* - * 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; + +package no.spca.android.iisc.scanner; import android.Manifest; import android.app.Dialog; @@ -48,29 +28,21 @@ import java.util.List; import java.util.Set; import java.util.UUID; -import no.nordicsemi.android.nrftoolbox.R; import no.nordicsemi.android.support.v18.scanner.BluetoothLeScannerCompat; import no.nordicsemi.android.support.v18.scanner.ScanCallback; import no.nordicsemi.android.support.v18.scanner.ScanFilter; import no.nordicsemi.android.support.v18.scanner.ScanResult; import no.nordicsemi.android.support.v18.scanner.ScanSettings; +import no.spca.android.iisc.R; + -/** - * 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 to scan - * 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 long SCAN_DURATION = 5000; - private final static int REQUEST_PERMISSION_REQ_CODE = 34; // any 8-bit number - - private BluetoothAdapter mBluetoothAdapter; + private final static int REQUEST_PERMISSION_REQ_CODE = 34; private BluetoothAdapter mBluetoothAdapter; private OnDeviceSelectedListener mListener; private DeviceListAdapter mAdapter; private final Handler mHandler = new Handler(); @@ -92,31 +64,16 @@ public class ScannerFragment extends DialogFragment { return fragment; } - /** - * Interface required to be implemented by activity. - */ + public 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, i.e. Sony Xperia Z1 (C6903) with Android 4.3. - * The name has to be parsed manually form the Advertisement packet. - */ + void onDeviceSelected(final BluetoothDevice device, final String name); - /** - * Fired when scanner dialog has been cancelled without selecting a device. - */ + void onDialogCanceled(); } - /** - * This will make sure that {@link OnDeviceSelectedListener} interface is implemented by activity. - */ + @Override public void onAttach(final Context context) { super.onAttach(context); @@ -167,9 +124,7 @@ public class ScannerFragment extends DialogFragment { mListener.onDeviceSelected(d.device, d.name); }); - mPermissionRationale = dialogView.findViewById(R.id.permission_rationale); // this is not null only on API23+ - - mScanButton = dialogView.findViewById(R.id.action_cancel); + mPermissionRationale = dialogView.findViewById(R.id.permission_rationale); mScanButton = dialogView.findViewById(R.id.action_cancel); mScanButton.setOnClickListener(v -> { if (v.getId() == R.id.action_cancel) { if (mIsScanning) { @@ -198,7 +153,6 @@ public class ScannerFragment extends DialogFragment { switch (requestCode) { case REQUEST_PERMISSION_REQ_CODE: { if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // We have been granted the Manifest.permission.ACCESS_COARSE_LOCATION permission. Now we may proceed with scanning. startScan(); } else { mPermissionRationale.setVisibility(View.VISIBLE); @@ -209,27 +163,18 @@ public class ScannerFragment extends DialogFragment { } } - /** - * 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() { - // Since Android 6.0 we need to obtain either Manifest.permission.ACCESS_COARSE_LOCATION or Manifest.permission.ACCESS_FINE_LOCATION to be able to scan for - // Bluetooth LE devices. This is related to beacons as proximity devices. - // On API older than Marshmallow the following code does nothing. - if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - // When user pressed Deny and still wants to use this functionality, show the rationale + if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { if (ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) && mPermissionRationale.getVisibility() == View.GONE) { mPermissionRationale.setVisibility(View.VISIBLE); return; } - requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, REQUEST_PERMISSION_REQ_CODE); + requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSION_REQ_CODE); return; } - // Hide the rationale message, we don't need it anymore. if (mPermissionRationale != null) mPermissionRationale.setVisibility(View.GONE); @@ -243,7 +188,6 @@ public class ScannerFragment extends DialogFragment { final List filters = new ArrayList<>(); filters.add(new ScanFilter.Builder().setServiceUuid(mUuid).build()); scanner.startScan(filters, settings, scanCallback); - mIsScanning = true; mHandler.postDelayed(() -> { if (mIsScanning) { @@ -252,9 +196,7 @@ public class ScannerFragment extends DialogFragment { }, SCAN_DURATION); } - /** - * Stop scan if user tap Cancel button - */ + private void stopScan() { if (mIsScanning) { mScanButton.setText(R.string.scanner_action_scan); @@ -266,11 +208,10 @@ public class ScannerFragment extends DialogFragment { } } - private ScanCallback scanCallback = new ScanCallback() { + private final ScanCallback scanCallback = new ScanCallback() { @Override public void onScanResult(final int callbackType, final ScanResult result) { - // do nothing - } + } @Override public void onBatchScanResults(final List results) { @@ -279,8 +220,7 @@ public class ScannerFragment extends DialogFragment { @Override public void onScanFailed(final int errorCode) { - // should never be called - } + } }; private void addBoundDevices() { diff --git a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ForegroundRelativeLayout.java b/app/src/main/java/no/spca/android/iisc/widget/ForegroundRelativeLayout.java similarity index 62% rename from app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ForegroundRelativeLayout.java rename to app/src/main/java/no/spca/android/iisc/widget/ForegroundRelativeLayout.java index c3aa280..cb9fd0f 100644 --- a/app/src/main/java/no/nordicsemi/android/nrftoolbox/widget/ForegroundRelativeLayout.java +++ b/app/src/main/java/no/spca/android/iisc/widget/ForegroundRelativeLayout.java @@ -1,26 +1,6 @@ -/************************************************************************************************************************************************* - * 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; + +package no.spca.android.iisc.widget; import android.annotation.TargetApi; import android.content.Context; @@ -34,7 +14,8 @@ import androidx.annotation.NonNull; import android.util.AttributeSet; import android.widget.RelativeLayout; -import no.nordicsemi.android.nrftoolbox.R; +import no.spca.android.iisc.R; + public class ForegroundRelativeLayout extends RelativeLayout { diff --git a/app/src/main/res/anim/button_animation.xml b/app/src/main/res/anim/button_animation.xml new file mode 100644 index 0000000..9eed840 --- /dev/null +++ b/app/src/main/res/anim/button_animation.xml @@ -0,0 +1,16 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/animator/click_animator.xml b/app/src/main/res/animator/click_animator.xml deleted file mode 100644 index 7b316a4..0000000 --- a/app/src/main/res/animator/click_animator.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/color/button_color.xml b/app/src/main/res/color/button_color.xml deleted file mode 100644 index 2c87a8e..0000000 --- a/app/src/main/res/color/button_color.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/color/menu_text.xml b/app/src/main/res/color/menu_text.xml deleted file mode 100644 index c6d777f..0000000 --- a/app/src/main/res/color/menu_text.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - diff --git a/app/src/main/res/drawable-hdpi/battery.png b/app/src/main/res/drawable-hdpi/battery.png deleted file mode 100644 index dd83f9bbaa1b65990f0f0427ff2480e51ac8957c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/app/src/main/res/drawable-hdpi/dst_logo.png b/app/src/main/res/drawable-hdpi/dst_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a37fed2f4531e8bfeadb7cf8b0666014a10e059e GIT binary patch literal 34700 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_action_disconnect.png b/app/src/main/res/drawable-hdpi/ic_action_disconnect.png deleted file mode 100644 index e64801efdd358565d2a732781be874d35b441b87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 332 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

1V{hPoSXI8>ra?~XmD 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 diff --git a/app/src/main/res/drawable-hdpi/ic_csc_feature.png b/app/src/main/res/drawable-hdpi/ic_csc_feature.png deleted file mode 100644 index 8a105bd0e63477592fb92a5a6b6938d282399b9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5152 zcmbuD=R4aC8-{?4S+sJ&Mc)mklW&DO4JJYvNjMU0}ccWp{3g4)qq!DH8~ zQ7d+8Z{Fv9|AqI%b)R3aPxo$L%iIP3)eTzuHV~VUP|D`5yUf5Jw;W+~EBu=XMKnnJ>D>?q7vHnB_zO!h zmtB|ntv19+7V*SSEyHii^rwpF=6G4{I2jE%tiwi7$z;Bj9_3p!$R|egMdl zOs!{`n|)G6kS*E(awJnfnp-sj%E*Qp)XgocK$18GxgIv?T*nkEjv7#e{IU}J-lIP% zPFeuMQ2{)p^4}HAl6$U?N!*l!e*?Zg4GyF}v^Wufg{1V>Fc*#<5CEKtPB!cxz3ijW zb|)SCp@7aR0%3|EbR+iiT2ua_d8MRs$8&Nv7YR2AvG_AyJ>T?&665{dbh zXjejVgg{_iex~+t{J9+SJ$A*I&!P#A3HAJ_WQP-N40(bD^n31;8u-VH6HL!=w!6Pq zR?bD}ikIw6I0v@+ugiY^;nXk{a7My%ZTx0q*R*&*ga`ObObO49A<0#GQQOl5(fFJ;EJLWHGT1rYnr{nVWp#;wiZY3y`-BF+0WrTSR`yB;SytqqMt!% zxU*tT(Da)vb5rc>UamW^V_I3T#FP_DWQZ5v*#rC$B$DatoIB(=_{ABKXLib?9c$?!V+&S%d{ibT3~F7odC#BK3I@!xP@=Lc$hOM-@owLy5L@n`>3tz=h z*wYV@Ko`ZH3@}ychga^v_r)8az zCQ}E#XH7JR(g<9)>>}!+y9=fVb14(zYzi0J&Cs!I20!`PD63gCq`vc@7jkA4H*_q3 zQo)l^#vW8Atp(IplzV=HnT(dke=v5IHe|>9J+MiJ(Dh^fc7T=L-V?@a!RuXdv|q&Y z+N`Ic$*PPW_TNgGP4eA4ruHaiD~Gq`QFLq+KHuvEozXHNX>W`PL2z)oIRw5Ksz?=VtFa4?#fAtiVJ5XbJwJts1CO*ox2@x49XxwsG6$ zZg4BTeM|&8aoeF(&78E9WLUeMAMgdqbK)o!B2SIKR!5IL~7oY?Au;8}P42)YIRh+m;pa~>Tfhz-! z;iUysI6)xJdobWIAW`u#+$vF0TGmWXM;qrxo9Fji!|S`NW? z!>XDeD?anoeD@3OFORUyNh@ItE(7AUk{mc24w4*9lz=e$)z~4BBrC2NZ5)^CvzmEN z?`)1z-5O8>57XnUK`r6X)JstyyLHVB#74;S3ob+sj%-cp1Ci_Pd|AjKefYUQ8ex)Z zMk+t0aH0{hZwtDNEG&=z0ElZP%_{>q5y_o!5DUEKB)wgYG;!2yE>4R zrr0SeJ1qwS%h^cgB2iTRM4WK!07pJM!$mTsd&usYk)VJ@6zND2Dg=nU_yCCL^`??m=bt~Rv1$P%?CNcrVmrS-)M~wR4ABv+K zs106$L)1n`J>TfLx|T?evSpGkTZ-Z7DTmJNkKfqwfXVkXh9*tC>_R~Ygbs(_9Z62e zl$4fs=llqz=1D#Ab0hP^;VKVS`~lXpE!*xQ=_qa}48+d!JhL3e&8jRn*nDHiH-q5* z#&2pjS`M>f8n#a_{2@AxyksljGRd+TgIqoI8(dP9pr}L%-8Y2x5ubW#JivcMeSN96 zTXz&I+8+bUN#Kq0^&RrsOB!H)b?RI(*}MG*z+bd1TtN^<`q*}jQUL{FE$euy^IGFq zeB~`;iW5Ep5k^7?yTHn(Av)0&$QgpaItgwUQQct{^_6@juQe|u(DPemdtUkj#r2_* z>JB5>vWF^s^KkaU{;;E|oH!bXgGWc-cvUIReX~-&TreH2p9t13VD;0j)Sk@|_}_ow zeExQABmV`nZJuIF^va?#c2cbOeHsIssH3xbH~IUF^<<@mT782@Zu~OI-<4*mbE*3{Zx^X4Do-74TD1Z5Y!%VVcM}G z`{Qe(K^uDC7GBV>NGP?%jo%B|NEP6+xzkLd?4Y3KJHG?6<<7{<^&?-+xrY+LpZowN zGM+uE+FnKF&q)*+=CU8|OuW8tIElLzlo(p-KqzaaR>oHgn5Zk^b9-$R?xnfP`Pw`9 zOp-g6mXtJ%yNVc`uGu6Gi~guZfXxp<=MCl&`)w`-!Ul&fLSsFi5FT320n3;Ub-7#l z%EwaP|7e-FMSY4}L778?%AYi(aSzlVH!UnQAHR-JEJl^sVd-k5P3_(L-fV4)4E}(( zJ#jY<5YPRTTe9jr0RDWP*Rj(6nT=+}HpAhl3-zXdL1Umd-``P;Ix<{|u4+JV{>U|q z(BD$9CT=*`9M8Dr>}Pz(TgJ5i&7|1jG;wGP#o16|A9`BFdl$K-DK+#p_>k^>80$=Ek2|sL?xWQG|m_`N(cta|Ljj#)vLlC3(iaKgj z{mh9ct%QXtL~$Q(L%L)2jcul=H@40GVpBPOf$6??EIj;mj+fN;fP(jLGB0YAW`$A- zD%~p3t`hwgNdAkhVm94E!O# z^5zT98*FR>KRuGkSFc^2ud@V_VxsCb56eQ{CVY6W(s^<581Mu2o(~%keyM1jl|dp` zLn3AWIv@WY37WfL4h?Bqo*kkPCHZPCuH6@k${_I>-CA%SY$Ur~v1@r$N0~3Nq^>{4 zWTd^ogpd*?cT)_mL@y;vcMu30qZ$Ka#9s-rz!ADFGvdrJFYY9ByCf$jHLR~Nq!wi7!e;+eW zpEd-HZVf5RSdaWSz@s`}|6R)= zA-47xR9t0ROz}!8MXX!lP$`KNHhbW@i2gc5KDw&?q-_>gj?f05C}}Qv)Nn*k#5!@he+_e<+=(G56+|ykKo?QDubF1^h5d7P!ixuK4x1w4vZ*)mLe}D965GWVI@T)k;P6Pb zKYt4k_|1=+r1Jlx88z&bAy1H%Cy0Y3X>h6YxRO^0m;9o)LByHwnlRp6wCf$R?h@t` zBxkTKKmXmB=QnI6s>fqW5@WOyvg12N>n&a{HC=!KwHP3o|^_Xe=*#z1e`SYil zY`Kf_MIYzffdQ>w(n?f~PpW?LM-nWuk?(4el}+^RK0Th${LUW^Ia4==ef!B)wSsyL(6RbsMohbQ z(jT^ER|B)Y_i`=mevjIxD2pQ9H%#(k?BVy=oZ1{`*P;1!x=8^q->`ufb^PU!$i`UA z5O3c#jc1Bw-Qkr0@Ak0hOy=s<9G%hiOcXyXb?46N@Kqwh%WY6>K#3GzN+4I^y1mE` zJWNhY+x_giQH#;8{(ciNUjW8IwaX?cyqp6aHu}*RGBd}K?N}T0c2P;zB&sJ2wYl4t zexDP3RN~Qc~LY`(|bS9U<8~T+8w2 zH|G4E$^~63lfECp$z(U*EE8a-^!SCsMh+Ld1=^1d3i?D9;k@lvRuP(!Of%f8JI3YA zS*Eo`h6yCQZKhC`^=CIN-J!WzRVKf#!Z4NNrr!RPcivR*|G2`=w>v^PcskFX>*eZ9 z3H8dingyW3?Y90JTb+DaA8|{tnA19T5Q~{-TxLde6HT=LQYmF3M0FSmK7=H>inNxd ztbAj-aC`i)t59*75y`t1<1M3^NZHkS?ZfyuO*?pqq&KL z+an4eI0_lJ6Wy&ZMdOA%Sd5<;%f1Dzk6In3arzr&d{CiN`Y_m<^=AYtmwd59H5D%p zK9{jiIB)LcBf&Rj2YUPT{H}W}{b=k_-rhm)yGhL7hM*1ON^JfM#g?&npOzvfrisB0 zID2wmVJYv~LSvv@Ye>LpSsH<1L+X0}K0ow=`k(IPoWodyYrTV&8Ue_Sv`u~{78}S+ zI3%QtXUnALn6c>EC%9vo^+1ZVjf!bUf-prf+Jj2tcS;j-x?qhZ$QexYY-=mZ@7ky@ zz=g$5wNt@k67TURMtQWT#LL29W9;_zX@x|iff)2eQ8{GG31hHMeC6!Q>{-(lzjEtK z%Ij0@;p6Q>%j6{dNFVh<5Mk9ewa}va&*B%QB(WNe=~|`2DJ%2ocG(yK!mWN&SE21B zY0tpd-z%=Y#l&K;EV&q=66Jo`<1wHj)$0EIqqXvbPUHzg{v*}^mw}$zKHq?+{Tob} zW|{mCvY77&*r-M;p?Mlw92>pCcVqi}dP>1?ah7WF@qtqd_S|NIA<H8U{m0QrF?#~BxnCMxF?_cujB~Fv!IsjpM1>F)ps@AN#lmsJwj_FtC>tOX*`K>qYj3j@fvb( zEJ1V-+DWc^H_@=Ax44EpX@uVS;jo>Ha1&NzpYpmEh$Z{;&Q?lZFUrYL@1xaZZ~T{W zDBQWlp07c%u3D;0)t0R3r&Bqg&#)*=nJ+}W>iv7>2MG!fz=?>S> VmAn;cuKy}O0Iu^yyHe98^gsUU-`@ZL diff --git a/app/src/main/res/drawable-hdpi/ic_dfu_feature.png b/app/src/main/res/drawable-hdpi/ic_dfu_feature.png deleted file mode 100644 index db59fae82b0e31240ffe5a0b4ae23485cc562d47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3079 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 VlfF}PPn-Y%002ovPDHLkV1i!qzPSJZ diff --git a/app/src/main/res/drawable-hdpi/ic_glucose_feature.png b/app/src/main/res/drawable-hdpi/ic_glucose_feature.png deleted file mode 100644 index 9ea9243977fd9593fdef94c0b2cea2eedb307812..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/app/src/main/res/drawable-hdpi/ic_help.png b/app/src/main/res/drawable-hdpi/ic_help.png deleted file mode 100644 index 459bed76c5b9f546541383271a6c9b9ff9943093..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1544 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 diff --git a/app/src/main/res/drawable-hdpi/ic_proximity_feature.png b/app/src/main/res/drawable-hdpi/ic_proximity_feature.png deleted file mode 100644 index 5b80a88113502cd7f0e6d16de351f466396917fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/app/src/main/res/drawable-hdpi/ic_rsc_feature.png b/app/src/main/res/drawable-hdpi/ic_rsc_feature.png deleted file mode 100644 index 8e45929ec27e9444b841f7d9e4d9c8c14366d53f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2525 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 yNuUm_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 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 deleted file mode 100644 index a0811938253dfed1dd2c443909cb306415f6e8e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 696 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 M4E>n`i3lE`uB*Jln%E;zp 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 {+~UXaw?!+MVZRlK#VoL@eCCJb>}&498u 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 A4*&oF literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/proximity_lock_open.png b/app/src/main/res/drawable-hdpi/proximity_lock_open.png deleted file mode 100644 index e2c0f280e079614384f7e658571cd484caaccd35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2697 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 J%Q~loCIGUAC13ym diff --git a/app/src/main/res/drawable-hdpi/shadow_r.png b/app/src/main/res/drawable-hdpi/shadow_r.png deleted file mode 100644 index ae07b59379f5fe0924138b29cab52307382a0786..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 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 diff --git a/app/src/main/res/drawable-mdpi/dst_logo.png b/app/src/main/res/drawable-mdpi/dst_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..60691db76bf06b01b9f3062fd467eee1f6a980d3 GIT binary patch literal 17136 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 Hu0mjfSD{oE literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/iisc_logo.png b/app/src/main/res/drawable-mdpi/iisc_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..197534524118ce6034c66f8616000189c4257975 GIT binary patch literal 122806 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