Android 4.4.2上與BLE 藍牙鎖設備的通訊


Android從4.3(Api level 18)開始支持BLE的開發,本文記錄了Android 4.4.2設備與BLE設備通訊的流程。

權限需求:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

步驟:
1.獲取藍牙服務
BluetoothManager btManager= (BluetoothManager) this.getSystemService(Context.BLUETOOTH_SERVICE);
2.獲取藍牙設備管理器(適配器)
BluetoothAdapter mBluetoothAdapter = btManager.getAdapter();
3.判斷設備是否支持BLE藍牙通訊,支持則判斷藍牙是否已開啟,未開啟藍牙的設置開啟。
if (mBluetoothAdapter != null && (!mBluetoothAdapter.isEnabled())){
mBluetoothAdapter.enable();//打開藍牙
}
4.掃描當前附近的藍牙BLE設備(這個操作比較耗電,要適時地停止)
5.停止設備掃描
6.與指定BLE設備建立Gatt連接
7.在連接成功后,設置掃描BLE設備支持的service和characteristic,並設置。這里需要注意,需要開啟通知的,需要設置相應描述符。
8.讀寫操作
9.斷開Gatt連接
10.關閉Gatt連接

在開發過程中,遇到的主要問題是onCharacteristicWrite失敗回調,這個可能跟低功耗藍牙外設有關,需要斷開並關閉Gatt連接重新建立

 下面是主要參考代碼

package com.rollup.bluetoothlock;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.UUID;

import com.android.peephole.MyApplication;
import com.rollup.bluetoothlock.MyLog;
import com.rollup.bluetoothlock.Utils;
import com.rollup.bluetoothlock.Value;



import android.R.integer;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothAdapter.LeScanCallback;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Handler;
import android.os.Message;
import android.widget.EditText;
import android.widget.Toast;

public class BleManager {
    private static final String TAG = "BleManager";
    public static final int ERROR_NO_ERROR = 0;//成功
    public static final int ERROR_BTDEVICE_EXC_FAIL = 1;// 藍牙鎖端執行錯誤
    public static final int ERROR_PSD_ERROR = 2; // 鑰匙錯誤
    public static final int ERROR_CONNECT_FAIL = 3;
    public static final int ERROR_DEFAULT = 4;
    public static final int ERROR_NOT_FOUND_DEVICE = 5;// 未掃描到指定編碼的鎖
    public static final int ERROR_HAVE_CONNECTED = 6;//上次連接未執行完畢
    public static final int ERROR_NO_DEVICE = 7;//設備沒有初始化
    public static final int ERROR_CREATE_FAIL = 8;

    private static final int STOP_LESCAN = 1;
    private final int OVER_TIMER = 60 * 1000;// 掃描超時時間

    private Context mContext = null;
    private BluetoothAdapter mBluetoothAdapter = null;
    private BluetoothManager mBluetoothManager = null;
    public BluetoothDevice mBluetoothDevice = null;
    private BluetoothGatt mBluetoothGatt;
    private static boolean isScanning = false;
    private BluetoothGattCharacteristic writeCharacteristic = null;
    private static boolean isConnectToDevice = false;
    private String btName = null;
    private String psd = null;
    private boolean hasExcuteOpenDoor = false;// 開門命令已執行
    private byte[] devceKey;

    private static boolean haveRetry = false;
    private static BleManager instance = null;
    private MyHandler mHandler = null;

    public static long lastOpendoorTime = 0;

    private OnBleScanOpenDoorCallback openDoorCallback = null;

    public interface OnBleScanOpenDoorCallback {
        public void openDoorSuc();
        public void openDoorFail(int error);
    }

    private BleManager(Context context, String btName, String psd) {
        this.mContext = context;
        initBluetooth();
        if (mBluetoothManager == null) {
            MyLog.e(TAG, "Unable to initialize BluetoothManager.");
            return;
        }
        this.btName = btName;
        this.psd = psd;
        devceKey = new byte[16];
    }

