Google Glass GDK: How to Communicate with Android Device
Asked Answered
J

5

26

I'm looking for a way to send data between my Android Device and Google Glass that doesn't rely on Cloud API's. Is this supported? I see the Bluetooth connections in the My Glass app, which makes me think it can be done. Is there an example source code that shows how this is done? Or do I have to decompile the MyGlass app to figure it out?

Is there a preferred method for doing this kind of data transfer? Ideally I'd like to transfer data in both directions.

Jillene answered 2/12, 2013 at 20:14 Comment(8)
So I've rolled my own bluetooth connection and it seems to be working just fine. A lot of work to do, but I suppose it's worth it. If I don't see a better answer here I'll put code up tomorrow.Jillene
I assume it's just setting up a Bluetooth Serial connection and doing data transfer over that?Paisley
yea, I have a host app that manages data on the HH and acts as a master to the slave devices. Pretty straightforward, but kinda cumbersome.Jillene
Any tricks/gotchas to report implementing this? Or is it just "follow the docs at dev.google.com"? And as a lazy dev, code is always welcome, nudge, nudge, wink, wink :)Wichman
It's fairly straightforward. I'll put an answer up with all the code in one nice copy pasteable format tonight or tomorrow. I'm at a week long hackathon right now, thus the lack of time to do it atm.Jillene
It would be very nice to see a working example of bluetooth connection between an Android device and Glass :) You are gonna become my new idol ;)Edholm
I'll get it up tonight.Jillene
Answer is up. Hope it helps.Jillene
J
23

Ok, for the requesters....

EDIT: The code below still works, but I've put it into a git repo for those who are interested...

https://github.com/NathanielWaggoner/GoogleGlassBlutooth

Here is my Bluetooth Host/Client code. It's not perfect - You're going to need some patience, and there are some bugs on reconnection and such, but it does work. I've been sending data up to Glass From the Hand Held and driving UI updates (publishing live cards, updating live cards etc...) for about three days using this now.

Host:

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);
        }
    }
}

Client:

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);
            }
        }
    }
}

Host Manifest:

 <?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>

Client 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>

I'll leave the UI as an exercise to the reader.

Jillene answered 6/12, 2013 at 2:8 Comment(7)
I should mention that I've not done two way data transfer with this, so I can't vouch for that functionality. I've only done HH to Glass.Jillene
Can you please provide the UI too? I am quite a noob to GDK, but would really appreciate a fully working scaffolding code!Mcminn
Sorry I'm not going to update this answer further unless I substantially change the underlying code.. I may put a simple project version up on git hub.Jillene
Theoretically, is it possible this sort of connection could be done for iOS to Glass?Aphrodite
I see no reason it couldn't work. You would need to rewrite the bluetooth host code to suit the iOS paradigm, but it should otherwise work right out of the box.Jillene
Is a two way communication possible ? I am planning to send images to android device from Google glass and then get the output back to glass.Perseid
Yea two way is possible. Would take a little more work but totally doable.Jillene
S
4

There is no preferred method, but if you're looking to do it wirelessly, a Bluetooth 3.0 RFCOMM does work.

If you provide more specifics about the problem you're trying to solve in your question, I'll be able to provide a more specific answer.

Saltish answered 3/12, 2013 at 23:36 Comment(5)
Thanks Jenny. I've already resolved this. I've got a bluetooth server/client relationship set up between a HandHeld and Glass applications. It's just suprising to me that they don't have a better solution than rolling your own atm.Jillene
Haha, I just checked your profile. I guess by They, I meant you =0 No offense meant, much love for glass so far. Also GDK rocks =)Jillene
I'm glad you're enjoying it, and thanks for posting your code. If you have an idea of an API you'd like added to support this broadly, be sure to add it to the issue tracker: code.google.com/p/google-glass-api/issues/listSaltish
Thanks Jenny. Is it appropriate to put general API requets there? The fromat seems to be for issue/bugs. I've got a couple of things i'd like to see at the moment.Jillene
Enhancement requests should also go there. And if you're going to request one, use cases help us a lot. We use them a lot in prioritization.Saltish
C
1

