1. 程式人生 > >android 藍芽BLE多連線

android 藍芽BLE多連線

最近做藍芽BLE的開發,此專案和網上別人的稍微有點不同,手機需要連線多個BLE裝置,此部分網上的資料很少,所以拿出來和大家分享一下

//初始化
private void initBt() {
		manager = BluetoothManager.getInstance();
		manager.setContext(this);
		if (!getPackageManager().hasSystemFeature(
				PackageManager.FEATURE_BLUETOOTH_LE)) {
			Toast.makeText(this, "您的手機不支援BLE", Toast.LENGTH_SHORT).show();
			finish();
		}
		BluetoothAdapter btaAdapter = BluetoothAdapter.getDefaultAdapter();
		if (!btaAdapter.isEnabled()) {
			btaAdapter.enable();
		}
		if (!manager.isScanning)
			new ScanLeTask().execute();

	}
//掃描ble 裝置
private class ScanLeTask extends AsyncTask<Void, Void, Void> {

		@Override
		protected Void doInBackground(Void... params) {

			manager.scanLeDevice(true, mLeScanCallback);
			return null;
		}

	}

	// Device scan callback.
	private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

		@Override
		public void onLeScan(final BluetoothDevice device, int rssi,
				byte[] scanRecord) {
			runOnUiThread(new Runnable() {

				@Override
				public void run() {
					Log.d(TAG, device.getName());
					BtDevice mDevice = new BtDevice(device.getAddress(),
							device.getName());
					if (!mList.contains(mDevice)) {
						mList.add(mDevice);
						View view = getLayoutInflater().inflate(
								R.layout.deviceitem, null);
						view.setTag(mList.size() - 1);
						TextView textView = (TextView) view
								.findViewById(R.id.name);
						Button button = (Button) view.findViewById(R.id.icon);
						button.setOnClickListener(new OnClickListener() {

							@Override
							public void onClick(View v) {
								View view = (View) v.getParent();
								int index = (Integer) view.getTag();
								manager.connect(mList.get(index).getAddr(),
										index);
								Log.d(TAG, "index is:" + index);
							}
						});
						textView.setText(mDevice.getName());
						container.addView(view);

					}
				}
			});
		}
	};

//封裝的核心類
public class BluetoothManager {

	protected static final String TAG = "BluetoothManager";
	private Context context;
	public boolean isScanning;
	private int index;

	private Handler handler = new Handler();
	// 10秒後停止查詢搜尋.
	private static final long SCAN_PERIOD = 10000;

