android 蓝牙开发

蓝牙知识了解:

每个手机如果有蓝牙的话,可以通过蓝牙扫描到你手机的mac地址。

(1)、MAC地址:每个设备都有全球唯一的,根据此MAC地址判断蓝牙设备

(2)、蓝牙传输数据,通常一秒钟会传输很多个包,每个包的数据情况如下:

此时,这个包有11个字节,0x55 是首码,通常通过他来判断一个包的开始

SUM是验证码,会有一套公式来计算,判断当前包是不是一个有效的完整的包

中间的即是数据,然后硬件方面会给我们一套计算公式,可以以此获取我们要的数据。

当然每个硬件的包的数据大小都是不同的,有的可能有21个字节,每个硬件的数据的计算方式也不想同.

代码实现:

一共就三部分,因为代码篇幅可能较大,不适合一段段代码讲解,直接贴出整个代码。所有的解释都在注释当中。

一:MainActivity

  public class MainActivity extends Activity {

      private BluetoothService mBluetoothService; //自定义蓝牙服务类
      private BluetoothAdapter mBluetoothAdapter;
      private String mConnectedDeviceName = null; //连接设备的名称

      //默认是1,因为程序启动时首先会连接一个蓝牙
      private int current_pos = 1;

      //hanlder消息标识 message.what
      public static final int MESSAGE_STATE_CHANGE = 1; // 状态改变
      public static final int MESSAGE_READ = 2;          // 读取数据
      public static final int MESSAGE_WRITE = 3;         // 给硬件传数据,暂不需要,看具体需求
      public static final int MESSAGE_DEVICE_NAME = 4;  // 设备名字
      public static final int MESSAGE_TOAST = 5;         // Toast

  //传感器 ,这里默认同时需要和三个硬件连接,分别设置id 1,2,3进行区分,demo中实际只用到 MAGIKARE_SENSOR_DOWN = 1
//可以根据情况自行添加删除
public static final int MAGIKARE_SENSOR_UP = 2;
public static final int MAGIKARE_SENSOR_DOWN = 1;
public static final int MAGIKARE_SENSOR_CENTER = 3;

public static float[] m_receive_data_up;                    //传感器的数据
public static float[] m_receive_data_down;                  //传感器的数据 ,demo中我们只需要这一个,因为只有一个硬件设备,
public static float[] m_receive_data_center;                //传感器的数据

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    //获取蓝牙适配器
    mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();

    // 1、判断设备是否支持蓝牙功能
    if (mBluetoothAdapter == null) {
        //设备不支持蓝牙功能
        Toast.makeText(this, "当前设备不支持蓝牙功能!", Toast.LENGTH_SHORT).show();
        return;
    }

    // 2、打开设备的蓝牙功能
    if (!mBluetoothAdapter.isEnabled()) {
        boolean enable = mBluetoothAdapter.enable(); //返回值表示 是否成功打开了蓝牙设备
        if (enable) {
            Toast.makeText(this, "打开蓝牙功能成功!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "打开蓝牙功能失败,请到'系统设置'中手动开启蓝牙功能!", Toast.LENGTH_SHORT).show();
            return;
        }
    }


    // 3、创建自定义蓝牙服务对象
    if (mBluetoothService == null) {
        mBluetoothService = new BluetoothService(MainActivity.this, mHandler);
    }
    if (mBluetoothService != null) {
        //根据MAC地址远程获取一个蓝牙设备,这里固定了,实际开发中,需要动态设置参数(MAC地址)
        BluetoothDevice sensor_down = mBluetoothAdapter.getRemoteDevice("20:16:06:15:78:76");
        if (sensor_down != null) {
            //成功获取到远程蓝牙设备(传感器),这里默认只连接MAGIKARE_SENSOR_DOWN = 1这个设备
            mBluetoothService.connect(sensor_down, MAGIKARE_SENSOR_DOWN);
        }
    }


}
private Handler mHandler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        switch (msg.what){
            case MESSAGE_READ:
                try {
                    String str=msg.getData().getString("index");
                    int index=Integer.valueOf(str);
                    switch (index)
                    {
                        //获取到蓝牙传输过来的数据
                        case MAGIKARE_SENSOR_UP:
                            m_receive_data_up=msg.getData().getFloatArray("Data");
                            break;
                        //实际只用到这个case ,因为demo只连接了一个硬件设备
                        case MAGIKARE_SENSOR_DOWN:
                            m_receive_data_down=msg.getData().getFloatArray("Data");
                            break;
                        case MAGIKARE_SENSOR_CENTER:
                            m_receive_data_center=msg.getData().getFloatArray("Data");
                            break;

                    }
                } catch (Exception e) {
                    // TODO: handle exception
                }
                break;
            case MESSAGE_STATE_CHANGE:
                //连接状态
                switch (msg.arg1) {
                    case BluetoothService.STATE_CONNECTED:
                        break;
                    case BluetoothService.STATE_CONNECTING:
                        break;
                    case BluetoothService.STATE_LISTEN:
                        break;
                    case BluetoothService.STATE_NONE:
                        break;
                }
                break;
            case MESSAGE_DEVICE_NAME:
                mConnectedDeviceName = msg.getData().getString("device_name");
                Log.i("bluetooth","成功连接到:"+mConnectedDeviceName);
                Toast.makeText(getApplicationContext(),"成功连接到设备" + mConnectedDeviceName,Toast.LENGTH_SHORT).show();

                break;
            case MESSAGE_TOAST:
                int index=msg.getData().getInt("device_id");
                Toast.makeText(getApplicationContext(),msg.getData().getString("toast"), Toast.LENGTH_SHORT).show();
                //当失去设备或者不能连接设备时,重新连接
                Log.d("Magikare","当失去设备或者不能连接设备时,重新连接");

       //重新连接硬件设备
               if(mBluetoothService!=null)
                {
                    switch (index) {
                        case MAGIKARE_SENSOR_DOWN:
          //根据你的硬件的MAC地址写参数,每一个硬件设备都有一个MAC地址,此方法是根据MAC地址得到蓝牙设备
                            BluetoothDevice sensor_down = mBluetoothAdapter.getRemoteDevice("20:16:06:15:78:76");
                            if (sensor_down != null)
                                mBluetoothService.connect(sensor_down, MAGIKARE_SENSOR_DOWN);
                            break;
                        case MAGIKARE_SENSOR_UP:
                            BluetoothDevice sensor_up = mBluetoothAdapter.getRemoteDevice("");  //参数写你这个设备的MAC码
                            if (sensor_up != null)
                                mBluetoothService.connect(sensor_up, MAGIKARE_SENSOR_UP);
                            break;
                        case MAGIKARE_SENSOR_CENTER:
                            BluetoothDevice center = mBluetoothAdapter.getRemoteDevice("");    //参数写你这个设备的MAC码
                            if (center != null)
                                mBluetoothService.connect(center, MAGIKARE_SENSOR_CENTER);
                            break;
                    }
                }
                break;
        }
        return false;
    }
});

