1

我正在使用 Android 的 HDPSample 应用程序。我正在尝试在我的三星 Galaxy S3 ANDROID V17 和 Zephyr HXM 蓝牙心率监视器之间配置蓝牙连接。我配对成功,并且正在成功写入日志文件。但是我想使用 serversockets 进行连接,所以我结合了 Android 示例中给出的两个类。我想将“作为客户端连接”的代码组合到 ConnectThread 类,然后使用 ConnectedThread 类管理连接。 http://developer.android.com/guide/topics/connectivity/bluetooth.html#ConnectingDevices 将这两个课程结合起来是一个糟糕的策略吗?每个类完成的线程是否重要,或者它只是 Androids 显示发生的两种不同操作以进行澄清的方式。这真的是我的问题。我目前在运行此程序时遇到异常。谢谢你。这是我的代码。

    package com.example.bluetooth.health;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.io.OutputStreamWriter;

    import java.sql.Timestamp;
    import java.util.Date;
    import java.util.UUID;

    import android.app.Activity;
    import android.app.AlertDialog;
    import android.app.Dialog;
    import android.app.DialogFragment;
    import android.bluetooth.BluetoothAdapter;
    import android.bluetooth.BluetoothDevice;
    import android.bluetooth.BluetoothServerSocket;
    import android.bluetooth.BluetoothSocket;
    import android.content.BroadcastReceiver;
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.content.ServiceConnection;
    import android.content.res.Resources;
    import android.os.Bundle;
    import android.os.Handler;
    import android.os.IBinder;
    import android.os.Message;
    import android.os.Messenger;
    import android.os.RemoteException;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;
    import android.widget.TextView;
    import android.widget.Toast;



    /**
     * Main user interface for the Sample application.  All Bluetooth health-related
     * operations happen in {@link BluetoothHDPService}.  This activity passes messages to and from
     * the service.
     */
    public class BluetoothHDPActivity extends Activity {
        private static final String TAG = "BluetoothHealthActivity";

        // Use the appropriate IEEE 11073 data types based on the devices used.
        // Below are some examples.  Refer to relevant Bluetooth HDP specifications for detail.
        //     0x1007 - blood pressure meter
        //     0x1008 - body thermometer
        //     0x100F - body weight scale
        private static final int HEALTH_PROFILE_SOURCE_DATA_TYPE = 0x1007;

        private static final int REQUEST_ENABLE_BT = 1;
        //private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
        private static final UUID MY_UUID = UUID.fromString("HXM020735");

        public static final int MESSAGE_READ = 0;
        private TextView mConnectIndicator;
        private ImageView mDataIndicator;
        private TextView mStatusMessage;

        private BluetoothAdapter mBluetoothAdapter;
        private BluetoothDevice[] mAllBondedDevices;
        private BluetoothDevice mDevice;
        //jt
        private BluetoothServerSocket mServerSocket;
        //jt
        private int mDeviceIndex = 0;
        private Resources mRes;
        private Messenger mHealthService;
        private boolean mHealthServiceBound;

        private class ConnectThread extends Thread {
            private final BluetoothSocket mmSocket;
            private final BluetoothDevice mmDevice;

            /**/
            private final InputStream mmInStream = null;
            private final OutputStream mmOutStream = null;
            private Handler mHandler;
            /**/

            public ConnectThread(BluetoothDevice device) {
                // Use a temporary object that is later assigned to mmSocket,
                // because mmSocket is final

                BluetoothSocket tmp = null;
                mmDevice = device;

                // Get a BluetoothSocket to connect with the given BluetoothDevice
                try {
                    // MY_UUID is the app's UUID string, also used by the server code
                    tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
                } catch (IOException e) { }
                mmSocket = tmp;

                InputStream tmpIn = null;
                OutputStream tmpOut = null;

            }

            public void ConnectedThread() {
                //mmSocket = socket;
                InputStream tmpIn = null;
                OutputStream tmpOut = null;

                // Get the input and output streams, using temp objects because
                // member streams are final
                try {
                    tmpIn = mmSocket.getInputStream();
                    tmpOut = mmSocket.getOutputStream();
                } catch (IOException e) { }


            }

            public void run() {
                // Cancel discovery because it will slow down the connection
                mBluetoothAdapter.cancelDiscovery();

                try {
                    // Connect the device through the socket. This will block
                    // until it succeeds or throws an exception
                    mmSocket.connect();
                } catch (IOException connectException) {
                    // Unable to connect; close the socket and get out
                    try {
                        mmSocket.close();
                    } catch (IOException closeException) { }
                    return;
                }

                // Do work to manage the connection (in a separate thread)
                //manageConnectedSocket(mmSocket);

                /***/
                byte[] buffer = new byte[1024];  // buffer store for the stream
                int bytes; // bytes returned from read()

                // Keep listening to the InputStream until an exception occurs
                while (true) {
                    try {
                        // Read from the InputStream
                        bytes = mmInStream.read(buffer);
                        // Send the obtained bytes to the UI activity
                        mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)       .sendToTarget();

                    } catch (IOException e) {
                        break;
                    }
                }
                /***/

            }

            /** Will cancel an in-progress connection, and close the socket */
            public void cancel() {
                try {
                    mmSocket.close();
                } catch (IOException e) { }
            }
        };

      /*  private class ConnectedThread extends Thread {
            private final BluetoothSocket mmSocket;
            private final InputStream mmInStream;
            private final OutputStream mmOutStream;
            private Handler mHandler;

            public ConnectedThread(BluetoothSocket socket) {
                mmSocket = socket;
                InputStream tmpIn = null;
                OutputStream tmpOut = null;

                // Get the input and output streams, using temp objects because
                // member streams are final
                try {
                    tmpIn = socket.getInputStream();
                    tmpOut = socket.getOutputStream();
                } catch (IOException e) { }

                mmInStream = tmpIn;
                mmOutStream = tmpOut;
            }

            public void run() {
                byte[] buffer = new byte[1024];  // buffer store for the stream
                int bytes; // bytes returned from read()

                // Keep listening to the InputStream until an exception occurs
                while (true) {
                    try {
                        // Read from the InputStream
                        bytes = mmInStream.read(buffer);
                        // Send the obtained bytes to the UI activity
                        mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer)       .sendToTarget();

                    } catch (IOException e) {
                        break;
                    }
                }
            }
         */
            /* Call this from the main activity to send data to the remote device */
         /*   public void write(byte[] bytes) {
                try {
                    mmOutStream.write(bytes);
                } catch (IOException e) { }
            }
         */
            /* Call this from the main activity to shutdown the connection */
           /* public void cancel() {
                try {
                    mmSocket.close();
                } catch (IOException e) { }
            }
        };

        */

        //Added by Jason to append data to a file on the android phone
        public void appendLog(String text)
        {       
           File logFile = new File("/storage/sdcard0/log.txt");
           if (!logFile.exists())
           {
              try
              {
                 logFile.createNewFile();
              } 
              catch (IOException e)
              {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
              }
           }
           try
           {
              //BufferedWriter for performance, true to set append to file flag
              BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); 
              buf.append(text);
              buf.newLine();
              buf.close();
           }
           catch (IOException e)
           {
              // TODO Auto-generated catch block
              e.printStackTrace();
           }

        }


        // Handles events sent by {@link HealthHDPService}.
        private Handler mIncomingHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    // Application registration complete.
                    case BluetoothHDPService.STATUS_HEALTH_APP_REG:
                        mStatusMessage.setText(
                                String.format(mRes.getString(R.string.status_reg),
                                msg.arg1));
                        break;
                    // Application unregistration complete.
                    case BluetoothHDPService.STATUS_HEALTH_APP_UNREG:
                        mStatusMessage.setText(
                                String.format(mRes.getString(R.string.status_unreg),
                                msg.arg1));
                        break;
                    // Reading data from HDP device.
                    case BluetoothHDPService.STATUS_READ_DATA:
                        mStatusMessage.setText(mRes.getString(R.string.read_data));
                        //get data from here and write to a file



                        mDataIndicator.setImageLevel(1);
                        break;
                    // Finish reading data from HDP device.
                    case BluetoothHDPService.STATUS_READ_DATA_DONE:
                        mStatusMessage.setText(mRes.getString(R.string.read_data_done));
                        mDataIndicator.setImageLevel(0);
                        break;
                    // Channel creation complete.  Some devices will automatically establish
                    // connection.
                    case BluetoothHDPService.STATUS_CREATE_CHANNEL:
                        mStatusMessage.setText(
                                String.format(mRes.getString(R.string.status_create_channel),
                                msg.arg1));
                        mConnectIndicator.setText(R.string.connected);
                        break;
                    // Channel destroy complete.  This happens when either the device disconnects or
                    // there is extended inactivity.
                    case BluetoothHDPService.STATUS_DESTROY_CHANNEL:
                        mStatusMessage.setText(
                                String.format(mRes.getString(R.string.status_destroy_channel),
                                msg.arg1));
                        mConnectIndicator.setText(R.string.disconnected);
                        break;
                    default:
                        super.handleMessage(msg);
                }
            }
        };

        private final Messenger mMessenger = new Messenger(mIncomingHandler);

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            // Check for Bluetooth availability on the Android platform.
            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
            if (mBluetoothAdapter == null) {
                Toast.makeText(this, R.string.bluetooth_not_available, Toast.LENGTH_LONG);
                finish();
                return;
            }
            setContentView(R.layout.console);
            mConnectIndicator = (TextView) findViewById(R.id.connect_ind);
            mStatusMessage = (TextView) findViewById(R.id.status_msg);
            mDataIndicator = (ImageView) findViewById(R.id.data_ind);
            mRes = getResources();
            mHealthServiceBound = false;

            // Initiates application registration through {@link BluetoothHDPService}.
            Button registerAppButton = (Button) findViewById(R.id.button_register_app);
            registerAppButton.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    sendMessage(BluetoothHDPService.MSG_REG_HEALTH_APP,
                            HEALTH_PROFILE_SOURCE_DATA_TYPE);
                }
            });

            // Initiates application unregistration through {@link BluetoothHDPService}.
            Button unregisterAppButton = (Button) findViewById(R.id.button_unregister_app);
            unregisterAppButton.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    sendMessage(BluetoothHDPService.MSG_UNREG_HEALTH_APP, 0);
                }
            });

            // Initiates channel creation through {@link BluetoothHDPService}.  Some devices will
            // initiate the channel connection, in which case, it is not necessary to do this in the
            // application.  When pressed, the user is asked to select from one of the bonded devices
            // to connect to.
            Button connectButton = (Button) findViewById(R.id.button_connect_channel);
            connectButton.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    mAllBondedDevices =
                            (BluetoothDevice[]) mBluetoothAdapter.getBondedDevices().toArray(
                                    new BluetoothDevice[0]);

                    if (mAllBondedDevices.length > 0) {
                        int deviceCount = mAllBondedDevices.length;
                        appendLog("device count = "+deviceCount);
                        /*if (mDeviceIndex < deviceCount) mDevice = mAllBondedDevices[mDeviceIndex];
                        else {
                            mDeviceIndex = 0;
                            mDevice = mAllBondedDevices[1];
                        }*/

                        String first3 = "";// mAllBondedDevices[j].substring(0, Math.min(s.length(), 3));
                        String bd;
                        for(int j=0; j < mAllBondedDevices.length;j++)
                        {
                            bd = mAllBondedDevices[j].getName();
                            first3 = bd.substring(0, 3);
                            if(first3.equalsIgnoreCase("HXM")){
                                appendLog("in if");
                                mDeviceIndex = 0;
                                mDevice= mAllBondedDevices[j];
                                break;
                            }else {
                                appendLog("not in if");
                                appendLog("first3 is "+first3);
                                    mDeviceIndex=0;
                                    mDevice = mAllBondedDevices[0];
                                  }
                        }

                        String[] deviceNames = new String[deviceCount];
                        int i = 0;
                        for (BluetoothDevice device : mAllBondedDevices) {
                            deviceNames[i++] = device.getName();
                        }
                        SelectDeviceDialogFragment deviceDialog =
                                SelectDeviceDialogFragment.newInstance(deviceNames, mDeviceIndex);
                        deviceDialog.show(getFragmentManager(), "deviceDialog");
                    }
                  //jt
                    appendLog("This is the name of the connected device");
                    appendLog(mDevice.getName());
                    appendLog(mDevice.toString());

                    appendLog("Current bondstate value " + mDevice.getBondState());
                    java.util.Date date= new java.util.Date();
                    appendLog(new Timestamp(date.getTime()).toString());    
                    //appendLog(mBluetoothAdapter.getBondedDevices());



                    try {

                        mServerSocket.accept(20000);//twenty seconds or 20k milli-seconds before timeout

                    } catch (IOException e) {
                      // TODO Auto-generated catch block
                       e.printStackTrace();
                    }
                    //jt
                }
            });



            // Initiates channel disconnect through {@link BluetoothHDPService}.
            Button disconnectButton = (Button) findViewById(R.id.button_disconnect_channel);
            disconnectButton.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    disconnectChannel();
                }
            });
            registerReceiver(mReceiver, initIntentFilter());
        }

        // Sets up communication with {@link BluetoothHDPService}.
        private ServiceConnection mConnection = new ServiceConnection() {
            public void onServiceConnected(ComponentName name, IBinder service) {
                mHealthServiceBound = true;
                Message msg = Message.obtain(null, BluetoothHDPService.MSG_REG_CLIENT);
                msg.replyTo = mMessenger;
                mHealthService = new Messenger(service);
                try {
                    mHealthService.send(msg);
                } catch (RemoteException e) {
                    Log.w(TAG, "Unable to register client to service.");
                    e.printStackTrace();
                }
            }

            public void onServiceDisconnected(ComponentName name) {
                mHealthService = null;
                mHealthServiceBound = false;
            }
        };

        @Override
        protected void onDestroy() {
            super.onDestroy();
            if (mHealthServiceBound) unbindService(mConnection);
            unregisterReceiver(mReceiver);
        }

        @Override
        protected void onStart() {
            super.onStart();
            // If Bluetooth is not on, request that it be enabled.
            if (!mBluetoothAdapter.isEnabled()) {
                Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
            } else {
                initialize();
            }
        }

        /**
         * Ensures user has turned on Bluetooth on the Android device.
         */
        @Override
        protected void onActivityResult(int requestCode, int resultCode, Intent data) {
            switch (requestCode) {
            case REQUEST_ENABLE_BT:
                if (resultCode == Activity.RESULT_OK) {
                    initialize();
                } else {
                    finish();
                    return;
                }
            }
        }

        /**
         * Used by {@link SelectDeviceDialogFragment} to record the bonded Bluetooth device selected
         * by the user.
         *
         * @param position Position of the bonded Bluetooth device in the array.
         */
        public void setDevice(int position) {
            mDevice = this.mAllBondedDevices[position];
            mDeviceIndex = position;
        }

        private void connectChannel() {
            sendMessageWithDevice(BluetoothHDPService.MSG_CONNECT_CHANNEL);
        }

        private void disconnectChannel() {
            sendMessageWithDevice(BluetoothHDPService.MSG_DISCONNECT_CHANNEL);
        }

        private void initialize() {
            // Starts health service.
            Intent intent = new Intent(this, BluetoothHDPService.class);
            startService(intent);
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        }

        // Intent filter and broadcast receive to handle Bluetooth on event.
        private IntentFilter initIntentFilter() {
            IntentFilter filter = new IntentFilter();
            filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
            return filter;
        }

        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                final String action = intent.getAction();
                if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                    if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR) ==
                        BluetoothAdapter.STATE_ON) {
                        initialize();
                    }
                }
            }
        };

        // Sends a message to {@link BluetoothHDPService}.
        private void sendMessage(int what, int value) {
            if (mHealthService == null) {
                Log.d(TAG, "Health Service not connected.");
                return;
            }

            try {
                mHealthService.send(Message.obtain(null, what, value, 0));
            } catch (RemoteException e) {
                Log.w(TAG, "Unable to reach service.");
                e.printStackTrace();
            }
        }

        // Sends an update message, along with an HDP BluetoothDevice object, to
        // {@link BluetoothHDPService}.  The BluetoothDevice object is needed by the channel creation
        // method.
        private void sendMessageWithDevice(int what) {
            if (mHealthService == null) {
                Log.d(TAG, "Health Service not connected.");
                return;
            }

            try {
                mHealthService.send(Message.obtain(null, what, mDevice));
            } catch (RemoteException e) {
                Log.w(TAG, "Unable to reach service.");
                e.printStackTrace();
            }
        }

        /**
         * Dialog to display a list of bonded Bluetooth devices for user to select from.  This is
         * needed only for channel connection initiated from the application.
         */
        public static class SelectDeviceDialogFragment extends DialogFragment {

            public static SelectDeviceDialogFragment newInstance(String[] names, int position) {
                SelectDeviceDialogFragment frag = new SelectDeviceDialogFragment();
                Bundle args = new Bundle();
                args.putStringArray("names", names);
                args.putInt("position", position);
                frag.setArguments(args);
                return frag;
            }

            @Override
            public Dialog onCreateDialog(Bundle savedInstanceState) {
                String[] deviceNames = getArguments().getStringArray("names");
                int position = getArguments().getInt("position", -1);
                if (position == -1) position = 0;
                return new AlertDialog.Builder(getActivity())
                        .setTitle(R.string.select_device)
                        .setPositiveButton(R.string.ok,
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {
                                    ((BluetoothHDPActivity) getActivity()).connectChannel();
                                }
                            })
                        .setSingleChoiceItems(deviceNames, position,
                            new DialogInterface.OnClickListener() {
                                public void onClick(DialogInterface dialog, int which) {
                                    ((BluetoothHDPActivity) getActivity()).setDevice(which);
                                }
                            }
                        )
                        .create();
            }
        }
    }
4

1 回答 1

1

AFAIK Zephyr HxM 监视器不是 HDP,它使用 SPP 上的专有协议。有一个二进制 JAR 提供访问设备的 API。

我刚刚找到了一个可能有用的示例应用程序:https ://github.com/woody2/PulseTrainer

于 2014-02-05T15:15:35.740 回答