HTS Scanner - Charles Palmer, Acute Technology, 22 November 2019
================================================================

This is an application that demonstrates the use of the Nordic BLE Scanner Library.

The app works with a Nordic Semiconductor PCA10040 development board programmed to advertise in a controlled manner.
Specifically, we program the PCA10040 with a modified version of the Health Thermometer Service (HTS) example. The modified device code
works so that pushing Button 1 starts the advertising. That way the user can control when the device advertises.
When the app detects the device it connects, reads one temperature, and disconnects.

For background, see the documentation of the library here:
https://github.com/NordicSemiconductor/Android-Scanner-Compat-Library
and this discussion on an example of the use of the library:
https://devzone.nordicsemi.com/f/nordic-q-a/50642/background-operation-of-ble-library-with-android-8---request-for-example

The app uses HTS code extracted from nRFToolbox to interact with the HTS device. In particular, a Service (HTSService) interacts with a BleManager
(HTSManager) to connect, read the temperature, and disconnect. Unlike the nRFToolbox model, HTSService runs all the time. It can be started by the
application's MainActivity, but also by code in StartupReceiver, which is invoked when the Android device wakes from a reset. This has the effect
that the app appears to be always listening for HTS advertisements, even after the Android device has been reset.

The app basically works as follows:

The MainActivity code enables or disables scanning (by clicking the FloatingActionButton). MainActivity also displays status
and the temperature data.

MainActivity calls the BleReceiver code to enable or disable the Ble Scanner. When enabling the scanner, a PendingIntent is set up.
The Ble Scanner listens for advertising from a matching Heath Thermometer and when it hears one, the PendingIntent fires and notifies
the HTSService. This creates a HTSManager and connects to the device, takes a temperature reading, broadcasts it, and disconnects.


Steps required:

1   Prepare to program a Nordic Semiconductor PCA10040 development board with the Health Thermometer example project, ble_app_hts
    Documented here: https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.3.0/ble_sdk_app_hts.html?cp=6_5_0_4_2_2_1

    Make the following code changes before programming the development board:

(a) in bsp_event_handler() change the BSP_EVENT_KEY_0 code so Button 1 starts advertising:
        case BSP_EVENT_KEY_0:
            if (m_conn_handle != BLE_CONN_HANDLE_INVALID)   {
                temperature_measurement_send();
            } else {
            	advertising_start(false);
            }

(b) in advertising_init() add this line to prevent advertising resuming after disconnect:
        init.config.ble_adv_on_disconnect_disabled = true;

(c) add "return;" as the first line in sleep_mode_enter() to prevent entering sleep mode (otherwise
    the button resets the application rather than works to start advertising):

(d) To make the LED1 behave correctly, add this to case BLE_ADV_EVT_IDLE:
        NRF_LOG_INFO("Idle.");
        err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);
    and this to   case BLE_GAP_EVT_DISCONNECTED:
        NRF_LOG_INFO("Disconnected.");
        err_code = bsp_indication_set(BSP_INDICATE_IDLE);
        APP_ERROR_CHECK(err_code);

    Be sure to erase any previous pairing by pressing Button_1 as power is applied.

2   Create a new Android "Basic Activity" project, named HTS Scanner. Build and download this project to an Android device
    to check you can.

3   Start adding the Nordic BLE code: add these dependencies to the app build.gradle file:
        implementation 'no.nordicsemi.android:ble:2.1.1'
        implementation 'no.nordicsemi.android.support.v18:scanner:1.4.3'
        implementation 'no.nordicsemi.android:log:2.2.0'

    and specify Java 1.8:

    android {
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
    }

    and add support for BLE and wakeup code to AndroidManifest.xml:

            <uses-permission android:name="android.permission.BLUETOOTH" />
            <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
            <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
            <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
            <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    then add two <receiver> definitions to the manifest file, one for triggering wake from reset events and the other
    for triggering BLE scanner events:

            <receiver
                android:name=".StartupReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter android:priority="500">
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                    <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                    <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </receiver>

            <receiver
                android:name=".BleReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="com.acutetechnology.htsscanner.ACTION_SCANNER_FOUND_DEVICE" />
                    <category android:name="android.intent.category.DEFAULT" />
                </intent-filter>
            </receiver>

    and add a service which will interact with the HTS device when it has been discovered:
            <service
                android:name=".HTSService"
                android:enabled="true"
                android:exported="false"></service>

3   Replace the MainActivity.java file and add the other source files. They behave as follows:

MainActivity.java - used to paint the screen with status and temperature readings. Starts the HTSService
(though the HTSService can also be started by StartupReceiver following a boot completion). Provides a
way for the user to toggle scanning on and off. Provides code to check Bluetooth permissions and enable
Bluetooth. It has a broadcast receiver that receives temperature readings and also BLE connection status etc.

HTSScannerApplication.java - extends Application. This contains code to store and retrieve state across reboots,
so supports resumpton of scanning following a reboot.

BleReceiver.java - controls the Nordic Scanner Library (turning on and off the scanner when instructed by MainActivity).
Includes the onReceive() code that receives the PendingIntent from the BLE scanner, as well as messages when the
BLE subsystem is shut down or started. When a matching HTS device is found, details are broadcast to HTSService
which will connect to the device.

HTSService.java - this service should be running all the time. It is started either when the MainActivity starts or
following a reboot. A BroadcastReceiver listens for DEVICE_FOUND messages from BleReceiver and then creates a new HTSManager
and asks it to connect to the device. The service receives various connection status messages from the Manager,
as well as the temperature reading. The temperature is broadcast to MainActivity for display. 100ms later
the service asks the manager to disconnect from the peripheral.

HTSManager.java - extends BleManager where most of the work is done. The HTSManager receives a TemperatureMeasurementCallback,
parses the messages and passes the data back to HTSService.

StartupReceiver.java - supports resumption of scanning when the device has been reset. It (re-)creates HTSScanner
following a reboot.

Notifier.java - code plays a sound when the app detects the device, when a temperature is read, and on an error.
This provides the user with audible feedback when the app is not in the foreground. The .wav files are in /res/raw

Code in the htsSupport folder has been taken from the nRFToolbox, mainly to parse the incoming messages.