public synchronized void onResume() {
    super.onResume();

    if (mBluetoothService != null) {
        if (mBluetoothService.getState() == BluetoothService.STATE_NONE) {
            mBluetoothService.start();
        }
    }
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (mBluetoothService != null) mBluetoothService.stop();
}

      // 硬件通过蓝牙传输的byte类型已经转换为float类型,并且通过handler传输到 m_receive_data_down[]数组中,一下操作是获取这个数据,根据个人情况使用
      //获取角度
      public float[] GetAngle(int index)
      {
          float[] angles=new float[3];
          if(m_receive_data_up==null
                  ||m_receive_data_down==null
                )
          {
              return angles;
          }
          switch (index)
          {
              case  MAGIKARE_SENSOR_DOWN:
                  angles[0]=m_receive_data_down[6];
                  angles[1]=m_receive_data_down[7];
                  angles[2]=m_receive_data_down[8];
                  break;
              case MAGIKARE_SENSOR_UP:
                  angles[0]=m_receive_data_up[6];
                  angles[1]=m_receive_data_up[7];
                  angles[2]=m_receive_data_up[8];
                 Log.d("安卓 Up 角度",angles[0]+","+angles[1]+","+angles[2]);
                  break;
          }
            return angles;
      }

//获取角速度
public static float[] GetAngleSpeed(int index){
    float [] anglespeed=new float[3];
    if(m_receive_data_down==null)
    {
        return anglespeed;
    }
    switch (index)
    {
        case MAGIKARE_SENSOR_DOWN:

            anglespeed[0]=m_receive_data_down[3];
            anglespeed[1]=m_receive_data_down[4];
            anglespeed[2]=m_receive_data_down[5];
            break;
        case MAGIKARE_SENSOR_UP:
            anglespeed[0]=m_receive_data_up[3];
            anglespeed[1]=m_receive_data_up[4];
            anglespeed[2]=m_receive_data_up[5];
            break;
    }
    return  anglespeed;
}

