【Android BLE】藍(lán)牙開(kāi)發(fā)「防丟器」的相關(guān)知識(shí)點(diǎn)(二):連接設(shè)備并檢測(cè)連接狀態(tài)

1.初始化藍(lán)牙連接服務(wù)類(lèi)

在掃描并識(shí)別到自家設(shè)備后,接下來(lái)就是連接設(shè)備,并綁定該設(shè)備到手機(jī)了。在連接設(shè)備之前,我們需要初始化藍(lán)牙連接服務(wù),這個(gè)初始化放在應(yīng)用的Application中進(jìn)行,整個(gè)應(yīng)用與該服務(wù)密切相關(guān)。

public BluetoothLeService mBluetoothLeService; // 藍(lán)牙連接服務(wù)
public ServiceConnection mServiceConnection; // 藍(lán)牙連接服務(wù)

/**
 * 初始化BLE相關(guān)
 */
private void initBle() {
    // 初始化并綁定服務(wù)
    mServiceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(final ComponentName componentName, final IBinder service) {
            BuglyLog.d(TAG, "--onServiceConnected--");
            mBluetoothLeService = ((BluetoothLeService.LocalBinder) service).getService();
            if (!mBluetoothLeService.initialize()) {
                BuglyLog.e(TAG, "Unable to initialize Bluetooth");
            }
        }

        @Override
        public void onServiceDisconnected(final ComponentName componentName) {
            mBluetoothLeService = null;
        }
    };

    Intent gattServiceIntent = new Intent(this, BluetoothLeService.class);
    bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);
}

初始化過(guò)程:

private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;

public boolean initialize() {
    // For API level 18 and above, get a reference to BluetoothAdapter through
    // BluetoothManager.
    if (mBluetoothManager == null) {
        mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        if (mBluetoothManager == null) {
            BuglyLog.e(TAG, "Unable to initialize BluetoothManager.");
            return false;
        }
    }

    mBluetoothAdapter = mBluetoothManager.getAdapter();
    if (mBluetoothAdapter == null) {
        BuglyLog.e(TAG, "Unable to obtain a BluetoothAdapter.");
        return false;
    }

    return true;
}

*以上過(guò)程在Application的onCreate中進(jìn)行,以下我再寫(xiě)點(diǎn)與業(yè)務(wù)邏輯相關(guān)的,可不看!該邏輯主要是用來(lái)定時(shí)檢測(cè)已經(jīng)綁定過(guò)的設(shè)備是否都已經(jīng)連接,實(shí)際場(chǎng)景就是:用戶(hù)可能在錢(qián)包、背包、遙控器上等放置了防丟器,如果超距后會(huì)斷開(kāi)連接,但是重新回到連接范圍后,手機(jī)要發(fā)起重連請(qǐng)求,這依賴(lài)于此定時(shí)檢測(cè)服務(wù)。

