com.wolkabout.hexiwear.service.DeviceDiscoveryService.java Source code

Java tutorial

Introduction

Here is the source code for com.wolkabout.hexiwear.service.DeviceDiscoveryService.java

Source

/**
 *  Hexiwear application is used to pair with Hexiwear BLE devices
 *  and send sensor readings to WolkSense sensor data cloud
 *
 *  Copyright (C) 2016 WolkAbout Technology s.r.o.
 *
 *  Hexiwear is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Hexiwear is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

package com.wolkabout.hexiwear.service;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import com.wolkabout.hexiwear.model.BluetoothDeviceWrapper;

import org.androidannotations.annotations.AfterInject;
import org.androidannotations.annotations.Background;
import org.androidannotations.annotations.EBean;
import org.androidannotations.annotations.RootContext;
import org.androidannotations.api.BackgroundExecutor;
import org.parceler.Parcels;

@EBean
public class DeviceDiscoveryService {

    private static final String TAG = DeviceDiscoveryService.class.getSimpleName();

    private static final long SCAN_PERIOD = 5000;
    private static final String SCAN_TASK = "scan";
    private static final String HEXIWEAR_TAG = "hexiwear";
    private static final String HEXI_OTAP_TAG = "hexiotap";

    public static final String SCAN_STARTED = "scanStarted";
    public static final String SCAN_STOPPED = "scanStopped";
    public static final String DEVICE_DISCOVERED = "deviceDiscovered";
    public static final String WRAPPER = "wrapper";

    private static final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

    @RootContext
    Context context;

    private static ScanCallback lolipopScanCallback;
    private static BluetoothAdapter.LeScanCallback kitKatScanCallback;

    @AfterInject
    void checkEnabled() {
        isEnabled();
    }

    public void startScan() {
        if (!isEnabled()) {
            return;
        }

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            startKitKatScan();
        } else {
            startLolipopScan();
        }

        setScanTimeLimit();
        sendBroadcast(new Intent(SCAN_STARTED));
        Log.i(TAG, "Bluetooth device discovery started.");
    }

    @SuppressWarnings("deprecation")
    @TargetApi(Build.VERSION_CODES.KITKAT)
    public void startKitKatScan() {
        kitKatScanCallback = new BluetoothAdapter.LeScanCallback() {
            @Override
            public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
                final BluetoothDeviceWrapper wrapper = new BluetoothDeviceWrapper();
                wrapper.setDevice(device);
                wrapper.setSignalStrength(rssi);
                onDeviceDiscovered(wrapper);
            }
        };
        bluetoothAdapter.startLeScan(kitKatScanCallback);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    private void startLolipopScan() {
        lolipopScanCallback = new ScanCallback() {
            @Override
            public void onScanResult(int callbackType, ScanResult result) {
                super.onScanResult(callbackType, result);
                final BluetoothDeviceWrapper wrapper = new BluetoothDeviceWrapper();
                wrapper.setDevice(result.getDevice());
                wrapper.setSignalStrength(result.getRssi());
                onDeviceDiscovered(wrapper);
            }
        };
        bluetoothAdapter.getBluetoothLeScanner().startScan(lolipopScanCallback);
    }

    private void onDeviceDiscovered(final BluetoothDeviceWrapper wrapper) {
        final BluetoothDevice device = wrapper.getDevice();
        Log.i(TAG, "Discovered device: " + device.getName() + "(" + device.getAddress() + ")");
        final String name = wrapper.getDevice().getName();
        if (HEXI_OTAP_TAG.equalsIgnoreCase(name)) {
            wrapper.setInOtapMode(true);
        } else if (!HEXIWEAR_TAG.equalsIgnoreCase(name)) {
            return;
        }

        final Intent deviceDiscovered = new Intent(DEVICE_DISCOVERED);
        deviceDiscovered.putExtra(WRAPPER, Parcels.wrap(wrapper));
        sendBroadcast(deviceDiscovered);
    }

    @Background(id = SCAN_TASK, delay = SCAN_PERIOD)
    void setScanTimeLimit() {
        cancelScan();
    }

    @SuppressWarnings("deprecation")
    public void cancelScan() {
        if (!isEnabled()) {
            return;
        }

        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            bluetoothAdapter.stopLeScan(kitKatScanCallback);
        } else {
            bluetoothAdapter.getBluetoothLeScanner().stopScan(lolipopScanCallback);
        }

        sendBroadcast(new Intent(SCAN_STOPPED));
        Log.i(TAG, "Bluetooth device discovery canceled");
        BackgroundExecutor.cancelAll(SCAN_TASK, true);
    }

    boolean isEnabled() {
        if (bluetoothAdapter == null) {
            Log.e(TAG, "Bluetooth not supported");
            return false;
        } else if (!bluetoothAdapter.isEnabled()) {
            context.startActivity(new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE));
            return false;
        } else {
            Log.v(TAG, "Bluetooth is enabled and functioning properly.");
            return true;
        }
    }

    private void sendBroadcast(Intent intent) {
        LocalBroadcastManager.getInstance(context).sendBroadcast(intent);
    }
}