public float[] GetQuaternion(int index)
{
    float[] quaternion=new float[4];

    if(m_receive_data_down==null)
    {
        return quaternion;
    }
    switch (index)
    {
        case  MAGIKARE_SENSOR_DOWN:
            quaternion[0]=m_receive_data_down[23];
            quaternion[1]=m_receive_data_down[24];
            quaternion[2]=m_receive_data_down[25];
            quaternion[3]=m_receive_data_down[26];
            Log.i("saveinfo","m_receive_data_down23"+m_receive_data_down[23]);
            Log.i("saveinfo","m_receive_data_down24"+m_receive_data_down[24]);
            Log.i("saveinfo","m_receive_data_down25"+m_receive_data_down[25]);
            Log.i("saveinfo","m_receive_data_down26"+m_receive_data_down[26]);
            break;
        case MAGIKARE_SENSOR_UP:
            quaternion[0]=m_receive_data_up[23];
            quaternion[1]=m_receive_data_up[24];
            quaternion[2]=m_receive_data_up[25];
            quaternion[3]=m_receive_data_up[26];
            break;
        case MAGIKARE_SENSOR_CENTER:
            quaternion[0]=m_receive_data_center[23];
            quaternion[1]=m_receive_data_center[24];
            quaternion[2]=m_receive_data_center[25];
            quaternion[3]=m_receive_data_center[26];
    }
    return  quaternion;
}

}

二、BluetoothService

  public class BluetoothService {
      private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
      private Context context;
      //蓝牙适配器
      private BluetoothAdapter mAdapter;
      private Handler mHandler;

      //当前传感器设备的个数,即要开启的线程个数,用于设置线程数组的大小
      //这里默认为1,因为我们目前只需要和一个传感器连接, 比如:你要连接两个硬件设备,那就设置值为2,这样就会开启两个线程,分别去执行想要操作
      public static final int  SENSEOR_NUM=1;

      private AcceptThread mAcceptThread;// 请求连接的监听进程
      private ConnectThread mConnectThread;// 连接一个设备的进程
      public ConnectedThread[] mConnectedThread=new ConnectedThread[SENSEOR_NUM];// 已经连接之后的管理进程
      private int mState;// 当前状态

      // 指明连接状态的常量
      public static final int STATE_NONE = 0;         //没有连接
      public static final int STATE_LISTEN = 1;       //等待连接
      public static final int STATE_CONNECTING = 2;  //正在连接
      public static final int STATE_CONNECTED = 3;   //已经连接

      public BluetoothService(Context context, Handler mHandler) {
      this.context = context;
      this.mHandler = mHandler;
      mAdapter = BluetoothAdapter.getDefaultAdapter();//获取蓝牙适配器
      mState = STATE_NONE ; //当前连接状态:未连接
      }

      // 参数 index 是 硬件设备的id ,随便设的,目的在于当 同时连接多个硬件设备的时候,根据此id进行区分
      public synchronized void connect(BluetoothDevice device, int index) {

      //连接一个蓝牙时,将该设备 的蓝牙连接线程关闭,如果有的话
      //demo  就只有一个硬件设备,默认该设备id 取值index=1;
      if (mConnectedThread[index-1] != null) {
            mConnectedThread[index-1].cancel();
            mConnectedThread[index-1]=null;
       }
          mConnectThread=new ConnectThread(device,index);
          mConnectThread.start();
          setState(STATE_CONNECTING);
      }

      private class ConnectThread extends Thread{
          private final BluetoothSocket mmSocket;
          private final BluetoothDevice mmDevice;
          private int index;
          public ConnectThread(BluetoothDevice device,int index) {
              mmDevice = device;
              this.index=index;
              BluetoothSocket tmp = null;
          try {
                tmp = device.createRfcommSocketToServiceRecord(MY_UUID);// Get a BluetoothSocket for a connection with the given BluetoothDevice
          }
            catch (IOException e) {}
            mmSocket = tmp;
        }

      public void run() {

        setName("ConnectThread");
        //当连接成功,取消蓝牙适配器搜索蓝牙设备的操作,因为搜索操作非常耗时
        mAdapter.cancelDiscovery();// Always cancel discovery because it will slow down a connection

        try {
            mmSocket.connect();// This is a blocking call and will only return on a successful connection or an exception
        }
        catch (IOException e) {
            connectionFailed(this.index);
            try {
                mmSocket.close();
            } catch (IOException e2) {}

            BluetoothService.this.start();// 引用来说明要调用的是外部类的方法 run
            return;
        }

        synchronized (BluetoothService.this) {// Reset the ConnectThread because we're done
            mConnectThread = null;
        }
        connected(mmSocket, mmDevice,index);// Start the connected thread
    }

    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {
        }
    }
}