	private static BluetoothAdapter btaAdapter = BluetoothAdapter
			.getDefaultAdapter();
	// public static BluetoothGatt mBluetoothGatt;
	private int disconStatus;
	public final static String ACTION_GATT_CONNECTED = "com.example.bluetooth.le.ACTION_GATT_CONNECTED";
	public final static UUID UUID_HEART_RATE_MEASUREMENT = UUID
			.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT);
	private static BluetoothManager instance;

	private BluetoothManager() {

	}

	public static BluetoothManager getInstance() {

		if (instance == null) {
			synchronized (BluetoothManager.class) {
				if (instance == null) {
					instance = new BluetoothManager();
				}
			}
		}
		return instance;
	}

	public void setContext(Context mContext) {
		context = mContext;
	}

	private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
		@Override
		public void onConnectionStateChange(BluetoothGatt gatt, int status,
				int newState) {
			if (newState == BluetoothProfile.STATE_CONNECTED) {

				Log.d(TAG, "Connected to GATT server.");
				// Attempts to discover services after successful connection.
				Log.d(TAG,
						"Attempting to start service discovery:"
								+ gatt.discoverServices());

			} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
				Log.d(TAG, "Disconnected from GATT server.");
				if (disconStatus == 129) {
					close(gatt);
					Log.d(TAG, "----129----");
					btaAdapter.disable();
					try {
						Thread.sleep(2500);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					btaAdapter.enable();
				}
			}
		}

		@Override
		public void onServicesDiscovered(BluetoothGatt gatt, int status) {
			if (status == BluetoothGatt.GATT_SUCCESS) {
				if (gatt == null)
					return;
				// writeData(gatt, new byte[] { 0x11, 0x12 });
				// displayGattServices(gatt.getServices());
				Log.d(TAG, "BluetoothGatt.GATT_SUCCESS");
			} else {
				Log.d(TAG, "onServicesDiscovered received: " + status);
				disconStatus = status;
			}
		}

		@Override
		public void onCharacteristicRead(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic, int status) {
			if (status == BluetoothGatt.GATT_SUCCESS) {
				// broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
				Log.d(TAG, "onCharacteristicRead");
				// Toast.makeText(BluetoothLeService.this,
				// "onCharacteristicRead successfully", 100).show();
			}
		}

		@Override
		public void onCharacteristicChanged(BluetoothGatt gatt,
				BluetoothGattCharacteristic characteristic) {
			// broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
			Log.d(TAG, "onCharacteristicChanged");
		}
	};

	public void writeData(BluetoothGatt gatt, byte[] datas) {
		if (/* btaAdapter == null || */gatt == null) {
			Log.w(TAG, "BluetoothGatt is null  can not writeData.");
			return;
		}
		BluetoothGattService gattService = gatt.getService(UUID
				.fromString(SampleGattAttributes.HEART_RATE_MEASUREMENT));
		if (gattService == null) {
			Log.w(TAG,
					"the gattService for BluetoothGattService is null,can not write data");
			return;
		}
		BluetoothGattCharacteristic characteristic = gattService
				.getCharacteristic(UUID
						.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
		if (characteristic == null) {
			Log.w(TAG,
					"the uuid for BluetoothGattCharacteristic is null,can not write data");
			return;
		}
		characteristic.setValue(datas);
		// gatt.writeCharacteristic(characteristic);
		Log.i(TAG,
				"writeCharacteristic"
						+ gatt.writeCharacteristic(characteristic));
	}

	/**
	 * Enables or disables notification on a give characteristic.
	 * 
	 * @param characteristic
	 *            Characteristic to act on.
	 * @param enabled
	 *            If true, enable notification. False otherwise.
	 */
	public void setCharacteristicNotification(
			BluetoothGattCharacteristic characteristic, boolean enabled) {
		BluetoothGatt gatt = MainActivity.mList.get(index).getmBluetoothGatt();
		if (btaAdapter == null || gatt == null) {
			Log.w(TAG, "BluetoothAdapter not initialized");
			return;
		}
		gatt.setCharacteristicNotification(characteristic, enabled);

		// This is specific to Heart Rate Measurement.
		if (UUID_HEART_RATE_MEASUREMENT.equals(characteristic.getUuid())) {
			BluetoothGattDescriptor descriptor = characteristic
					.getDescriptor(UUID
							.fromString(SampleGattAttributes.CLIENT_CHARACTERISTIC_CONFIG));
			descriptor
					.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
			gatt.writeDescriptor(descriptor);
		}
	}

	private boolean isPrepared;

	public void scanLeDevice(final boolean enable,
			final BluetoothAdapter.LeScanCallback mLeScanCallback) {
		if (!isPrepared) {
			isPrepared = true;
			Looper.prepare();
		}
		if (enable) {
			// Stops scanning after a pre-defined scan period.
			handler.postDelayed(new Runnable() {
				@Override
				public void run() {
					isScanning = false;
					btaAdapter.stopLeScan(mLeScanCallback);
					Log.d(TAG, "STOP....");
				}
			}, SCAN_PERIOD);
			isScanning = true;
			btaAdapter.startLeScan(mLeScanCallback);
		} else {
			isScanning = false;
			btaAdapter.stopLeScan(mLeScanCallback);
		}
	}

	/**
	 * After using a given BLE device, the app must call this method to ensure
	 * resources are released properly.
	 */
	public void close(BluetoothGatt gatt) {
		if (gatt == null) {
			return;
		}
		gatt.close();
		gatt = null;
	}

	/**
	 * Connects to the GATT server hosted on the Bluetooth LE device.
	 * 
	 * @param address
	 *            The device address of the destination device.
	 * 
	 * @return Return true if the connection is initiated successfully. The
	 *         connection result is reported asynchronously through the
	 *         {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
	 *         callback.
	 */
	public boolean connect(final String address, int index) {
		this.index = index;
		if (address == null) {
			Log.w(TAG, " unspecified address.");
			return false;
		}

		final BluetoothDevice device = btaAdapter.getRemoteDevice(address);
		if (device == null) {
			Log.w(TAG, "Device not found.  Unable to connect.");
			return false;
		}
		// We want to directly connect to the device, so we are setting the
		// autoConnect
		// parameter to false.

		// MainActivity.mList.get(index).setmBluetoothGatt(gatt);
		if (!MainActivity.gattMap.containsKey(MainActivity.mList.get(index)
				.getAddr())) {
			BluetoothGatt gatt = device.connectGatt(context, true,
					mGattCallback);
			MainActivity.gattMap.put(MainActivity.mList.get(index).getAddr(),
					gatt);
			Log.d(TAG, "Trying to create a new connection."
					+ MainActivity.gattMap.size());
		} else
			Log.d(TAG, "allready connected." + MainActivity.gattMap.size());
		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(int index) {
		if (btaAdapter == null) {
			Log.w(TAG, "BluetoothAdapter not initialized");
			return;
		}
		MainActivity.mList.get(index).getmBluetoothGatt().disconnect();
	}
}

//用於傳送資料的執行緒池
public class BluetoothExecutor {

	private static final String TAG = "TcpExecutor";
	private static BluetoothExecutor instance = null;
	private ThreadPoolExecutor executor;
	private Semaphore semp;

	private BluetoothManager manager;

	private BluetoothExecutor() {
		executor = new ThreadPoolExecutor(1, 7, 500, TimeUnit.MILLISECONDS,
				new ArrayBlockingQueue<Runnable>(20));
		semp = new Semaphore(1);
		manager = BluetoothManager.getInstance();
	}

	public static BluetoothExecutor getInstans() {
		if (instance == null) {
			synchronized (BluetoothExecutor.class) {
				if (instance == null)
					instance = new BluetoothExecutor();
			}
		}
		return instance;
	}

	public void execute(final byte[] chars) {
		Log.d(TAG, "execute start" + executor.getActiveCount());
		try {
			semp.acquire();

			final Set<String> set = MainActivity.gattMap.keySet();
			Log.d(TAG, "Set<String>" + set);
			for (int i = 0; i < MainActivity.gattMap.size(); i++) {

				executor.execute(new Runnable() {
					@Override
					public void run() {
						manager.writeData(
								MainActivity.gattMap.get(set.iterator().next()),
								chars);
					}
				});
			}

			while (executor.getActiveCount() != 0)
				;
			semp.release();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}