我正在寻找一种在我的Android设备和Google Glass之间发送不依赖于Cloud API的数据的方法.这支持吗?我在My Glass应用程序中看到蓝牙连接,这让我觉得可以完成.是否有示例源代码显示如何完成此操作?或者我是否必须反编译MyGlass应用程序才能弄明白?
有没有一种首选的方法来进行这种数据传输?理想情况下,我想在两个方向上传输数据.
好的,对于请求者....
编辑:下面的代码仍然有效,但我已经把它放入一个git仓库为感兴趣的人...
https://github.com/NathanielWaggoner/GoogleGlassBlutooth
这是我的蓝牙主机/客户端代码.它并不完美 - 你需要一些耐心,重新连接有一些错误,但它确实有效.我现在一直使用此功能将数据发送到Glass From the Hand Held并推动UI更新(发布实时卡,更新实时卡等...)约三天.
主办:
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.UUID; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothServerSocket; 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.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.Menu; import android.widget.TextView; public class BluetoothHost extends Activity { public static String msgToSend=""; public static final int STATE_CONNECTION_STARTED = 0; public static final int STATE_CONNECTION_LOST = 1; public static final int READY_TO_CONN = 2; public static final String DEVICE_NAME = "device_name"; public static final String TOAST = "toast"; // our last connection ConnectedThread mConnectedThread;// = new ConnectedThread(socket); // track our connections ArrayList<ConnectedThread> mConnThreads; // bt adapter for all your bt needs (where we get all our bluetooth powers) BluetoothAdapter myBt; // list of sockets we have running (for multiple connections) ArrayList<BluetoothSocket> mSockets = new ArrayList<BluetoothSocket>(); // list of addresses for devices we've connected to ArrayList<String> mDeviceAddresses = new ArrayList<String>(); // just a name, nothing more... String NAME="G6BITCHES"; // We can handle up to 7 connections... or something... UUID[] uuids = new UUID[2]; // some uuid's we like to use.. String uuid1 = "05f2934c-1e81-4554-bb08-44aa761afbfb"; String uuid2 = "c2911cd0-5c3c-11e3-949a-0800200c9a66"; // just a tag.. String TAG = "G6 Bluetooth Host Activity"; // constant we define and pass to startActForResult (must be >0), that the system passes back to you in your onActivityResult() // implementation as the requestCode parameter. int REQUEST_ENABLE_BT = 1; AcceptThread accThread; TextView connectedDevices; Handler handle; BroadcastReceiver receiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // the activity for this is pretty stripped, just a basic selection ui.... setContentView(R.layout.activity_main); uuids[0] = UUID.fromString(uuid1); uuids[1] = UUID.fromString(uuid2); connectedDevices = (TextView) findViewById(R.id.connected_devices_values); handle = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case STATE_CONNECTION_STARTED: connectedDevices.setText(msg.getData().getString("NAMES")); break; case STATE_CONNECTION_LOST: connectedDevices.setText(""); startListening(); break; case READY_TO_CONN: startListening(); default: break; } } }; // .... myBt = BluetoothAdapter.getDefaultAdapter(); // run the "go get em" thread.. accThread = new AcceptThread(); accThread.start(); } public void startListening() { if(accThread!=null) { accThread.cancel(); }else if (mConnectedThread!= null) { mConnectedThread.cancel(); } else { accThread = new AcceptThread(); accThread.start(); } } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } private class AcceptThread extends Thread { private BluetoothServerSocket mmServerSocket; BluetoothServerSocket tmp; public AcceptThread() { BluetoothServerSocket tmp = null; try { tmp = myBt.listenUsingInsecureRfcommWithServiceRecord(NAME, uuids[0]); } catch (IOException e) { } mmServerSocket = tmp; } public void run() { Log.e(TAG,"Running?"); BluetoothSocket socket = null; // Keep listening until exception occurs or a socket is returned while (true) { try { socket = mmServerSocket.accept(); } catch (IOException e) { e.printStackTrace(); break; } // If a connection was accepted if (socket != null) { try { mmServerSocket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // Do work to manage the connection (in a separate thread) manageConnectedSocket(socket); break; } } } /** Will cancel the listening socket, and cause the thread to finish */ public void cancel() { try { mmServerSocket.close(); Message msg = handle.obtainMessage(READY_TO_CONN); handle.sendMessage(msg); } catch (IOException e) { } } } private void manageConnectedSocket(BluetoothSocket socket) { // start our connection thread mConnectedThread = new ConnectedThread(socket); mConnectedThread.start(); // Send the name of the connected device back to the UI Activity // so the HH can show you it's working and stuff... String devs=""; for(BluetoothSocket sock: mSockets) { devs+=sock.getRemoteDevice().getName()+"\n"; } // pass it to the UI.... Message msg = handle.obtainMessage(STATE_CONNECTION_STARTED); Bundle bundle = new Bundle(); bundle.putString("NAMES", devs); msg.setData(bundle); handle.sendMessage(msg); } private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { Log.d(TAG, "create ConnectedThread"); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the BluetoothSocket input and output streams try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "temp sockets not created", e); } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; // Keep listening to the InputStream while connected while (true) { try { //byte[] blah = ("System Time:" +System.currentTimeMillis()).getBytes(); if(!msgToSend.equals("")) { Log.e(TAG,"writing!"); write(msgToSend.getBytes()); setMsg(""); } Thread.sleep(1000); } catch (Exception e) { Log.e(TAG, "disconnected", e); connectionLost(); } } } public void connectionLost() { Message msg = handle.obtainMessage(STATE_CONNECTION_LOST); handle.sendMessage(msg); } /** * Write to the connected OutStream. * @param buffer The bytes to write */ public void write(byte[] buffer) { try { mmOutStream.write(buffer); } catch (IOException e) { Log.e(TAG, "Exception during write", e); connectionLost(); } } public void cancel() { try { mmSocket.close(); Message msg = handle.obtainMessage(READY_TO_CONN); handle.sendMessage(msg); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } public static synchronized void setMsg(String newMsg) { msgToSend = newMsg; } public static class HostBroadRec extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Bundle b= intent.getExtras(); String vals =""; for(String key: b.keySet()) { vals+=key+"&"+b.getString(key)+"Z"; } BluetoothHost.setMsg(vals); } } }
客户:
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Set; 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.os.Handler; import android.os.Looper; import android.os.Message; import android.text.format.DateFormat; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; public class BluetoothClient extends Activity { public static final int READY_TO_CONN =0; public static final int CANCEL_CONN =1; public static final int MESSAGE_READ =2; // holds the bluetooth names/ids that we're associated with. ArrayAdapter<String> btArray; // bt adapter for all your bt needs BluetoothAdapter myBt; String NAME="G6BITCHES"; String TAG = "G6 Bluetooth Slave Activity"; UUID[] uuids = new UUID[2]; // some uuid's we like to use.. String uuid1 = "05f2934c-1e81-4554-bb08-44aa761afbfb"; String uuid2 = "c2911cd0-5c3c-11e3-949a-0800200c9a66"; // DateFormat df = new DateFormat("ddyyyy") ConnectThread mConnThread; Spinner devices; Handler handle; // constant we define and pass to startActForResult (must be >0), that the system passes back to you in your onActivityResult() // implementation as the requestCode parameter. int REQUEST_ENABLE_BT = 1; // bc for discovery mode for BT... private final BroadcastReceiver mReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // When discovery finds a device if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Get the BluetoothDevice object from the Intent BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // Add the name and address to an array adapter to show in a ListView if(device!= null) { if(device.getName().contains("Nexus")) { } else { btArray.add(device.getName() + "\n" + device.getAddress()); } } update(); } } }; Context ctx; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // publishCards(this); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); ctx = this; handle = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case READY_TO_CONN: mConnThread=null; update(); break; case CANCEL_CONN: break; case MESSAGE_READ: byte[] readBuf = (byte[]) msg.obj; // construct a string from the valid bytes in the buffer String readMessage = new String(readBuf, 0, msg.arg1); Log.e(TAG,"received: "+readMessage); if (readMessage.length() > 0) { // do soemthing... } // updateCards(ctx, readMessage); // update() // mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage); break; default: break; } } }; btArray = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, android.R.id.text1); btArray.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); uuids[0] = UUID.fromString(uuid1); uuids[1] = UUID.fromString(uuid2); // spinner for displaying available devices for pairing devices = (Spinner) findViewById(R.id.devices_spinner); devices.setAdapter(btArray); // use the same UUID across an installation // should allow clients to find us repeatedly myBt = BluetoothAdapter.getDefaultAdapter(); if (myBt == null) { Toast.makeText(this, "Device Does not Support Bluetooth", Toast.LENGTH_LONG).show(); } else if (!myBt.isEnabled()) { // we need to wait until bt is enabled before set up, so that's done either in the following else, or // in the onActivityResult for our code ... Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT); } else { detectAndSetUp(); } setContentView(R.layout.bluetooth_activity_layout); } @Override public void onDestroy() { unregisterReceiver(mReceiver); super.onDestroy(); } @Override protected void onActivityResult (int requestCode, int resultCode, Intent data){ if(requestCode == REQUEST_ENABLE_BT) { if (resultCode != RESULT_OK) { Toast.makeText(this, "Failed to enable Bluetooth", Toast.LENGTH_LONG).show(); } else { Toast.makeText(this, "Bluetooth Enabled", Toast.LENGTH_LONG).show(); detectAndSetUp(); } } } private void detectAndSetUp() { IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy Set<BluetoothDevice> pairedDevices = myBt.getBondedDevices(); // If there are paired devices if (pairedDevices.size() > 0) { // Loop through paired devices for (BluetoothDevice device : pairedDevices) { if(device.getName().contains("Nexus")) { } else { btArray.add(device.getName() + "\n" + device.getAddress()); } // Add the name and address to an array adapter to show in a ListView // btArray.add(device.getName() + "\n" + device.getAddress()); // update(); } } myBt.startDiscovery(); } public void update() { devices = (Spinner) findViewById(R.id.devices_spinner); devices.setAdapter(btArray); devices.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) { if(mConnThread!=null) { Log.e(TAG,"Canceling old connection, and starting new one."); mConnThread.cancel(); } else { Log.e(TAG,"got a thing..."); String str = ((TextView)arg1).getText().toString(); Log.e(TAG,"tots: "+str); String[] vals = str.split("\n"); Log.e(TAG,"mac: "+vals[1]); BluetoothDevice dev = myBt.getRemoteDevice(vals[1]); mConnThread = new ConnectThread(dev); mConnThread.run(); } } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.bluetooth, menu); return true; } private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; public ConnectThread(BluetoothDevice device) { Log.e(TAG,"ConnectThread start...."); // 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 { // this seems to work on the note3... // you can remove the Insecure if you want to... tmp = device.createInsecureRfcommSocketToServiceRecord(uuids[0]); // Method m; // this is an approach I've seen others use, it wasn't nescesary for me, // but your results may vary... // m = device.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class}); // tmp = (BluetoothSocket) m.invoke(device, 1); // } catch (NoSuchMethodException e1) { // // TODO Auto-generated catch block // e1.printStackTrace(); // } catch (IllegalArgumentException e2) { // // TODO Auto-generated catch block // e2.printStackTrace(); // } catch (IllegalAccessException e3) { // // TODO Auto-generated catch block // e3.printStackTrace(); // } catch (InvocationTargetException e4) { // // TODO Auto-generated catch block // e4.printStackTrace(); // } // if(tmp.isConnected()) { // break // } } catch (Exception e) { Log.e(TAG,"Danger Will Robinson"); e.printStackTrace(); } mmSocket = tmp; } public void run() { // Cancel discovery because it will slow down the connection myBt.cancelDiscovery(); Log.e(TAG,"stopping discovery"); try { // Connect the device through the socket. This will block // until it succeeds or throws an exception Log.e(TAG,"connecting!"); mmSocket.connect(); } catch (IOException connectException) { Log.e(TAG,"failed to connect"); // Unable to connect; close the socket and get out try { Log.e(TAG,"close-ah-da-socket"); mmSocket.close(); } catch (IOException closeException) { Log.e(TAG,"failed to close hte socket"); } Log.e(TAG,"returning.."); return; } Log.e(TAG,"we can now manage our connection!"); // Do work to manage the connection (in a separate thread) manageConnectedSocket(mmSocket); } /** Will cancel an in-progress connection, and close the socket */ public void cancel() { try { mmSocket.close(); Message msg = handle.obtainMessage(READY_TO_CONN); handle.sendMessage(msg); } catch (IOException e) { } } } public void manageConnectedSocket(BluetoothSocket mmSocket) { ConnectedThread t = new ConnectedThread(mmSocket); t.start(); // manage your socket... I'll probably do a lot of the boiler plate here later } private class ConnectedThread extends Thread { private final BluetoothSocket mmSocket; private final InputStream mmInStream; private final OutputStream mmOutStream; public ConnectedThread(BluetoothSocket socket) { Log.d(TAG, "create ConnectedThread"); mmSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Get the BluetoothSocket input and output streams try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { Log.e(TAG, "temp sockets not created", e); } mmInStream = tmpIn; mmOutStream = tmpOut; } public void run() { Log.i(TAG, "BEGIN mConnectedThread"); byte[] buffer = new byte[1024]; int bytes; // Keep listening to the InputStream while connected while (true) { try { // byte[] blah = ("System Time:" +System.currentTimeMillis()).getBytes(); // write(blah); // Thread.sleep(1000); // Read from the InputStream bytes = mmInStream.read(buffer); // Send the obtained bytes to the UI Activity handle.obtainMessage(MESSAGE_READ, bytes, -1, buffer) .sendToTarget(); // .sendToTarget(); } catch (Exception e) { Log.e(TAG, "disconnected", e); connectionLost(); // break; } } } public void connectionLost() { Message msg = handle.obtainMessage(CANCEL_CONN); // Bundle bundle = new Bundle(); // bundle.putString("NAMES", devs); // msg.setData(bundle); handle.sendMessage(msg); } /** * Write to the connected OutStream. * @param buffer The bytes to write */ public void write(byte[] buffer) { try { mmOutStream.write(buffer); // Share the sent message back to the UI Activity // mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer) // .sendToTarget(); } catch (IOException e) { Log.e(TAG, "Exception during write", e); } } public void cancel() { try { mmSocket.close(); } catch (IOException e) { Log.e(TAG, "close() of connect socket failed", e); } } } }
主机清单:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="transapps.android_bluetooth_host" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="17" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name="transapps.android_bluetooth_host.BluetoothHost" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <receiver android:name=".BluetoothHost$HostBroadRec" > <intent-filter> <action android:name="transapps.g6.new.alert" /> </intent-filter> </receiver> </application> </manifest>
客户清单:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="transapps.android_blutooth" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="15" android:targetSdkVersion="15" /> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <activity android:name="transapps.android_blutooth.BluetoothClient" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
我会将UI作为练习留给读者.