class ConnectedThread extends Thread{
    private BluetoothSocket mmSocket;
    private InputStream mmInStream;
    private OutputStream mmOutStream;
    private int index;
    private Queue queueBuffer = new LinkedList();
    private byte[] packBuffer = new byte[11];


    //构造方法
    public ConnectedThread(BluetoothSocket socket,int index) {
        mmSocket = socket;
        InputStream tmpIn = null;
        OutputStream tmpOut = null;
        this.index=index;
        // Get the BluetoothSocket input and output streams
        try {
            tmpIn = socket.getInputStream();
            tmpOut = socket.getOutputStream();
        } catch (IOException e) {}

        mmInStream = tmpIn;
        mmOutStream = tmpOut;
    }

    // 数组大小看你的数据需求,这里存的是你处理蓝牙传输来的字节数据之后实际要用到的数据
    private float [] fData=new float[31];

    @Override
    public void run() {
        byte[] tempInputBuffer = new byte[1024];
        int acceptedLen = 0; //记录每次读取数据的数据长度
        byte sHead;
        long lLastTime = System.currentTimeMillis(); //获取开始时间
        while(true){
            try {
                acceptedLen = mmInStream.read(tempInputBuffer);//返回接收的长度
                //从缓冲区中读取数据
                for (int i = 0; i < acceptedLen; i++) {
                    queueBuffer.add(tempInputBuffer[i]);
                }
                // 这里需要按个人硬件数据的情况自行修改了
                // 如果你的硬件蓝牙传输 一个包有11个字节,那queueBuffer.size()>=11
                // 如果你的硬件蓝牙传输 一个包有21个字节,那queueBuffer.size()>=21
                while (queueBuffer.size()>=11){
                    //返回队首并删除,判断队首是不是0x55,如果不是,说明不是一个包的数据,跳过,
                    //注意这里的0x55是你的包的首字节
                    if (queueBuffer.poll()!=0x55)
                        continue;
                    // 进入到这里,说明得到一个包的数据了,然后就要根据个人硬件的数据情况,将byte类型的数据转换为float类型的数据
                  sHead = queueBuffer.poll(); //返回队首并删除
    // 现在得到的就是你数据部分了,如果有9位字节代表数据,j<9 ,如果有19位字节代表数据,j<19
    //将字节数组存到packBuffer[]数据中,用于byte-->float数据的转换
                    for (int j = 0; j < 9; j++) {
                        packBuffer[j] = queueBuffer.poll();
                    }
                    switch (sHead) {//
                        case 0x52://角速度
                            fData[3] = ((((short) packBuffer[1]) << 8) | ((short) packBuffer[0] & 0xff)) / 32768.0f * 2000;
                            fData[4] = ((((short) packBuffer[3]) << 8) | ((short) packBuffer[2] & 0xff)) / 32768.0f * 2000;
                            fData[5] = ((((short) packBuffer[5]) << 8) | ((short) packBuffer[4] & 0xff)) / 32768.0f * 2000;
                            fData[17] = ((((short) packBuffer[7]) << 8) | ((short) packBuffer[6] & 0xff)) / 100.0f;
                            break;
                        case 0x53://角度
                            fData[6] = ((((short) packBuffer[1]) << 8) | ((short) packBuffer[0] & 0xff)) / 32768.0f * 180;
                            fData[7] = ((((short) packBuffer[3]) << 8) | ((short) packBuffer[2] & 0xff)) / 32768.0f * 180;
                            fData[8] = ((((short) packBuffer[5]) << 8) | ((short) packBuffer[4] & 0xff)) / 32768.0f * 180;
                            fData[17] = ((((short) packBuffer[7]) << 8) | ((short) packBuffer[6] & 0xff)) / 100.0f;
                            break;
                        case 0x59://四元数
                            fData[23] = ((((short) packBuffer[1]) << 8) | ((short) packBuffer[0] & 0xff)) / 32768.0f;
                            fData[24] = ((((short) packBuffer[3]) << 8) | ((short) packBuffer[2] & 0xff))/32768.0f;
                            fData[25] = ((((short) packBuffer[5]) << 8) | ((short) packBuffer[4] & 0xff))/32768.0f;
                            fData[26] = ((((short) packBuffer[7]) << 8) | ((short) packBuffer[6] & 0xff))/32768.0f;
                            break;
                    }
                }
                long lTimeNow = System.currentTimeMillis(); // 获取收据转换之后的时间
                // 如果数据处理后的时间  与 接收到数据的时间 的时间差>80 则发送消息传输数据,
                // 这个时间需要看你硬件一秒钟发送的包的个数
                if (lTimeNow - lLastTime > 80) {
                    lLastTime = lTimeNow;
                    Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_READ);
                    Bundle bundle = new Bundle();
                    bundle.putString("index",String.valueOf(this.index));
                    bundle.putFloatArray("Data", fData);
                    msg.setData(bundle);
                    mHandler.sendMessage(msg);
                }
            } catch (IOException e) {
                connectionLost(this.index);
                e.printStackTrace();
            }
        }
    }
    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {}
    }
}
//连接失败
private void connectionFailed(int index) {
    setState(STATE_LISTEN);
    // Send a failure message back to the Activity
    Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString("toast", "未能连接设备"+index);
    bundle.putInt("device_id",index);
    msg.setData(bundle);
    mHandler.sendMessage(msg);
}
// 连接丢失
private void connectionLost(int index) {
    setState(STATE_LISTEN);
    Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_TOAST);
    Bundle bundle = new Bundle();
    bundle.putString("toast", "设备丢失"+index);
    bundle.putInt("device_id",index);
    msg.setData(bundle);
    mHandler.sendMessage(msg);
}


