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;
}
}



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;
}
}
}



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)功能。
}



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();
}
});
}
}

1289



被折叠的 条评论
为什么被折叠?