// 以下與應(yīng)用業(yè)務(wù)邏輯高度關(guān)聯(lián),可不看
TimerTask task = new TimerTask() {
    @Override
    public void run() {
        BluetoothManager btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        BluetoothAdapter mBluetoothAdapter = btManager.getAdapter();

        if (!mBluetoothAdapter.isEnabled()) {
            BuglyLog.i(TAG, "^^^藍(lán)牙沒(méi)打開(kāi)^^^");
            if (mBluetoothLeService != null) {
                // 如果之前有連接信息,需要清除(不清除的后果就是藍(lán)牙重新打開(kāi),會(huì)檢測(cè)到之前連接過(guò),但是其實(shí)此時(shí)并未重新連接)
                mBluetoothLeService.clear();
            }
            return;
        }

        if (mBluetoothLeService != null) {
            List<Beagle> mBeagles = getDaoSession().getBeagleDao().loadAll();
            List<BluetoothDevice> connectDevices = mBluetoothLeService.getConnectedDevices();

            for (Beagle beagle : mBeagles) {
                BuglyLog.d(TAG, "檢查:" + beagle.getMac());
                boolean isConnected = false;
                for (BluetoothDevice bd : connectDevices) {
                    if (TextUtils.equals(bd.getAddress(), beagle.getMac())) {
                        BuglyLog.d(TAG, "定時(shí)檢測(cè),設(shè)備已經(jīng)處于連接狀態(tài):" + beagle.getMac());
                        isConnected = true;
                        break;
                    }
                }

                // 未連接時(shí),自動(dòng)重連
                if (!isConnected) {
                    boolean flag = mBluetoothLeService.connect(beagle.getMac());
                    if (flag) {
                        BuglyLog.d(TAG, "連接成功:" + beagle.getMac());
                    } else {
                        BuglyLog.d(TAG, "連接失?。? + beagle.getMac());
                    }
                }
            }
        }
    }
};

mTimer = new Timer();
mTimer.schedule(task, 2000, 10000);

2.連接BLE設(shè)備

其實(shí)連接設(shè)備的步驟非常簡(jiǎn)單,代碼如下:

getApp().mDeviceAddress = mAdapterList.get(position).getAddress();
getApp().mBluetoothLeService.connect(getApp().mDeviceAddress);

對(duì)應(yīng)的*BluetoothLeService中方法如下:

/**
 * 連接藍(lán)牙設(shè)備
 *
 * @param mac mac
 */
public boolean connect(String mac) {
    if (mBluetoothAdapter == null || mac == null) {
        BuglyLog.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
        return false;
    }

    List<BluetoothDevice> connectDevices = getConnectedDevices();

    for (BluetoothDevice bd : connectDevices) {
        if (TextUtils.equals(bd.getAddress(), mac)) {
            BuglyLog.d(TAG, "該設(shè)備已經(jīng)連接啦:" + mac);
            return true;
        }
    }

    // 使用之前連接過(guò)的
    if (mBluetoothGatts.get(mac) != null) {
        if (mBluetoothGatts.get(mac).connect()) {
            BuglyLog.d(TAG, "使用之前連接過(guò)的:" + mac);
            return true;
        } else {
            return false;
        }
    }

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mac);
    if (device == null) {
        BuglyLog.w(TAG, "Device not found.  Unable to connect.");
        return false;
    }
    device.connectGatt(this, false, mGattCallback);
    BuglyLog.d(TAG, "創(chuàng)建一個(gè)新連接,MAC=" + mac);
    return true;
}

*這里的getApp()就是獲取應(yīng)用的靜態(tài)Application,BluetoothLeService類(lèi)內(nèi)容較多,最后附上,下面拆分簡(jiǎn)單說(shuō)下。

3.處理連接后的回調(diào)事件

