控件界面
package com.testBlueTooth; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.UUID; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ListView; import android.widget.Toast; import android.widget.ToggleButton; public class testBlueTooth extends Activity { static final String SPP_UUID = "00001101-0000-1000-8000-00805F9B34FB"; Button btnSearch, btnDis, btnExit; ToggleButton tbtnSwitch; ListView lvBTDevices; ArrayAdapter<String> adtDevices; List<String> lstDevices = new ArrayList<String>(); BluetoothAdapter btAdapt; public static BluetoothSocket btSocket; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // Button 设置 btnSearch = (Button) this.findViewById(R.id.btnSearch); btnSearch.setOnClickListener(new ClickEvent()); btnExit = (Button) this.findViewById(R.id.btnExit); btnExit.setOnClickListener(new ClickEvent()); btnDis = (Button) this.findViewById(R.id.btnDis); btnDis.setOnClickListener(new ClickEvent()); // ToogleButton设置 tbtnSwitch = (ToggleButton) this.findViewById(R.id.tbtnSwitch); tbtnSwitch.setOnClickListener(new ClickEvent()); // ListView及其数据源 适配器 lvBTDevices = (ListView) this.findViewById(R.id.lvDevices); adtDevices = new ArrayAdapter<String>(testBlueTooth.this, android.R.layout.simple_list_item_1, lstDevices); lvBTDevices.setAdapter(adtDevices); lvBTDevices.setOnItemClickListener(new ItemClickEvent()); btAdapt = BluetoothAdapter.getDefaultAdapter();// 初始化本机蓝牙功能 if(btAdapt != null){ if (btAdapt.getState() == BluetoothAdapter.STATE_OFF)// 读取蓝牙状态并显示 tbtnSwitch.setChecked(false); else if (btAdapt.getState() == BluetoothAdapter.STATE_ON) tbtnSwitch.setChecked(true); } // 注册Receiver来获取蓝牙设备相关的结果 IntentFilter intent = new IntentFilter(); intent.addAction(BluetoothDevice.ACTION_FOUND);// 用BroadcastReceiver来取得搜索结果 intent.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); intent.addAction(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED); intent.addAction(BluetoothAdapter.ACTION_STATE_CHANGED); registerReceiver(searchDevices, intent); } private BroadcastReceiver searchDevices = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Bundle b = intent.getExtras(); Object[] lstName = b.keySet().toArray(); // 显示所有收到的消息及其细节 for (int i = 0; i < lstName.length; i++) { String keyName = lstName[i].toString(); Log.e(keyName, String.valueOf(b.get(keyName))); } //搜索设备时,取得设备的MAC地址 if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); String str= device.getName() + "|" + device.getAddress(); if (lstDevices.indexOf(str) == -1)// 防止重复添加 lstDevices.add(str); // 获取设备名称和mac地址 adtDevices.notifyDataSetChanged(); } } }; @Override protected void onDestroy() { this.unregisterReceiver(searchDevices); super.onDestroy(); android.os.Process.killProcess(android.os.Process.myPid()); } class ItemClickEvent implements AdapterView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { btAdapt.cancelDiscovery(); String str = lstDevices.get(arg2); String[] values = str.split("\\|"); String address=values[1]; Log.e("address",values[1]); UUID uuid = UUID.fromString(SPP_UUID); BluetoothDevice btDev = btAdapt.getRemoteDevice(address); try { btSocket = btDev .createRfcommSocketToServiceRecord(uuid); btSocket.connect(); //打开波形图实例 Intent intent = new Intent(); intent.setClass(testBlueTooth.this, WaveDiagram.class); startActivity(intent); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } class ClickEvent implements View.OnClickListener { @Override public void onClick(View v) { if (v == btnSearch)// 搜索蓝牙设备,在BroadcastReceiver显示结果 { if (btAdapt.getState() == BluetoothAdapter.STATE_OFF) {// 如果蓝牙还没开启 Toast.makeText(testBlueTooth.this, "请先打开蓝牙", 1000).show(); return; } setTitle("本机蓝牙地址:" + btAdapt.getAddress()); lstDevices.clear(); btAdapt.startDiscovery(); } else if (v == tbtnSwitch) {// 本机蓝牙启动/关闭 if (tbtnSwitch.isChecked() == false) btAdapt.enable(); else if (tbtnSwitch.isChecked() == true) btAdapt.disable(); } else if (v == btnDis)// 本机可以被搜索 { Intent discoverableIntent = new Intent( BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); discoverableIntent.putExtra( BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300); startActivity(discoverableIntent); } else if (v == btnExit) { try { if (btSocket != null) btSocket.close(); } catch (IOException e) { e.printStackTrace(); } testBlueTooth.this.finish(); } } } }
2.显示界面
package com.testBlueTooth; import java.io.IOException; import java.io.InputStream; import android.app.Activity; import android.graphics.Color; import android.graphics.Paint; import android.os.Bundle; import android.util.Log; import android.view.MotionEvent; import android.view.SurfaceView; import android.view.View; import android.view.View.OnTouchListener; public class WaveDiagram extends Activity { ClsWaveDiagram clsWaveDiagram; SurfaceView sfvWave; Paint mPaint; InputStream btInput; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.wavediagram); sfvWave = (SurfaceView) this.findViewById(R.id.sfvWave); sfvWave.setOnTouchListener(new TouchEvent()); mPaint = new Paint(); mPaint.setColor(Color.GREEN);// 画笔为绿色 mPaint.setStrokeWidth(2);// 设置画笔粗细 try { if (testBlueTooth.btSocket.getInputStream() != null) { clsWaveDiagram = new ClsWaveDiagram( testBlueTooth.btSocket.getInputStream(), 3, 1, sfvWave.getWidth()/2);//横向绘制波形图 clsWaveDiagram.Start(sfvWave, mPaint,80); Log.e("clsWaveDiagram","start"); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public void onDestroy() { clsWaveDiagram.Stop(); try { testBlueTooth.btSocket.close(); } catch (IOException e) { e.printStackTrace(); } super.onDestroy(); } class TouchEvent implements OnTouchListener { @Override public boolean onTouch(View v, MotionEvent event) { clsWaveDiagram.baseLine = (int) event.getX(); return true; } } }
画图方法
package com.testBlueTooth; import java.io.InputStream; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.Log; import android.view.SurfaceView; public class ClsWaveDiagram { private boolean isRecording = false;// 线程控制标记 private InputStream btInput = null;// 蓝牙数据输入流 /** * X轴缩小的比例 */ public int rateX = 1; /** * Y轴缩小的比例 */ public int rateY = 1; /** * Y轴基线 */ public int baseLine = 0; /** * 初始化 */ public ClsWaveDiagram(InputStream btInput, int rateX, int rateY, int baseLine) { this.btInput = btInput; this.rateX = rateX; this.rateY = rateY; this.baseLine = baseLine; } /** * 开始 * * @param recBufSize * AudioRecord的MinBufferSize */ public void Start(SurfaceView sfv, Paint mPaint, int wait) { isRecording = true; new DrawThread(sfv, mPaint, wait).start();// 开始绘制线程 } /** * 停止 */ public void Stop() { isRecording = false; } /** * 负责绘制inBuf中的数据 * * @author GV * */ class DrawThread extends Thread { private int oldX = 0;// 上次绘制的X坐标 private int oldY = 0;// 上次绘制的Y坐标 private SurfaceView sfv;// 画板 private int X_index = 0;// 当前画图所在屏幕X轴的坐标 private Paint mPaint;// 画笔 private int wait = 50;// 线程等待时间 public DrawThread(SurfaceView sfv, Paint mPaint, int wait) { this.sfv = sfv; this.mPaint = mPaint; this.wait = wait; } public void run() { while (isRecording) { try { byte[] temp = new byte[1024]; int len = btInput.read(temp); Log.e("available", String.valueOf(len)); if (len > 0) { byte[] btBuf = new byte[len]; System.arraycopy(temp, 0, btBuf, 0, btBuf.length); SimpleDraw(X_index, btBuf, rateX, rateY, baseLine);// 把缓冲区数据画出来 X_index = X_index + (btBuf.length/rateX) - 1;// 这里-1可以减少空隙 if (X_index > sfv.getHeight()) { X_index = 0; } } Thread.sleep(wait);// 延时一定时间缓冲数据 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } /** * 绘制指定区域 * * @param start * X轴开始的位置(全屏) * @param inputBuf * 缓冲区 * @param rateX * X轴数据缩小的比例 * @param rateY * Y轴数据缩小的比例 * @param baseLine * Y轴基线 */ void SimpleDraw(int start, byte[] inputBuf, int rateX, int rateY, int baseLine) { if (start == 0) oldX = 0; // 根据需要缩小X轴比例 byte[] buffer = new byte[inputBuf.length / rateX]; for (int i = 0, ii = 0; i < buffer.length; i++, ii = i * rateX) buffer[i] = inputBuf[ii]; Canvas canvas = sfv.getHolder().lockCanvas( new Rect(0, start, sfv.getWidth(), start + buffer.length));// 关键:获取画布 canvas.drawColor(Color.BLACK);// 清除背景 for (int i = 0; i < buffer.length; i++) {// 有多少画多少 int y = i + start; int x = (0xFF - (buffer[i] & 0xFF))// 0xFF- 用于翻转, // &0xFF用把byte类型的负数取值转为正 / rateY + baseLine;// 调节缩小比例,调节基准线 canvas.drawLine(oldX, oldY, x, y, mPaint); oldX = x; oldY = y; } sfv.getHolder().unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像 } } }
布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <LinearLayout android:id="@+id/LinearLayout01" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:id="@+id/TextView01" android:layout_height="wrap_content" android:text="手机蓝牙开关" android:layout_width="100dip"></TextView><ToggleButton android:layout_height="wrap_content" android:text="蓝牙开关" android:layout_width="wrap_content" android:id="@+id/tbtnSwitch"></ToggleButton> <Button android:layout_height="wrap_content" android:text="本机蓝牙可见" android:id="@+id/btnDis" android:layout_width="160dip"></Button></LinearLayout> <LinearLayout android:id="@+id/LinearLayout02" android:layout_width="wrap_content" android:layout_height="wrap_content"> <Button android:layout_height="wrap_content" android:id="@+id/btnSearch" android:text="搜索设备" android:layout_width="160dip"></Button> <Button android:layout_height="wrap_content" android:id="@+id/btnExit" android:text="退出程序" android:layout_width="160dip"></Button> </LinearLayout> <ListView android:layout_width="fill_parent" android:id="@+id/lvDevices" android:layout_height="fill_parent"> </ListView> </LinearLayout>
<?xml version="1.0" encoding="UTF-8"?> <LinearLayout android:id="@+id/LinearLayout01" android:layout_width="fill_parent" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <SurfaceView android:layout_height="fill_parent" android:layout_width="fill_parent" android:id="@+id/sfvWave"></SurfaceView> </LinearLayout>