作者: 張奇
我將在這篇文章中介紹了的Android藍牙程序。這個程序就是將實現把手機變做電腦PPT播放的遙控器:用音量加和音量減鍵來控制PPT頁面的切換。
遙控器服務器端
首先,我們需要編寫一個遙控器的服務器端(支持藍牙的電腦)來接收手機端發出的信號。爲了實現這個服務器端,我用到了一個叫做Bluecove(專門用來爲藍牙服務的!)的Java庫。
以下是我的RemoteBluetoothServer類:
- <span style="font-size:16px;">public class RemoteBluetoothServer{
- public static void main(String[] args) {
- Thread waitThread = new Thread(new WaitThread());
- waitThread.start();
- }
- }
- </span>
在主方法中創建了一個線程,用於連接客戶端,並處理信號。
- <span style="font-size:16px;">public class WaitThread implements Runnable{
- /** Constructor */
- public WaitThread() {
- }
- @Override
- public void run() {
- waitForConnection();
- }
- /** Waiting for connection from devices */
- private void waitForConnection() {
- // retrieve the local Bluetooth device object
- LocalDevice local = null;
- StreamConnectionNotifier notifier;
- StreamConnection connection = null;
- // setup the server to listen for connection
- try {
- local = LocalDevice.getLocalDevice();
- local.setDiscoverable(DiscoveryAgent.GIAC);
- UUID uuid = new UUID(80087355); // "04c6093b-0000-1000-8000-00805f9b34fb"
- String url = "btspp://localhost:" + uuid.toString() + ";name=RemoteBluetooth";
- notifier = (StreamConnectionNotifier)Connector.open(url);
- } catch (Exception e) {
- e.printStackTrace();
- return;
- }
- // waiting for connection
- while(true) {
- try {
- System.out.println("waiting for connection...");
- connection = notifier.acceptAndOpen();
- Thread processThread = new Thread(new ProcessConnectionThread(connection));
- processThread.start();
- } catch (Exception e) {
- e.printStackTrace();
- return;
- }
- }
- }
- }
- </span>
在waitForConnection()中,首先將服務器設爲可發現的,併爲這個程序創建了UUID(用於同客戶端通信);然後就等待來自客戶端的連接請求。當它收到一個初始的連接請求時,將創建一個ProcessConnectionThread來處理來自客戶端的命令。以下是ProcessConnectionThread的代碼:
- <span style="font-size:16px;">public class ProcessConnectionThread implements Runnable{
- private StreamConnection mConnection;
- // Constant that indicate command from devices
- private static final int EXIT_CMD = -1;
- private static final int KEY_RIGHT = 1;
- private static final int KEY_LEFT = 2;
- public ProcessConnectionThread(StreamConnection connection)
- {
- mConnection = connection;
- }
- @Override
- public void run() {
- try {
- // prepare to receive data
- InputStream inputStream = mConnection.openInputStream();
- System.out.println("waiting for input");
- while (true) {
- int command = inputStream.read();
- if (command == EXIT_CMD)
- {
- System.out.println("finish process");
- break;
- }
- processCommand(command);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /**
- * Process the command from client
- * @param command the command code
- */
- private void processCommand(int command) {
- try {
- Robot robot = new Robot();
- switch (command) {
- case KEY_RIGHT:
- robot.keyPress(KeyEvent.VK_RIGHT);
- System.out.println("Right");
- break;
- case KEY_LEFT:
- robot.keyPress(KeyEvent.VK_LEFT);
- System.out.println("Left");
- break;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- </span>
ProcessConnectionThread類主要用於接收並處理客戶端發送的命令。需要處理的命令只有兩個:KEY_RIGHT和KEY_LEFT。我用java.awt.Robot來生成電腦端的鍵盤事件。
以上就是服務器端所需要做的工作。
遙控器客戶端
這裏的客戶端指的其實就是Android手機。在開發手機端代碼的過程中,我參考了 Android Dev Guide中Bluetooth Chat這個程序的代碼,這個程序在SDK的示例代碼中可以找到。
要將客戶端連接服務器端,那麼必須讓手機可以掃描到電腦,DeviceListActivity 類的工作就是掃描並連接服務器。BluetoothCommandService類負責將命令傳至服務器端。這兩個類與Bluetooth Chat中的內容相似,只是刪除了Bluetooth Chat中的BluetoothCommandService中的AcceptThread ,因爲客戶端不需要接受連接請求。ConnectThread用於初始化與服務器的連接,ConnectedThread 用於發送命令。
RemoteBluetooth 是客戶端的主activity,其中主要代碼如下:
- <span style="font-size:16px;">protected void onStart() {
- super.onStart();
- // If BT is not on, request that it be enabled.
- // setupCommand() will then be called during onActivityResult
- if (!mBluetoothAdapter.isEnabled()) {
- Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
- startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
- }
- // otherwise set up the command service
- else {
- if (mCommandService==null)
- setupCommand();
- }
- }
- private void setupCommand() {
- // Initialize the BluetoothChatService to perform bluetooth connections
- mCommandService = new BluetoothCommandService(this, mHandler);
- }
- </span>
onStart()用於檢查手機上的藍牙是否已經打開,如果沒有打開則創建一個Intent來打開藍牙。setupCommand()用於在按下音量加或音量減鍵時向服務器發送命令。其中用到了onKeyDown事件:
- <span style="font-size:16px;">public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
- mCommandService.write(BluetoothCommandService.VOL_UP);
- return true;
- }
- else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN){
- mCommandService.write(BluetoothCommandService.VOL_DOWN);
- return true;
- }
- return super.onKeyDown(keyCode, event);
- }
- </span>
此外,還需要在AndroidManifest.xml加入打開藍牙的權限的代碼。
- <span style="font-size:16px;"> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
- <uses-permission android:name="android.permission.BLUETOOTH" />
- </span>
以上就是客戶端的代碼。
將兩個程序分別在電腦和手機上安裝後,即可實現用手機當作一個PPT遙控器了!
參考文獻:
http://developer.android.com/guide/topics/wireless/bluetooth.html
http://developer.android.com/resources/samples/BluetoothChat/index.html