Several things I noticed when following this solution (awesome work by the way!)

1) I could only create a bluetooth connection when my phone and the Google Glass were not already paired through the MyGlass app - If you are having trouble establishing a connection, try forgetting that pairing.

2) The Glass API does not support controlling your bluetooth connection through intents using commands like

Intent discoveryIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoveryIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, DISCOVER_DURATION);
startActivityForResult(discoveryIntent, REQUEST_BLU);

In order to make the Glass headset discoverable (rather than the phone it is connecting to), I needed to follow solutions similar to those like user4934624 provided at this question and shantanu gave at this question. I invoked a hidden method to access bluetooth functionality directly. Warning: the hidden method seems to have been there for years, but there is no guarantee it will continue to be in future APIs.

 // this method allows us to make the device discoverable without alerting the users
// NOTE!!!! This uses a hidden method, so it may be removed from the API in the future
public void makeDiscoverable (){

    Class <?> baClass = BluetoothAdapter.class;
    Method[] methods = baClass.getDeclaredMethods();

    // we want to use method setScanMode(int mode, int duration)
    // there are 2 setScanModes
    // so select the first setScanMode you see

    // test to see which method is the one we want
    //for (int i = 0; i<50; i++) {Log.d(Integer.toString(i), methods[i].getName());}

    //I had trouble calling the first setScanMode, so I called the second.
    // I need to pass in a discoverable time, but it stays discoverable indefinitely
    // Thus you must turn off the setScanMode as soon as the connection is established
    // I should probably write in some other security stuff to turn it off if connection fails
    // maybe a timer running on a different thread?


    Method mSetScanMode = methods[38];
    try {
        mSetScanMode.invoke(myBt, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,300);
        //mSetScanMode.invoke(myBt, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE);


    } catch (Exception e) {
        Log.e("discoverable", e.getMessage());
    }
}

// this method allows us to make the device not discoverable without alerting the user
// NOTE!!!! This uses a hidden method, so it may be removed from the API in the future
public void makeNotDiscoverable (){

    // see notes for makeDiscoverable
    Class <?> baClass = BluetoothAdapter.class;
    Method [] methods = baClass.getDeclaredMethods();

    Method mSetScanMode = methods[38];
    try {
       mSetScanMode.invoke(myBt, BluetoothAdapter.SCAN_MODE_CONNECTABLE,300);
    } catch (Exception e) {
        Log.e("discoverable", e.getMessage());
    }
}

Note that I first ran a test that output the names of all the methods in the class I mirrored; that allowed me to narrow my search for which method I wanted to use.

Chromato answered 29/6, 2015 at 21:16 Comment(3)
Thanks for the updated information! I haven't looked at this in almost two years, glad to see its still useful for people.Jillene
@Nathaniel, quick question. Did they have something like the Bluetooth connection controlled through the MyGlass app when you were programming this? If so, were you able to have two simultaneous Bluetooth connections at the same time (the MyGlass connection and our connection), or were you limited to one or the other? Thank you again for posting this code!Chromato
When I did this there were no API's available to handle this stuff. MyGlass existed, but you couldn't interface with it at all at this level.Jillene
U
0

The JoeGlass app for android claims to be a replacement for MyGlass. It will talk to your glass directly, using a bluetooth connection. I have not tried yet it but it is open source (github), so if it works, you are good.

Upward answered 26/6, 2014 at 9:8 Comment(0)
V
0

My book Beginning Google Glass Development has a full chapter on this topic, with fully working example code on using Bluetooth and socket to transfer data between Glass and Android (or iOS) devices.

The book is available at amazon: http://www.amazon.com/Beginning-Google-Glass-Development-Jeff/dp/1430267887

and the source code is available for download at http://www.apress.com/downloadable/download/sample/sample_id/1562/

Vidovik answered 11/11, 2014 at 6:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.