    public static BleManager getInstance(String btName, String psd) {
        if (instance == null) {
            instance = new BleManager(MyApplication.getMyApplication(), btName,
                    psd);
        } else {
            instance.setBTinfo(btName, psd);
        }
        return instance;
    }

    private void setBTinfo(String name, String psd) {
        this.btName = name;
        this.psd = psd;
    }

    private void initBluetooth() {
        mHandler = new MyHandler(this);
        mBluetoothManager = (BluetoothManager) mContext
                .getSystemService(Context.BLUETOOTH_SERVICE);
        if (mBluetoothManager != null) {
            mBluetoothAdapter = mBluetoothManager.getAdapter();
            if (mBluetoothAdapter != null) {
                if (!mBluetoothAdapter.isEnabled()) {
                    mBluetoothAdapter.enable(); // 打開藍牙
                }
            }
        }
    }
    
    /**
     * 是否空閑可用
     * @return
     */
    public static boolean isFree(){
        return (!isConnectToDevice)&&(!isScanning);
    }

    public void startLeScan(boolean autoConnect) {
        if (mBluetoothAdapter == null) {
            return;
        }
        if (btName == null || btName.length() == 0) {
            return;
        }

        if (isScanning) {
            return;
        }
        isScanning = true;

        if (autoConnect) {
            mBluetoothAdapter.startLeScan(mLeScanCallback2);
        } else {
            mBluetoothAdapter.startLeScan(mLeScanCallback); // 此mLeScanCallback為回調函數
        }

        mHandler.sendEmptyMessageDelayed(STOP_LESCAN, OVER_TIMER); // 這個搜索30秒,如果搜索不到則停止搜索
    }

    private void stopLeScan() {
        if (mHandler != null && mHandler.hasMessages(STOP_LESCAN)) {
            mHandler.removeMessages(STOP_LESCAN);
        }
        if (mBluetoothAdapter == null) {
            return;
        }

        if (!isScanning) {
            return;
        }
        mBluetoothAdapter.stopLeScan(mLeScanCallback);
        mBluetoothAdapter.stopLeScan(mLeScanCallback2);
        isScanning = false;
    }