在上面的連接設(shè)備方法中,有一個(gè)很關(guān)鍵的參數(shù)mGattCallback,這個(gè)是用來(lái)接收藍(lán)牙連接的各類(lèi)回調(diào)事件的,我們主要的業(yè)務(wù)邏輯都會(huì)在此處理:連接成功后的服務(wù)通道獲取、認(rèn)證、斷開(kāi)連接處理、指令發(fā)送與接收回調(diào)、信號(hào)強(qiáng)度變化等等。
其對(duì)應(yīng)的代碼如下,其實(shí)根據(jù)BluetoothGattCallback需要重寫(xiě)的方法名稱(chēng),也能大概知道其作用:

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {

    @Override
    public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic
            characteristic) {
        dealWithData(gatt, characteristic);
    }

    @Override
    public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {
            dealWithData(gatt, characteristic);
        } else {
            BuglyLog.e(TAG, "讀取通道信息失?。? + characteristic.getUuid());
        }
    }

    @Override
    public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
        if (newState == BluetoothProfile.STATE_CONNECTED) {
            BuglyLog.i(TAG, "BluetoothGatt連接上,MAC:" + gatt.getDevice().getAddress());

            gatt.discoverServices();
            mBluetoothGatts.put(gatt.getDevice().getAddress(), gatt);

        } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
            dealDeviceDisconnected(gatt);
            BuglyLog.w(TAG, "BluetoothGatt斷開(kāi),MAC:" + gatt.getDevice().getAddress());
        }
    }

    @Override
    public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
        super.onCharacteristicWrite(gatt, characteristic, status);

        String uuidStr = characteristic.getUuid().toString();

        BuglyLog.e(TAG, "onCharacteristicWrite-->\nmac:" + gatt.getDevice().getAddress() + "\nuuid:" + uuidStr +
                "\n發(fā)送的值:" + ByteUtils.byteArrayToHexString(characteristic.getValue()) + "\nstatus:" + status);

        if (TextUtils.equals(uuidStr, BluetoothUtils.UUID_S_EXTRA_C.toString())) { // 設(shè)備信息設(shè)置

            StatusEvent e = new StatusEvent();
            String action = "";

            if (characteristic.getValue() == BluetoothUtils.VALUE_MODE_THETHER) {
                action = StatusEvent.ACTION_MODE_THETHER;
            } else if (characteristic.getValue() == BluetoothUtils.VALUE_MODE_FIND) {
                action = StatusEvent.ACTION_MODE_FIND;
            } else if (characteristic.getValue() == BluetoothUtils.VALUE_FIND_LIGHT_ON) {
                action = StatusEvent.ACTION_FIND_LIGHT_ON;
            } else if (characteristic.getValue() == BluetoothUtils.VALUE_FIND_LIGHT_OFF) {
                action = StatusEvent.ACTION_FIND_LIGHT_OFF;
            } else if (characteristic.getValue() == BluetoothUtils.VALUE_TETHER_BEEP_ON) {
                action = StatusEvent.ACTION_TETHER_BEEP_ON;
            } else if (characteristic.getValue() == BluetoothUtils.VALUE_TETHER_BEEP_OFF) {
                action = StatusEvent.ACTION_TETHER_BEEP_OFF;
            }


            e.setAction(action);
            e.setMac(gatt.getDevice().getAddress());
            EventBus.getDefault().post(e);
        } else if (TextUtils.equals(uuidStr, BluetoothUtils.UUID_S_IMMEDIATE_C_ALERT.toString())) { // 立即警報(bào)設(shè)置

            StatusEvent e = new StatusEvent();
            e.setAction(StatusEvent.ACTION_IMMEDIATE);
            e.setMac(gatt.getDevice().getAddress());
            EventBus.getDefault().post(e);

        } else if (TextUtils.equals(uuidStr, BluetoothUtils.UUID_S_EXTRA_C_LOGIN.toString())) {

            // 通知綁定頁(yè)面
            BindEvent e = new BindEvent();
            e.setAction(BindEvent.ACTION_BIND_SUCCESS);
            e.setMac(gatt.getDevice().getAddress());
            EventBus.getDefault().post(e);

        } else if (TextUtils.equals(uuidStr, BluetoothUtils.UUID_S_EXTRA_C_UNBIND.toString())) { // 解綁命令
            QueryBuilder qb = MyApplication.getInstance().getDaoSession().getBeagleDao().queryBuilder();
            qb.where(BeagleDao.Properties.Mac.eq(gatt.getDevice().getAddress()));
            List<Beagle> mBeagles = qb.list();

            Beagle beagle;
            if (mBeagles.size() > 0) {
                beagle = mBeagles.get(0);
            } else {
                return;
            }

            if (beagle.getUpdateStatus() == Beagle.UPDATE_PROCESSING) {
                BuglyLog.d(TAG, "解綁--升級(jí)…………");
                mBluetoothGatts.remove(gatt.getDevice().getAddress());
            } else {
                BuglyLog.d(TAG, "解綁?。?!");
                MyApplication.getInstance().getDaoSession().getBeagleDao().deleteByKey(beagle.getMac());
                StatusEvent e = new StatusEvent();
                e.setAction(StatusEvent.ACTION_UNBIND);
                e.setMac(gatt.getDevice().getAddress());
                EventBus.getDefault().post(e);
            }
        }
    }

    @Override
    public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
        BuglyLog.w(TAG, "onServicesDiscovered received: " + status);
        if (status == BluetoothGatt.GATT_SUCCESS) {
            dealServicesDiscoverd(gatt);
        } else {
            BuglyLog.w(TAG, "onServicesDiscovered received: " + status);
        }
    }

    @Override
    public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
        if (status == BluetoothGatt.GATT_SUCCESS) {

            StatusEvent e = new StatusEvent();
            e.setAction(StatusEvent.ACTION_RSSI);
            e.setMac(gatt.getDevice().getAddress());
            e.setRssi(rssi);
            EventBus.getDefault().post(e);

        } else {
            BuglyLog.w(TAG, "onReadRemoteRssi received: " + status);
        }
    }
};

