com.diy.blelib.profile.BleProfileService.java Source code

Java tutorial

Introduction

Here is the source code for com.diy.blelib.profile.BleProfileService.java

Source

/*******************************************************************************
 * Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved.
 *
 * The information contained herein is property of Nordic Semiconductor ASA.
 * Terms and conditions of usage are described in detail in NORDIC SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
 * Licensees are granted free, non-transferable use of the information. NO WARRANTY of ANY KIND is provided.
 * This heading must NOT be removed from the file.
 ******************************************************************************/
package com.diy.blelib.profile;

import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.widget.Toast;

import com.diy.blelib.R;
import com.diy.blelib.bag.ByteUtil;

import de.greenrobot.event.EventBus;
import de.greenrobot.event.Subscribe;

public abstract class BleProfileService extends Service implements BleManagerCallbacks {
    private static final String TAG = "BleProfileService";

    public static final String BROADCAST_CONNECTION_STATE = "com.xs.charge.BROADCAST_CONNECTION_STATE";
    public static final String BROADCAST_SERVICES_DISCOVERED = "com.xs.charge.BROADCAST_SERVICES_DISCOVERED";
    public static final String BROADCAST_BOND_STATE = "com.xs.charge.BROADCAST_BOND_STATE";
    public static final String BROADCAST_BATTERY_LEVEL = "com.xs.charge.BROADCAST_BATTERY_LEVEL";
    public static final String BROADCAST_ERROR = "com.xs.charge.BROADCAST_ERROR";
    //add by xs.lin on 2016-6-13
    public static final String BROADCASE_LOG = "com.xs.charge.log";
    public static final String EXTRA_LOG = "com.xs.charge.log.EXTRA_LOG";

    /** 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 = "com.xs.charge.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 = "com.xs.charge.EXTRA_DEVICE_NAME";
    public static final String EXTRA_LOG_URI = "com.xs.charge.EXTRA_LOG_URI";
    public static final String EXTRA_CONNECTION_STATE = "com.xs.charge.EXTRA_CONNECTION_STATE";
    public static final String EXTRA_BOND_STATE = "com.xs.charge.EXTRA_BOND_STATE";
    public static final String EXTRA_SERVICE_PRIMARY = "com.xs.charge.EXTRA_SERVICE_PRIMARY";
    public static final String EXTRA_SERVICE_SECONDARY = "com.xs.charge.EXTRA_SERVICE_SECONDARY";
    public static final String EXTRA_BATTERY_LEVEL = "com.xs.charge.EXTRA_BATTERY_LEVEL";
    public static final String EXTRA_ERROR_MESSAGE = "com.xs.charge.EXTRA_ERROR_MESSAGE";
    public static final String EXTRA_ERROR_CODE = "com.xs.charge.EXTRA_ERROR_CODE";
    public static final String EXTRA_DESTORY_SERVICE = "com.xs.charge.EXTRA_DESTORY_SERVICE";
    public static final int STATE_LINK_LOSS = -1;
    public static final int STATE_DISCONNECTED = 0;
    public static final int STATE_CONNECTED = 1;
    public static final int STATE_CONNECTING = 2;
    public static final int STATE_DISCONNECTING = 3;
    //add by siushen 1227
    public static final int STATE_BROADCAST_ERROR = 4;
    public static final int STATE_RECONN_FAIL = 5;
    public static final int EXTRA_DESTORY_SERVICE_INT = 6; //hand to stop ble service

    private BleManager<BleManagerCallbacks> mBleManager;
    private Handler mHandler;

    public static boolean mConnected;
    private String mDeviceAddress;
    private String mDeviceName;
    private boolean serviceLife = false;
    private BluetoothAdapter mBlutoothAdapter;

    public class LocalBinder extends Binder {
        /**
         * Disconnects from the sensor.
         */
        public final void disconnect() {
            if (!mConnected) {
                onDeviceDisconnected(false);
                return;
            }

            // notify user about changing the state to DISCONNECTING
            final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
            broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTING);
            LocalBroadcastManager.getInstance(BleProfileService.this).sendBroadcast(broadcast);

            mBleManager.disconnect();
        }

        /**
         * Returns the device address
         *
         * @return device address
         */
        public String getDeviceAddress() {
            return mDeviceAddress;
        }

        /**
         * Returns the device name
         *
         * @return the device name
         */
        public String getDeviceName() {
            return mDeviceName;
        }

        /**
         * Returns <code>true</code> if the device is connected to the sensor.
         *
         * @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
         */
        public boolean isConnected() {
            return mConnected;
        }

        /**
         * notify from service to manager
         * @param command
         */
        public void serviceToManager(byte[] command) {
            mBleManager.serviceToManager(command);
        }
    }

    @Override
    public IBinder onBind(final Intent intent) {
        return getBinder();
    }

    /**
     * Returns the binder implementation. This must return class implementing the additional manager interface that may be used in the binded activity.
     *
     * @return the service binder
     */
    protected LocalBinder getBinder() {
        // default implementation returns the basic binder. You can overwrite the LocalBinder with your own, wider implementation
        return new LocalBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        // we must allow to rebind to the same service
        return true;
    }

    @SuppressWarnings("unchecked")
    @Override
    public void onCreate() {
        super.onCreate();
        serviceLife = true;
        mHandler = new Handler();

        // initialize the manager
        mBleManager = initializeManager();
        mBleManager.setGattCallbacks(this);
        mBlutoothAdapter = BluetoothAdapter.getDefaultAdapter();

        EventBus.getDefault().register(this);
    }

    @SuppressWarnings("rawtypes")
    protected abstract BleManager initializeManager();

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        if (intent == null || !intent.hasExtra(EXTRA_DEVICE_ADDRESS))
            throw new UnsupportedOperationException("No device address at EXTRA_DEVICE_ADDRESS key");

        mDeviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
        Log.i(TAG, "Service started");
        //?????
        if (!mBlutoothAdapter.isEnabled())
            mBlutoothAdapter.enable();
        // notify user about changing the state to CONNECTING
        final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
        broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTING);
        LocalBroadcastManager.getInstance(BleProfileService.this).sendBroadcast(broadcast);

        final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
        final BluetoothAdapter adapter = bluetoothManager.getAdapter();
        final BluetoothDevice device = adapter.getRemoteDevice(mDeviceAddress);
        mDeviceName = device.getName();
        onServiceStarted();

        Log.v(TAG, "Connecting...");
        mBleManager.connect(BleProfileService.this, device);
        return START_REDELIVER_INTENT;
    }

    /**
     * Called when the service has been started. The device name and address are set. It nRF Logger is installed than logger was also initialized.
     */
    protected void onServiceStarted() {
        // empty default implementation
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        final Intent broadcast = new Intent(EXTRA_DESTORY_SERVICE);
        LocalBroadcastManager.getInstance(BleProfileService.this).sendBroadcast(broadcast);
        // shutdown the manager
        //      if(mBleManager == null)
        mBleManager.closeBluetoothGatt();
        mBleManager = null;
        mDeviceAddress = null;
        mDeviceName = null;
        mConnected = false;
        serviceLife = false;

        EventBus.getDefault().unregister(this);
    }

    @Override
    public void onDeviceConnected() {
        mConnected = true;

        final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
        broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_CONNECTED);
        broadcast.putExtra(EXTRA_DEVICE_ADDRESS, mDeviceAddress);
        broadcast.putExtra(EXTRA_DEVICE_NAME, mDeviceName);
        LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
    }

    @Override
    public void onLinklossOccur() {
        Log.w(TAG, "Connection lost");
        mConnected = false;

        final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
        broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_LINK_LOSS);
        LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
    }

    @Override
    public void onServicesDiscovered(final boolean optionalServicesFound) {
        Log.i(TAG, "Services Discovered");
        Log.v(TAG, "Primary service found");
        if (optionalServicesFound)
            Log.v(TAG, "Secondary service found");

        final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
        broadcast.putExtra(EXTRA_SERVICE_PRIMARY, true);
        broadcast.putExtra(EXTRA_SERVICE_SECONDARY, optionalServicesFound);
        LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
    }

    @Override
    public void onDeviceNotSupported() {
        Log.i(TAG, "Services Discovered");
        Log.w(TAG, "Device is not supported");

        final Intent broadcast = new Intent(BROADCAST_SERVICES_DISCOVERED);
        broadcast.putExtra(EXTRA_SERVICE_PRIMARY, false);
        broadcast.putExtra(EXTRA_SERVICE_SECONDARY, false);
        LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);

        // no need for disconnecting, it will be disconnected by the manager automatically
    }

    @Override
    public void onBatteryValueReceived(final int value) {
        Log.i(TAG, "Battery level received: " + value + "%");

        final Intent broadcast = new Intent(BROADCAST_BATTERY_LEVEL);
        broadcast.putExtra(EXTRA_BATTERY_LEVEL, value);
        LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
    }

    @Override
    public void onBondingRequired() {
        Log.v(TAG, "Bond state: Bonding...");
        //      showToast(R.string.bonding);

        final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
        broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDING);
        LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
    }

    @Override
    public void onBonded() {
        Log.i(TAG, "Bond state: Bonded");
        //      showToast(R.string.bonded);

        final Intent broadcast = new Intent(BROADCAST_BOND_STATE);
        broadcast.putExtra(EXTRA_BOND_STATE, BluetoothDevice.BOND_BONDED);
        LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
    }

    @Override
    public void onError(String message, int errorCode, boolean hand) {
        // TODO Auto-generated method stub
        Log.e(TAG, message + " (" + errorCode + ")");
        if (serviceLife) {
            final Intent broadcast = new Intent(BROADCAST_ERROR);
            broadcast.putExtra(EXTRA_ERROR_MESSAGE, message);
            broadcast.putExtra(EXTRA_ERROR_CODE, errorCode);
            LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
            mBleManager.disconnect();
        }
        //   stopSelf();
    }

    @Override
    public void onDeviceDisconnected(boolean hand) {
        // TODO Auto-generated method stub
        Log.i(TAG, "Disconnected");
        mConnected = false;
        mDeviceAddress = null;
        mDeviceName = null;
        if (serviceLife) {
            final Intent broadcast = new Intent(BROADCAST_CONNECTION_STATE);
            broadcast.putExtra(EXTRA_CONNECTION_STATE, STATE_DISCONNECTED);
            LocalBroadcastManager.getInstance(this).sendBroadcast(broadcast);
        }
        // user requested disconnection. We must stop the service
        //      stopSelf();
    }

    @Override
    public void onLogRecord(String message) {
        if (serviceLife) {
            final Intent broadcast = new Intent(BROADCASE_LOG);
            broadcast.putExtra(EXTRA_LOG, message);
            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(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(BleProfileService.this, messageResId, Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     * Shows a message as a Toast notification. This method is thread safe, you can call it from any thread
     *
     * @param message
     *            a message to be shown
     */
    protected void showToast(final String message) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(BleProfileService.this, message, Toast.LENGTH_SHORT).show();
            }
        });
    }

    /**
     * Returns the device address
     *
     * @return device address
     */
    protected String getDeviceAddress() {
        return mDeviceAddress;
    }

    /**
     * Returns the device name
     *
     * @return the device name
     */
    protected String getDeviceName() {
        return mDeviceName;
    }

    /**
     * Returns <code>true</code> if the device is connected to the sensor.
     *
     * @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
     */
    protected boolean isConnected() {
        return mConnected;
    }

    @Subscribe
    public void onEvent(String batteryStr) {
        String hexString = Integer.toHexString(Integer.valueOf(batteryStr));
        byte[] battery = ByteUtil.hexStringToBytes(hexString);
        mBleManager.serviceToManager(battery);
    }

}