    private LeScanCallback mLeScanCallback = new LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice device, int arg1, byte[] arg2) {
            MyLog.i(TAG, "onLeScan() DeviceName------>" + device.getName()); // 在這里可通過device這個對象來獲取到搜索到的ble設備名稱和一些相關信息
            if (device.getAddress() != null) {
                if (device.getName().toLowerCase().replace("_", "")
                        .contentEquals(btName.toLowerCase().replace(" ", ""))) {
                    mBluetoothDevice = device;
                    stopLeScan();
                }
            }
        }
    };

    private LeScanCallback mLeScanCallback2 = new LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice device, int arg1, byte[] arg2) {
            MyLog.i(TAG, "onLeScan() DeviceName------>" + device.getName()); // 在這里可通過device這個對象來獲取到搜索到的ble設備名稱和一些相關信息
            if (device.getAddress() != null) {
                if (device.getName().toLowerCase().replace("_", "")
                        .contentEquals(btName.toLowerCase().replace(" ", ""))) {
                    mBluetoothDevice = device;
                    stopLeScan();
                    connect();
                }
            }
        }
    };

    private static class MyHandler extends Handler {
        WeakReference<BleManager> wf = null;

        public MyHandler(BleManager manager) {
            // TODO Auto-generated constructor stub
            wf = new WeakReference<BleManager>(manager);
        }

        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            switch (msg.what) {
            case STOP_LESCAN:
                MyLog.i(TAG,  "MyHandler handleMessage STOP_LESCAN");
                if (wf.get()!=null){
                    wf.get().stopLeScan();
                }
                MyLog.i(TAG, "release(), Scan time is up");
                break;
            }
        }
    }

    public int connect() {
        if (mBluetoothDevice == null) {
            MyLog.i(TAG, "BluetoothDevice is null.");
            return ERROR_NO_DEVICE;
        }
        
        if(isConnectToDevice){
            MyLog.i(TAG, "Have connected to device");
            return ERROR_HAVE_CONNECTED;
        }
        isConnectToDevice = true;
        hasExcuteOpenDoor = false;

        // 兩個設備通過BLE通信,首先需要建立GATT連接。這里我們講的是Android設備作為client端,連接GATT Server

        mBluetoothGatt = mBluetoothDevice.connectGatt(mContext, false,
                mGattCallback); // mGattCallback為回調接口

        if (mBluetoothGatt != null) {

            if (mBluetoothGatt.connect()) {
                MyLog.d(TAG, "Connect succeed.");
                return ERROR_NO_ERROR;
            } else {
                MyLog.d(TAG, "Connect fail.");
                return ERROR_CONNECT_FAIL;
            }
        } else {
            MyLog.d(TAG, "BluetoothGatt null.");
            return ERROR_CREATE_FAIL;
        }
    }

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status,
                int newState) {
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                isConnectToDevice = true;
                gatt.discoverServices(); // 執行到這里其實藍牙已經連接成功了
                MyLog.i(TAG, "Connected to GATT server.");
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                if (!hasExcuteOpenDoor) {
                    disconnect();
                    retryUnlock();
                    if (!haveRetry) {
                        //已失敗重試過
                        if (openDoorCallback != null) {
                            openDoorCallback.openDoorFail(ERROR_CONNECT_FAIL);
                        }
                    } 
                } else {
                    MyLog.i(TAG, "BluetoothProfile.STATE_DISCONNECTED  hasExcuteOpenDoor=TRUE");
                    haveRetry = false;
                    disconnect();
                }
                MyLog.i(TAG, "BluetoothProfile.STATE_DISCONNECTED --release()");
            }
        }

        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                MyLog.i(TAG, "onServicesDiscovered");
                List<BluetoothGattService> services = gatt.getServices();
                for (int i = 0; i < services.size(); i++) {
                    MyLog.i(TAG, "[Service " + i + "] uuid:"
                            + services.get(i).getUuid());
                    if (services.get(i).getUuid().equals(Value.uuid)) {
                        List<BluetoothGattCharacteristic> characteristics = services
                                .get(i).getCharacteristics();
                        for (int j = 0; j < characteristics.size(); j++) {
                            MyLog.i(TAG, "[Characteristic]"
                                    + characteristics.get(j).getUuid());
                            if (characteristics.get(j).getUuid()
                                    .equals(Value.CHARACTERISTIC_READ)) {
                                boolean res = mBluetoothGatt
                                        .setCharacteristicNotification(
                                                characteristics.get(j), true);
                                // 打開通知描述
                                for (BluetoothGattDescriptor descriptor : characteristics
                                        .get(j).getDescriptors()) {
                                    descriptor
                                            .setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                                    gatt.writeDescriptor(descriptor);
                                    MyLog.i(TAG,
                                            "Characteristic set notification is Success!");
                                }
                                MyLog.i(TAG,
                                        "onServicesDiscovered setCharacteristicNotification result="
                                                + res);
                                break;
                            }
                        }
                        characteristics = null;
                    }
                }

                for (int i = 0; i < services.size(); i++) {
                    MyLog.i(TAG, "[Service " + i + "] uuid:"
                            + services.get(i).getUuid());
                    if (services.get(i).getUuid().equals(Value.uuid)) {
                        List<BluetoothGattCharacteristic> characteristics = services
                                .get(i).getCharacteristics();
                        for (int j = 0; j < characteristics.size(); j++) {
                            MyLog.i(TAG, "[Characteristic]"
                                    + characteristics.get(j).getUuid());
                            if (characteristics.get(j).getUuid()
                                    .equals(Value.CHARACTERISTIC_WRITE)) {
                                writeCharacteristic = characteristics.get(j);
                                final int charaProp = characteristics.get(j)
                                        .getProperties();
                                // 如果該char可寫
                                if ((charaProp | BluetoothGattCharacteristic.PROPERTY_READ) > 0) {
                                    byte[] value = new byte[] { 0x01, 0x00,
                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                            0x00, 0x00, 0x00 };
                                    characteristics.get(j).setValue(value);
                                    writeCharacteristic
                                            .setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
                                    mBluetoothGatt
                                            .writeCharacteristic(characteristics
                                                    .get(j));
                                    value = null;
                                }
                                break;
                            }
                        }
                        characteristics = null;
                    }
                }
                services = null;
            } else {
                MyLog.i(TAG, "onServicesDiscovered status------>" + status);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
            MyLog.i(TAG,
                    "onCharacteristicRead------>"
                            + Utils.bytesToHexString(characteristic.getValue()));

        }

        

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic) {
            MyLog.i(TAG,
                    "onCharacteristicChanged------>"
                            + Utils.bytesToHexString(characteristic.getValue()));
            MyLog.i(TAG, "UUID------>" + characteristic.getUuid().toString());

            if (Value.CHARACTERISTIC_READ.equals(characteristic.getUuid())) {
                byte[] value = characteristic.getValue();
                if ((value[0] & 0xFF) == 0x81) {
                    for (int i = 0; i < 16; i++) {
                        devceKey[i] = value[i + 1];
                    }
                    // MyLog.i(TAG, "加密秘鑰為:"+Utils.bytesToHexString(devceKey));
                    if (writeCharacteristic != null) {
                        byte[] cmd = new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                0x00, 0x00, 0x00 };
                        if (psd.length() == 8) {
                            int j = 0;
                            for (int i = 0; i < 4; i++) {
                                cmd[5 + i] = (byte) (((((Integer.valueOf(psd
                                        .charAt(j)) - 48) << 4) & (0xF0)) + ((Integer
                                        .valueOf(psd.charAt(j + 1)) - 48) & 0x0F)) & 0xFF);
                                MyLog.i(TAG, "cmd" + (9 + i) + "=" + cmd[9 + i]);
                                j = j + 2;
                            }
                        }
                        byte[] cmd_encrypt = Utils.enCode(devceKey, cmd);
                        if (cmd_encrypt != null) {
                            byte[] request = new byte[17];
                            request[0] = 0x03;
                            for (int i = 1; i < (cmd_encrypt.length < request.length ? cmd_encrypt.length
                                    : request.length); i++) {
                                request[i] = cmd_encrypt[i - 1];
                            }
                            writeCharacteristic.setValue(request);
                            writeCharacteristic
                                    .setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
                            // MyLog.i(TAG,
                            // "發送開鎖命令:"+Utils.bytesToHexString(request));
                            mBluetoothGatt
                                    .writeCharacteristic(writeCharacteristic);
                            request = null;
                        }
                        cmd_encrypt  = null;
                        cmd = null;
                    }

                } else if ((value[0] & 0xFF) == 0x83) {
                    byte[] res = new byte[16];
                    for (int i = 0; i < 16; i++) {
                        res[i] = value[i + 1];
                    }
                    // MyLog.i(TAG, "解密秘鑰為:"+Utils.bytesToHexString(devceKey));
                    // MyLog.i(TAG, "待解密數據為:"+Utils.bytesToHexString(res));
                    byte[] decode_res = Utils.deCode(devceKey, res);
                    hasExcuteOpenDoor = true;
                    if (decode_res != null) {
                        MyLog.i(TAG,
                                "獲取到藍牙開鎖返回數據:"
                                        + Utils.bytesToHexString(decode_res));
                        if ((decode_res[0] & 0xFF) == 0x01) {
                            if ((decode_res[1] & 0xFF) == 0x00) {
                                MyLog.i(TAG, "開鎖成功");

                                if (openDoorCallback != null) {
                                    openDoorCallback.openDoorSuc();
                                }
                                lastOpendoorTime = System.currentTimeMillis();
                            } else if ((decode_res[1] & 0xFF) == 0x01) {
                                MyLog.i(TAG, "開鎖失敗:命令執行失敗");
                                if (openDoorCallback != null) {
                                    openDoorCallback
                                            .openDoorFail(ERROR_BTDEVICE_EXC_FAIL);
                                }
                            } else if ((decode_res[1] & 0xFF) == 0x02) {
                                MyLog.i(TAG, "開鎖失敗:密鑰解密失敗,無效用戶密鑰");
                                if (openDoorCallback != null) {
                                    openDoorCallback
                                            .openDoorFail(ERROR_PSD_ERROR);
                                }
                            } else {
                                MyLog.e(TAG, "開鎖返回異常");
                                if (openDoorCallback != null) {
                                    openDoorCallback
                                            .openDoorFail(ERROR_DEFAULT);
                                }
                            }

                            new Timer().schedule(new TimerTask() {

                                @Override
                                public void run() {
                                    // TODO Auto-generated method stub
                                    sendEndCmd();
                                }
                            }, 500);

                        } else {
                            MyLog.e(TAG, "開鎖返回動作標志位異常,此時鎖還會再次返回其他數據");
                            if (openDoorCallback != null) {
                                openDoorCallback.openDoorFail(ERROR_DEFAULT);
                            }
                        }

                    } else {
                        MyLog.e(TAG, "藍牙開鎖數據獲取失敗");
                        if (openDoorCallback != null) {
                            openDoorCallback.openDoorFail(ERROR_DEFAULT);
                        }
//                        disconnect(true);
                    }
                    decode_res = null;
                    res = null;
                } else {
                    MyLog.e(TAG, " value[0] =  " + value[0]
                            + " ===release()    11111111");
//                    disconnect(true);
                }
                value = null;
            }
        }

        // 接受Characteristic被寫的通知,收到藍牙模塊的數據后會觸發onCharacteristicWrite
        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt,
                BluetoothGattCharacteristic characteristic, int status) {
            MyLog.i(TAG,
                    "onCharacteristicWrite status = " + status
                            + ",onCharacteristicWrite------>"
                            + Utils.bytesToHexString(characteristic.getValue()));
            if (status != 0) {
//                disconnect(true);
            }
        }
    };
    
    private void sendEndCmd() {
        if (writeCharacteristic != null) {
            byte[] cmd = new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                    0x00 };
            byte[] cmd_encrypt = Utils.enCode(devceKey, cmd);
            if (cmd_encrypt != null) {
                byte[] request = new byte[17];
                request[0] = 0x08;
                for (int i = 1; i < (cmd_encrypt.length < request.length ? cmd_encrypt.length
                        : request.length); i++) {
                    request[i] = cmd_encrypt[i - 1];
                }
                writeCharacteristic.setValue(request);
                writeCharacteristic
                        .setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
                mBluetoothGatt.writeCharacteristic(writeCharacteristic);
                request = null;
            }
            cmd = null;
            cmd_encrypt = null;
        }
        // release();
    }

    private void retryUnlock() {
        if (!haveRetry) {
            haveRetry = true;
            connect();
        } else {
            haveRetry = false;
            MyLog.i(TAG, "retryUnlock  haveRetry");
        }
    }

    public void setOpenDoorCallback(OnBleScanOpenDoorCallback callback) {
        openDoorCallback = callback;
    }
    
    public synchronized void disconnect() {
        MyLog.i(TAG, "disconnect");
        if (mBluetoothGatt != null) {
            mBluetoothGatt.disconnect();
            mBluetoothGatt.close();
            mBluetoothGatt = null;
        }
        isConnectToDevice = false;
    }
}
View Code
package com.example.common;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class Utils {

     /** Convert byte[] to hex string.這里我們可以將byte轉換成int,然后利用Integer.toHexString(int)來轉換成16進制字符串。  
     * @param src byte[] data  
     * @return hex string  
     */     
    public static String bytesToHexString(byte[] src){  
        StringBuilder stringBuilder = new StringBuilder("");  
        if (src == null || src.length <= 0) {  
            return null;  
        }  
        for (int i = 0; i < src.length; i++) {  
            int v = src[i] & 0xFF;  
            String hv = Integer.toHexString(v);  
            if (hv.length() < 2) {  
                stringBuilder.append(0);  
            }  
            stringBuilder.append(hv);  
        }  
        return stringBuilder.toString();  
    }  
    /** 
     * Convert hex string to byte[] 
     * @param hexString the hex string 
     * @return byte[] 
     */  
    public static byte[] hexStringToBytes(String hexString) {  
        if (hexString == null || hexString.equals("")) {  
            return null;  
        }  
        hexString = hexString.toUpperCase();  
        int length = hexString.length() / 2;  
        char[] hexChars = hexString.toCharArray();  
        byte[] d = new byte[length];  
        for (int i = 0; i < length; i++) {  
            int pos = i * 2;  
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));  
        }  
        return d;  
    }  
    
    /** 
     * Convert char to byte 
     * @param c char 
     * @return byte 
     */  
     private static byte charToByte(char c) {  
        return (byte) "0123456789ABCDEF".indexOf(c);  
    }  

    //將指定byte數組以16進制的形式打印到控制台  
    public static void printHexString( byte[] b) {    
       for (int i = 0; i < b.length; i++) {   
         String hex = Integer.toHexString(b[i] & 0xFF);   
         if (hex.length() == 1) {   
           hex = '0' + hex;   
         }   
         System.out.print(hex.toUpperCase() );   
       }   
      
    }  
    
    /**
     * 真正的加密過程
     * 1.通過密鑰得到一個密鑰專用的對象SecretKeySpec
     * 2.Cipher 加密算法,加密模式和填充方式三部分或指定加密算 (可以只用寫算法然后用默認的其他方式)Cipher.getInstance("AES");
     * @param key
     * @param src
     * @return
     * @throws Exception
     */
    public static byte[] enCode(byte[] key, byte[] src) {
        try {
            SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding"); 
            cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
            byte[] encrypted = cipher.doFinal(src);
            return encrypted;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            return null;
        }
        
    }
    
     /**
     * 解密
     * @param view
     */
    public static byte[] deCode(byte[] key, byte[] src){ 
        try {
            //獲取AESkey
            SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
            Cipher cipher = Cipher.getInstance("AES/ECB/ZeroBytePadding"); //AES/ECB/ZeroBytePadding
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            byte[] decrypted = cipher.doFinal(src);
            byte[] result;
            if (decrypted.length<16){
                result = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
                for (int i=0; i<decrypted.length; i++){
                    result[i]=decrypted[i];
                }
            }else{
                result = decrypted;
            }
            return result;
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
            return null;
        }
    }
}
View Code
package com.example.common;