通常在建立連接后,會(huì)進(jìn)入onServicesDiscovered方法,這個(gè)時(shí)候可已根據(jù)需要去發(fā)起一些通道的訂閱(可遍歷所有通道信息,根據(jù)通道的可讀、通知屬性來(lái)訂閱)。我這里,手機(jī)需要向設(shè)備發(fā)起認(rèn)證信息(這個(gè)需要固件配合,認(rèn)證后,其他手機(jī)就掃描不到該設(shè)備了),認(rèn)證的指令自定義約定,此處略。從最后附錄的全部代碼可以看到認(rèn)證指令發(fā)送失敗是立即通知程序頁(yè)面認(rèn)證失敗的,但是成功發(fā)送認(rèn)證指令,并沒(méi)有立即通知,這里要注意,真正的指令是否成功寫(xiě)入設(shè)備,是要通過(guò)onCharacteristicWrite來(lái)判斷的:

  • onCharacteristicChanged:接收到通道指令(前提是已經(jīng)訂閱),如設(shè)備的點(diǎn)擊、雙擊、長(zhǎng)按事件;
  • onCharacteristicRead:手機(jī)主動(dòng)發(fā)起的read后,設(shè)備回傳過(guò)來(lái)的數(shù)據(jù),如讀取設(shè)備電量、固件版本等;
  • onConnectionStateChange:設(shè)備與手機(jī)的連接狀態(tài)變化:連接成功、斷開(kāi)連接;
  • onCharacteristicWrite:手機(jī)向設(shè)備寫(xiě)入指令的結(jié)果,該方法中可獲取被寫(xiě)入通道的ID,內(nèi)容,狀態(tài);
  • onServicesDiscovered:剛建立連接時(shí),設(shè)備擁有的服務(wù)被發(fā)現(xiàn);
  • onReadRemoteRssi:設(shè)備信號(hào)強(qiáng)度變化。

要處理手機(jī)與設(shè)備之間的業(yè)務(wù),BluetoothGattCallback是重點(diǎn),再各個(gè)回調(diào)方法中,結(jié)合自己的業(yè)務(wù)邏輯,基本可完成應(yīng)用的基礎(chǔ)功能:綁定(成功后是要寫(xiě)入手機(jī)本地?cái)?shù)據(jù)庫(kù)的,與藍(lán)牙無(wú)關(guān)就不貼了)、斷開(kāi)報(bào)警、信號(hào)弱時(shí)提醒距離遠(yuǎn)、接收設(shè)備指令來(lái)完成對(duì)應(yīng)動(dòng)作……

4. 附錄:

上面的代碼中有一些方法代碼缺失,下面是BluetoothLeService.java完整代碼:

package com.powerstick.beaglepro.services;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.support.v7.app.NotificationCompat;
import android.telephony.TelephonyManager;
import android.text.TextUtils;

import com.afap.utils.ByteUtils;
import com.powerstick.beaglepro.MyApplication;
import com.powerstick.beaglepro.R;
import com.powerstick.beaglepro.event.BatteryEvent;
import com.powerstick.beaglepro.event.BindEvent;
import com.powerstick.beaglepro.event.FirmwareEvent;
import com.powerstick.beaglepro.event.StatusEvent;
import com.powerstick.beaglepro.greendao.Beagle;
import com.powerstick.beaglepro.greendao.BeagleDao;
import com.powerstick.beaglepro.receiver.GattUpdateReceiver;
import com.powerstick.beaglepro.util.BluetoothUtils;
import com.powerstick.beaglepro.util.Utils;
import com.tencent.bugly.crashreport.BuglyLog;

import org.greenrobot.eventbus.EventBus;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import de.greenrobot.dao.query.QueryBuilder;


public class BluetoothLeService extends Service {
    private final static String TAG = "BluetoothLeService";
    private final IBinder mBinder = new LocalBinder();
    private BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;
    // 記錄MAC對(duì)應(yīng)的BluetoothGatt,可通過(guò)MAC來(lái)獲取各個(gè)設(shè)備的BluetoothGatt
    private Map<String, BluetoothGatt> mBluetoothGatts = new HashMap<>();

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {

        @Override
        public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic
                characteristic) {
            dealWithData(gatt, characteristic);
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                dealWithData(gatt, characteristic);
            } else {
                BuglyLog.e(TAG, "讀取通道信息失敗:" + characteristic.getUuid());
            }
        }

        @Override
        public void onConnectionStateChange(final BluetoothGatt gatt, final int status, final int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                BuglyLog.i(TAG, "BluetoothGatt連接上,MAC:" + gatt.getDevice().getAddress());

                gatt.discoverServices();
                mBluetoothGatts.put(gatt.getDevice().getAddress(), gatt);

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                dealDeviceDisconnected(gatt);
                BuglyLog.w(TAG, "BluetoothGatt斷開(kāi),MAC:" + gatt.getDevice().getAddress());
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);

            String uuidStr = characteristic.getUuid().toString();

            BuglyLog.e(TAG, "onCharacteristicWrite-->\nmac:" + gatt.getDevice().getAddress() + "\nuuid:" + uuidStr +
                    "\n發(fā)送的值:" + ByteUtils.byteArrayToHexString(characteristic.getValue()) + "\nstatus:" + status);

            if (TextUtils.equals(uuidStr, BluetoothUtils.UUID_S_EXTRA_C.toString())) { // 設(shè)備信息設(shè)置

                StatusEvent e = new StatusEvent();
                String action = "";

                if (characteristic.getValue() == BluetoothUtils.VALUE_MODE_THETHER) {
                    action = StatusEvent.ACTION_MODE_THETHER;
                } else if (characteristic.getValue() == BluetoothUtils.VALUE_MODE_FIND) {
                    action = StatusEvent.ACTION_MODE_FIND;
                } else if (characteristic.getValue() == BluetoothUtils.VALUE_FIND_LIGHT_ON) {
                    action = StatusEvent.ACTION_FIND_LIGHT_ON;
                } else if (characteristic.getValue() == BluetoothUtils.VALUE_FIND_LIGHT_OFF) {
                    action = StatusEvent.ACTION_FIND_LIGHT_OFF;
                } else if (characteristic.getValue() == BluetoothUtils.VALUE_TETHER_BEEP_ON) {
                    action = StatusEvent.ACTION_TETHER_BEEP_ON;
                } else if (characteristic.getValue() == BluetoothUtils.VALUE_TETHER_BEEP_OFF) {
                    action = StatusEvent.ACTION_TETHER_BEEP_OFF;
                }


                e.setAction(action);
                e.setMac(gatt.getDevice().getAddress());
                EventBus.getDefault().post(e);
            } else if (TextUtils.equals(uuidStr, BluetoothUtils.UUID_S_IMMEDIATE_C_ALERT.toString())) { // 立即警報(bào)設(shè)置

                StatusEvent e = new StatusEvent();
                e.setAction(StatusEvent.ACTION_IMMEDIATE);
                e.setMac(gatt.getDevice().getAddress());
                EventBus.getDefault().post(e);

            } else if (TextUtils.equals(uuidStr, BluetoothUtils.UUID_S_EXTRA_C_LOGIN.toString())) {

                // 通知綁定頁(yè)面
                BindEvent e = new BindEvent();
                e.setAction(BindEvent.ACTION_BIND_SUCCESS);
                e.setMac(gatt.getDevice().getAddress());
                EventBus.getDefault().post(e);

            } else if (TextUtils.equals(uuidStr, BluetoothUtils.UUID_S_EXTRA_C_UNBIND.toString())) { // 解綁命令
                QueryBuilder qb = MyApplication.getInstance().getDaoSession().getBeagleDao().queryBuilder();
                qb.where(BeagleDao.Properties.Mac.eq(gatt.getDevice().getAddress()));
                List<Beagle> mBeagles = qb.list();

                Beagle beagle;
                if (mBeagles.size() > 0) {
                    beagle = mBeagles.get(0);
                } else {
                    return;
                }

                // 升級(jí)完畢后的解綁,不做刪除
//                if (beagle.getUpdateStatus() == Beagle.UPDATE_COMPLETED) {
//                    BuglyLog.d(TAG, "解綁--升級(jí)完畢");
//                    beagle.setUpdateStatus(Beagle.UPDATE_NONE);
//                    MyApplication.getInstance().getDaoSession().getBeagleDao().update(beagle);
//                } else
                if (beagle.getUpdateStatus() == Beagle.UPDATE_PROCESSING) {
                    BuglyLog.d(TAG, "解綁--升級(jí)…………");
                    mBluetoothGatts.remove(gatt.getDevice().getAddress());
                } else {
                    BuglyLog.d(TAG, "解綁?。?!");
                    MyApplication.getInstance().getDaoSession().getBeagleDao().deleteByKey(beagle.getMac());
                    StatusEvent e = new StatusEvent();
                    e.setAction(StatusEvent.ACTION_UNBIND);
                    e.setMac(gatt.getDevice().getAddress());
                    EventBus.getDefault().post(e);
                }
            }
        }

        @Override
        public void onServicesDiscovered(final BluetoothGatt gatt, final int status) {
            BuglyLog.w(TAG, "onServicesDiscovered received: " + status);
            if (status == BluetoothGatt.GATT_SUCCESS) {
                dealServicesDiscoverd(gatt);
            } else {
                BuglyLog.w(TAG, "onServicesDiscovered received: " + status);
            }
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {

                StatusEvent e = new StatusEvent();
                e.setAction(StatusEvent.ACTION_RSSI);
                e.setMac(gatt.getDevice().getAddress());
                e.setRssi(rssi);
                EventBus.getDefault().post(e);

            } else {
                BuglyLog.w(TAG, "onReadRemoteRssi received: " + status);
            }
        }
    };

    public boolean initialize() {
        // For API level 18 and above, get a reference to BluetoothAdapter through
        // BluetoothManager.
        if (mBluetoothManager == null) {
            mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
            if (mBluetoothManager == null) {
                BuglyLog.e(TAG, "Unable to initialize BluetoothManager.");
                return false;
            }
        }

        mBluetoothAdapter = mBluetoothManager.getAdapter();
        if (mBluetoothAdapter == null) {
            BuglyLog.e(TAG, "Unable to obtain a BluetoothAdapter.");
            return false;
        }

        return true;
    }


    public BluetoothGatt getGatt(String mac) {
        return mBluetoothGatts.get(mac);
    }

    public void close() {
        for (BluetoothGatt gatt : mBluetoothGatts.values()) {
            if (gatt != null) {
                gatt.close();
                gatt = null;

            }
        }
    }


    public void clear() {
        if (mBluetoothAdapter == null) {
            BuglyLog.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return;
        }
        mBluetoothGatts.clear();
    }

    /**
     * 連接藍(lán)牙設(shè)備
     *
     * @param mac mac
     */
    public boolean connect(String mac) {
        if (mBluetoothAdapter == null || mac == null) {
            BuglyLog.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return false;
        }

        List<BluetoothDevice> connectDevices = getConnectedDevices();

        for (BluetoothDevice bd : connectDevices) {
            if (TextUtils.equals(bd.getAddress(), mac)) {
                BuglyLog.d(TAG, "該設(shè)備已經(jīng)連接啦:" + mac);
                return true;
            }
        }

        // 使用之前連接過(guò)的
        if (mBluetoothGatts.get(mac) != null) {
            if (mBluetoothGatts.get(mac).connect()) {
                BuglyLog.d(TAG, "使用之前連接過(guò)的:" + mac);
                return true;
            } else {
                return false;
            }
        }

        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mac);
        if (device == null) {
            BuglyLog.w(TAG, "Device not found.  Unable to connect.");
            return false;
        }
        device.connectGatt(this, false, mGattCallback);
        BuglyLog.d(TAG, "創(chuàng)建一個(gè)新連接,MAC=" + mac);
        return true;
    }

    /**
     * Disconnects an existing connection or cancel a pending connection. The disconnection result
     * is reported asynchronously through the
     * {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
     * callback.
     */
    public void disconnect(String mac) {
        if (mBluetoothAdapter == null || mBluetoothGatts.get(mac) == null) {
            BuglyLog.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        BluetoothGatt gatt = mBluetoothGatts.get(mac);
        gatt.disconnect();
        gatt.close();
        mBluetoothGatts.remove(mac);
    }

    /**
     * Retrieves a list of supported GATT services on the connected device. This should be
     * invoked only after {@code BluetoothGatt#discoverServices()} completes successfully.
     *
     * @return A {@code List} of supported services.
     */
    public List<BluetoothGattService> getSupportedGattServices(String mac) {
        if (mBluetoothGatts.get(mac) == null) {
            return null;
        }
        return mBluetoothGatts.get(mac).getServices();
    }

    /**
     * 讀取目標(biāo)通道數(shù)據(jù)
     *
     * @param mac            目標(biāo)設(shè)備MAC
     * @param characteristic 目標(biāo)通道
     */
    public void readCharacteristic(String mac, BluetoothGattCharacteristic characteristic) {
        if (mBluetoothAdapter == null || mBluetoothGatts.get(mac) == null) {
            BuglyLog.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        mBluetoothGatts.get(mac).readCharacteristic(characteristic);
    }

    /**
     * 向目標(biāo)通道寫(xiě)入數(shù)據(jù)
     *
     * @param mac            目標(biāo)設(shè)備MAC
     * @param characteristic 目標(biāo)通道
     */
    public boolean writeCharacteristic(String mac, BluetoothGattCharacteristic characteristic) {
        if (mBluetoothAdapter == null || mBluetoothGatts.get(mac) == null) {
            BuglyLog.w(TAG, "BluetoothAdapter not initialized");
            return false;
        }

        return mBluetoothGatts.get(mac).writeCharacteristic(characteristic);
    }

    /**
     * 設(shè)置監(jiān)聽(tīng)通道通知
     *
     * @param mac            目標(biāo)設(shè)備MAC
     * @param characteristic 目標(biāo)通道
     * @param enabled        是否接收通知
     */
    public void setCharacteristicNotification(String mac, BluetoothGattCharacteristic characteristic, boolean enabled) {
        if (mBluetoothAdapter == null || mBluetoothGatts.get(mac) == null) {
            BuglyLog.w(TAG, "BluetoothAdapter未初始化");
            return;
        }
        mBluetoothGatts.get(mac).setCharacteristicNotification(characteristic, enabled);
    }

    public List<BluetoothDevice> getConnectedDevices() {
        if (mBluetoothManager == null) {
            return null;
        }

        return mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER);
    }

    public BluetoothGattService getService(String mac, UUID uuid) {
        if (mBluetoothGatts.get(mac) == null) {
            BuglyLog.w(TAG, "BluetoothGatt未初始化");
            return null;
        }
        return mBluetoothGatts.get(mac).getService(uuid);
    }

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

    @Override
    public boolean onUnbind(final Intent intent) {
        close();
        return super.onUnbind(intent);
    }

    public class LocalBinder extends Binder {
        public BluetoothLeService getService() {
            return BluetoothLeService.this;
        }
    }


    /**
     * 處理Service被發(fā)現(xiàn)
     */
    private void dealServicesDiscoverd(BluetoothGatt gatt) {
        String mac = gatt.getDevice().getAddress();
        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
            mMediaPlayer.stop();
        }

        displayGattServices(getSupportedGattServices(mac), mac);
    }

    /**
     * 處理設(shè)備斷開(kāi)的情況
     */
    private void dealDeviceDisconnected(BluetoothGatt gatt) {
        Context context = getApplicationContext();
        String mac = gatt.getDevice().getAddress();


        // TODO
        BuglyLog.i(TAG, "斷開(kāi)連接 響鈴:" + mac);
        mBluetoothGatts.get(mac).close();
        mBluetoothGatts.remove(mac);

        QueryBuilder qb = MyApplication.getInstance().getDaoSession().getBeagleDao().queryBuilder();
        qb.where(BeagleDao.Properties.Mac.eq(mac));
        List<Beagle> mBeagles = qb.list();

        Beagle beagle;
        if (mBeagles.size() > 0) {
            beagle = mBeagles.get(0);
        } else {
            return;
        }

        if (beagle.getPhoneAlarm() && Utils.isNeedNotify(context, beagle) && beagle.getMode() == 0) {

            bellToRemind();

            Intent i = new Intent(GattUpdateReceiver.ACTION_CANCEL);
            PendingIntent pIntent = PendingIntent.getBroadcast(context, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
            Uri ringUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            Notification notify = new NotificationCompat
                    .Builder(context)
                    .setTicker(context.getString(R.string.app_name))
                    .setContentTitle(context.getString(R.string.app_name))
                    .setContentText("Device " + beagle.getAlias() + " Disconnected")
                    .setSmallIcon(R.drawable.ic_notification)
                    .setAutoCancel(false)
                    .setOngoing(true)
                    .setContentIntent(pIntent)
                    .setSound(ringUri)
                    .build();
            MyApplication.getInstance().getmNotificationManager().notify(GattUpdateReceiver.NOTIFY_ID, notify);
        }

        // 通知主界面
        StatusEvent e = new StatusEvent();
        e.setAction(StatusEvent.ACTION_GATT_DISCONNECTED);
        e.setMac(mac);
        EventBus.getDefault().post(e);
    }


    private static MediaPlayer mMediaPlayer;

    /**
     * 處理接收到的數(shù)據(jù)
     */
    private void dealWithData(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
        BuglyLog.d(TAG, "進(jìn)入方法:dealWithData()");

        final UUID uuid = characteristic.getUuid();
        final String mac = gatt.getDevice().getAddress();
        final byte[] dataArr = characteristic.getValue();
        String dataString = new String(dataArr);

        BuglyLog.i(TAG, "接收到地址:" + mac);
        BuglyLog.i(TAG, "接收到參數(shù):" + ByteUtils.byteArrayToHexString(dataArr));
        BuglyLog.i(TAG, "接收到參數(shù):" + dataString);

        if (BluetoothUtils.UUID_S_KEY_C_PRESS.equals(uuid)) {
            int v = ByteUtils.getIntFromByte(dataArr[0]);

            if (v == 1) { // 短按
                // 通知主界面
                StatusEvent e = new StatusEvent();
                e.setAction(StatusEvent.ACTION_PRESS_SHORT);
                e.setMac(mac);
                EventBus.getDefault().post(e);

            } else if (v == 2) { // 長(zhǎng)按
                if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
                    mMediaPlayer.stop();
                } else {
                    bellToRemind();
                }
            }

        } else if (BluetoothUtils.UUID_S_BATTERY_C_LEVEL.equals(uuid)) {

            // 通知設(shè)備信息界面
            BatteryEvent e = new BatteryEvent();
            e.setMac(mac);
            e.setLevel(ByteUtils.getIntFromByte(dataArr[0]));
            EventBus.getDefault().post(e);

        } else if (BluetoothUtils.UUID_S_DEVICEINFO_C_FIRMWARE.equals(uuid)) {

            // 通知設(shè)備信息界面
            FirmwareEvent e = new FirmwareEvent();
            e.setMac(mac);
            e.setVersion(dataString);
            EventBus.getDefault().post(e);

        }
//        else if (BluetoothUtils.UUID_S_EXTRA_C_LOGIN.equals(uuid)) {
//            // 寫(xiě)入認(rèn)證信息后,設(shè)備返回pass則綁定成功
//            String result = new String(dataArr);
//            if (TextUtils.equals(result.toLowerCase(), "pass")) {
//                // 通知綁定頁(yè)面
//                BindEvent e = new BindEvent();
//                e.setAction(BindEvent.ACTION_BIND_SUCCESS);
//                e.setMac(mac);
//                EventBus.getDefault().post(e);
//            }
//        }

    }


    void bellToRemind() {
        AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        int max = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
        am.setStreamVolume(AudioManager.STREAM_MUSIC, max, AudioManager.FLAG_PLAY_SOUND);

        if (mMediaPlayer != null && mMediaPlayer.isPlaying()) {
            mMediaPlayer.stop();
        }

        mMediaPlayer = MediaPlayer.create(getApplicationContext(), R.raw.helium);
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mMediaPlayer.setLooping(false); //循環(huán)播放
        mMediaPlayer.start();
    }

    BluetoothGattCharacteristic mNotifyCharacteristic;

    private void displayGattServices(List<BluetoothGattService> gattServices, String mac) {
        if (gattServices == null) {
            return;
        }

        for (final BluetoothGattService gattService : gattServices) {
            final List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();

            String uuid0 = gattService.getUuid().toString();

            BuglyLog.i(TAG, "服務(wù)uuid0=" + uuid0);
            // Loops through available Characteristics.
            for (final BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                UUID uuid = gattCharacteristic.getUuid();

                BuglyLog.d(TAG, "服務(wù)uuid=" + uuid);
                // 監(jiān)聽(tīng)按鍵指令以及認(rèn)證結(jié)果信息
                if (BluetoothUtils.UUID_S_KEY_C_PRESS.equals(uuid) ||
                        BluetoothUtils.UUID_S_EXTRA_C_LOGIN.equals(uuid)) {
                    BuglyLog.i(TAG, "啟動(dòng)監(jiān)聽(tīng)通知服務(wù)uuid=" + uuid);
                    int charaProp = gattCharacteristic.getProperties();
//                    if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
//                        BuglyLog.i(TAG, "讀取=" + uuid);
//                        // If there is an active notification on a characteristic, clear
//                        // it first so it doesn't update the data field on the user interface.
//                        if (mNotifyCharacteristic != null) {
//                            MyApplication.getInstance().mBluetoothLeService.setCharacteristicNotification
//                                    (mac, mNotifyCharacteristic, true);
//                            mNotifyCharacteristic = null;
//                        }
//                    }
                    if ((charaProp | BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0) {
                        mNotifyCharacteristic = gattCharacteristic;
                        setCharacteristicNotification(mac, gattCharacteristic, true);
                    }
                }
            }
        }

        // 建立連接后,搜尋到設(shè)備服務(wù),且該設(shè)備并未找到綁定記錄,則寫(xiě)入認(rèn)證信息進(jìn)行綁定
        String imei = ((TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE)).getDeviceId();
        byte[] loginValue = new byte[20];
        // 認(rèn)證的具體內(nèi)容我就不寫(xiě)了,這個(gè)是要與設(shè)備固件開(kāi)發(fā)約定好的

        boolean loginFlag = BluetoothUtils.sendValueToBle(mac, BluetoothUtils.UUID_S_EXTRA, BluetoothUtils
                .UUID_S_EXTRA_C_LOGIN, loginValue);
        BuglyLog.i(TAG, "寫(xiě)入認(rèn)證信息=" + loginFlag);
        if (!loginFlag) {
            BindEvent e = new BindEvent();
            e.setAction(BindEvent.ACTION_BIND_FAIL);
            e.setMac(mac);
            EventBus.getDefault().post(e);
        }
    }
}

我……寫(xiě)的好亂,多包涵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容