//用于 蓝牙连接的Activity onResume()方法
public synchronized void start() {
    // Cancel any thread attempting to make a connection
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }

    if (mAcceptThread == null) {
        mAcceptThread = new AcceptThread();
        mAcceptThread.start();
    }
    setState(STATE_LISTEN);
}

public synchronized void connected(BluetoothSocket socket,BluetoothDevice device,int index) {
    Log.d("MAGIKARE","连接到线程"+index);
    // Cancel the thread that completed the connection
    if (mConnectThread != null) {
        mConnectThread.cancel();
        mConnectThread = null;
    }
    // Cancel the accept thread because we only want to connect to one device
    if (mAcceptThread != null) {
        mAcceptThread.cancel();
        mAcceptThread = null;
    }

    // Start the thread to manage the connection and perform transmissions
    mConnectedThread[index-1] = new ConnectedThread(socket,index);

    mConnectedThread[index-1].start();

    // Send the name of the connected device back to the UI Activity
    Message msg = mHandler.obtainMessage(MainActivity.MESSAGE_DEVICE_NAME);
    Bundle bundle = new Bundle();
    bundle.putString("device_name", device.getName()+" "+index);

    msg.setData(bundle);
    mHandler.sendMessage(msg);

    setState(STATE_CONNECTED);
}

private synchronized void setState(int state) {
    mState = state;
    // Give the new state to the Handler so the UI Activity can update
    mHandler.obtainMessage(MainActivity.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}

private class AcceptThread extends Thread {
    // The local server socket
    private final BluetoothServerSocket mmServerSocket;
    //private int index;
    public AcceptThread() {
        BluetoothServerSocket tmp = null;
        // this.index=index;
        // Create a new listening server socket
        try {
            tmp = mAdapter.listenUsingRfcommWithServiceRecord("BluetoothData", MY_UUID);
        }
        catch (IOException e) {}
        mmServerSocket = tmp;
    }

    public void run() {
        new Thread(new Runnable() {
            @Override
            public void run() {

            }
        }).start();

    }

    public void cancel() {

        try {
            if(mmServerSocket!=null) {
                mmServerSocket.close();
            }
        }
        catch (IOException e) {}
    }
}
public synchronized int getState() {
    return mState;
}


public synchronized void stop() {
    if (mConnectedThread != null) {
        for(int i=0;i

}

三、自定义即时变化的折线图:

public class MyView extends View {
      /*http://www.cnblogs.com/aibuli/p/950c34f2bc0d02cbd290dd6a8339d42a.html*/
      //坐标轴原点的位置
      private int xPoint=60;
      private int yPoint=260;
    //刻度长度
    private int xScale=8;  //8个单位构成一个刻度
    private int yScale=40;
    //x与y坐标轴的长度
    private int xLength=580;
    private int yLength=480;
    private int MaxDataSize=xLength/xScale;   //横坐标  最多可绘制的点
    private List data=new ArrayList();   //存放 纵坐标 所描绘的点
    private String[] yLabel=new String[yLength/yScale];  //Y轴的刻度上显示字的集合

    private Handler mh=new Handler(){
        public void handleMessage(android.os.Message msg) {
            if(msg.what==0){                //判断接受消息类型
                MyView.this.invalidate();  //刷新View
            }
        };
    };
public MyView(Context context, AttributeSet attrs) {
    super(context, attrs);
    for (int i = 0; i MaxDataSize){  //判断集合的长度是否大于最大绘制长度
                    data.remove(0);  //删除头数据
                }
                // 这里得到蓝牙设备得到的数据
                float[] floats = MainActivity.GetAngleSpeed(1);
                data.add(floats[0]);
                mh.sendEmptyMessage(0);   //发送空消息通知刷新
            }
        }
    }).start();
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    Paint paint=new Paint();
    paint.setStyle(Paint.Style.STROKE);
    paint.setAntiAlias(true);
    paint.setColor(Color.RED);
    //绘制Y轴
    canvas.drawLine(xPoint, yPoint-yLength, xPoint, yPoint, paint);
    //绘制Y轴左右两边的箭头
    canvas.drawLine(xPoint, yPoint-yLength, xPoint-3,yPoint-yLength+6, paint);
    canvas.drawLine(xPoint, yPoint-yLength, xPoint+3,yPoint-yLength+6, paint);
    //Y轴上的刻度与文字
    for (int i = 0; i * yScale< yLength; i++) {
        canvas.drawLine(xPoint, yPoint-i*yScale, xPoint+5, yPoint-i*yScale, paint);  //刻度
        canvas.drawText(yLabel[i], xPoint-50, yPoint-i*yScale, paint);//文字
    }
    //X轴
    canvas.drawLine(xPoint, yPoint, xPoint+xLength, yPoint, paint);
    //如果集合中有数据
    if(data.size()>1){
        for (int i = 1; i < data.size(); i++) {  //依次取出数据进行绘制
            canvas.drawLine(xPoint+(i-1)*xScale, yPoint-data.get(i-1)*yScale, xPoint+i*xScale, yPoint-data.get(i)*yScale, paint);
        }
    }
  }}

你可能感兴趣的:(android 蓝牙开发)