import java.util.UUID;

public class Value {
    public static final String BLE_LOCK_SP_NAME = "BleLockConfig";
    public static final String KEY_BLE_LOCK_ID = "kEY_BLE_LOCK_ID";
    public static final String KEY_BLE_LOCK_KEY = "KEY_BLE_LOCK_KEY";
    
    public final static UUID uuid = UUID.fromString("0000ff12-0000-1000-8000-00805f9b34fb");
    public final static UUID CHARACTERISTIC_WRITE = UUID.fromString("0000ff01-0000-1000-8000-00805f9b34fb");//主機BLE發送給BLE模塊數據使用
    public final static UUID CHARACTERISTIC_READ = UUID.fromString("0000ff04-0000-1000-8000-00805f9b34fb");//BLE模塊發送給主機BLE數據使用,NOTIFY功能發送,前提是雙方連接上后,需要主機BLE主動打開BLE模塊的UUID=0XFF04(NOTIFY)功能。
}
View Code
package com.example.bluetoothdemo;

import com.example.common.BleManager;
import com.example.common.Utils;
import com.example.common.BleManager.OnBleScanOpenDoorCallback;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener, OnBleScanOpenDoorCallback{
    
    private final String TAG = "MainActivity";
    private final String KEY_BLE_LOCK_ID = "kEY_BLE_LOCK_ID";
    private final String KEY_BLE_LOCK_KEY = "KEY_BLE_LOCK_KEY";
    
    private BleManager mBleManager = null;
    
    private RelativeLayout relativeLayout = null;
    private EditText idEditText = null;
    private EditText psdEditText = null;
    private Button scanButton = null;
    private Button connectButton = null;
    private ProgressDialog progressDialog = null;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        
        relativeLayout = (RelativeLayout) findViewById(R.id.relativelayout);
        scanButton = (Button) findViewById(R.id.button_scan);    
        connectButton = (Button) findViewById(R.id.button_connect);
        idEditText = (EditText) findViewById(R.id.edittext_lock_id);
        psdEditText = (EditText) findViewById(R.id.edittext_psd);
        progressDialog = new ProgressDialog(this);
        progressDialog.setMessage(getString(R.string.waiting));
        
        SharedPreferences sp = getPreferences(MODE_PRIVATE);
        String bleName = sp.getString(KEY_BLE_LOCK_ID, "ZY121711240013");
        String blePsd = sp.getString(KEY_BLE_LOCK_KEY, "12345678");
        idEditText.setText(bleName);
        psdEditText.setText(blePsd);
        
        relativeLayout.setOnClickListener(this);
        scanButton.setOnClickListener(this);        
        connectButton.setOnClickListener(this);
        
        mBleManager = BleManager.getInstance(bleName, blePsd);  //這個this是一個上下文,只要在上面的BleManager工具類定義一個有參數就好
        mBleManager.setOpenDoorCallback(this);
    }
    
    @Override
    protected void onResume() {
        // TODO Auto-generated method stub
        super.onResume();
    }
    
    @Override
    protected void onPause() {
        // TODO Auto-generated method stub
        super.onPause();
        SharedPreferences sp = getPreferences(MODE_PRIVATE);
        Editor editable = sp.edit();
        editable.putString(KEY_BLE_LOCK_ID, idEditText.getText().toString().trim());
        editable.putString(KEY_BLE_LOCK_KEY, psdEditText.getText().toString().trim());
        editable.commit();
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        switch (v.getId()) {
        case R.id.button_scan:
            break;
        case R.id.relativelayout:
            InputMethodManager m = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            m .hideSoftInputFromWindow(relativeLayout.getWindowToken(), 0);//比如EditView
            break;
        case R.id.button_connect:
            progressDialog.show();
            int res = mBleManager.connect();
            
            if (res == BleManager.ERROR_NO_ERROR){
            }else if (res == BleManager.ERROR_HAVE_CONNECTED){
                //已經連接不能再次連
                progressDialog.dismiss();
            }else{
                mBleManager.startLeScan(true);
            }

            break;
        
        default:            
            break;
        }
    }

    @Override
    protected void onDestroy() {
        // TODO Auto-generated method stub
        
        if (mBleManager != null){
            mBleManager.setOpenDoorCallback(null);
            mBleManager.disconnect();
            mBleManager = null;
        }
        super.onDestroy();
    }


    @Override
    public void openDoorSuc() {
        // TODO Auto-generated method stub
        runOnUiThread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                if (progressDialog.isShowing()){
                    progressDialog.dismiss();
                }
                Toast.makeText(MainActivity.this, getString(R.string.open_door_suc), Toast.LENGTH_LONG).show();
            }
        });
        
    }

    @Override
    public void openDoorFail(final int error) {
        // TODO Auto-generated method stub
        runOnUiThread(new Runnable() {
            
            @Override
            public void run() {
                // TODO Auto-generated method stub
                if (progressDialog.isShowing()){
                    progressDialog.dismiss();
                }
                int resId  = R.string.error_default;
                if (error==BleManager.ERROR_BTDEVICE_EXC_FAIL){
                    resId = R.string.error_btdevice_exc_fail;
                }else if (error == BleManager.ERROR_CONNECT_FAIL){
                    resId = R.string.error_not_connect;
                }else if (error == BleManager.ERROR_PSD_ERROR){
                    resId = R.string.error_psd_error;
                }else if (error == BleManager.ERROR_NOT_FOUND_DEVICE){
                    resId = R.string.error_device_not_found;
                }
                Toast.makeText(MainActivity.this, resId, Toast.LENGTH_LONG).show();
            }
        });
        
    }
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM