For this lab, you will learn about some of the pieces for creating a connection between two co-located devices using Bluetooth.
Android provides a detailed API (open this link for reference!) for interactive with Bluetooth. There are a number of steps and details, so you'll be working with a project that has many of the fussy pieces in place for you (like reading and writing data over a Socket!).
-
You'll be filling in the remaining pieces from a Sample Project provided by Google. Google includes lots of samples demonstrating how to use particular pieces of functionality; reading and adapting the provided projects is a great way to learn new skills. There are a lot of comments, though that sometimes makes it hard to follow all the pieces. Read carefully!
-
A lot of this work will actually just be using
Intents
to interact with the Bluetooth radio, so you may want your notes for that handy.
Open up this project in Android Studio to get started. IMPORTANT NOTE: you will need to run this project on a physical device, not the emulator---the emulator doesn't support Bluetooth :(
Your task is to fill in the missing pieces of code, following the instructions below. I've marked each location with a TODO
comment, which should show up in blue in Android Studio.
-
Start by reading through The Basics to get a sense for what classes will be in place and what their roles are. You only need to focus on the first 4:
BluetoothAdapter
,BluetoothDevice
,BluetoothSocket
, andBluetoothServerSocket
(the rest are for other kinds of Bluetooth connections, like audio transfer and stuff). You don't need to know all the methods or details of these classes, but should be familiar with their general, one-sentence purposes! -
You'll need to request permission to use Bluetooth. Add the appropriate
<uses-permission>
attributes: one forBLUETOOTH
(for communication; included) and one forBLUETOOTH_ADMIN
(to "discover" devices and make connections). -
The main UI is defined in the
BluetoothChatFragment
class, which is a Fragment that holds the chat system. Start by filling in theonCreate()
callback by fetching the default Bluetooth adapter and saving it to an instance variable (mBluetoothAdapter
). If the adapter doesn't exist (isnull
), you shouldToast
a message that Bluetooth isn't available (using theActivity's
Application Context
so that the Toast lasts), and then callfinish()
on the Fragment's Activity (to close the application). -
You'll want your app to make sure that the user has Bluetooth turned on. If the
BluetoothAdapter
is notenabled
, you'll want to prompt the user to enable it, such as by launching the "Settings" app. Create an Implicit Intent for the actionBluetoothAdapter.ACTION_REQUEST_ENABLE
, and send this Intent for a result (with the result code ofREQUEST_ENABLE_BT
). Look in theonActivityResult()
method to see what happens when we get a response back!
- The
BluetoothChatService
(stored in the instance variablemChatService
) is an object representing a "background service"---think an AsyncTask but with a much longer lifespan. This particular service handles sending bytes of data back and forth over Bluetooth. We'll talk aboutServices
more later in the course.
- In order for a device to connect to yours over Bluetooth, your device will need to be discoverable: effectively, it has to respond to public queries about its existence (sort of like having your instant messaging status as "Online/Available"). In the
ensureDiscoverable()
helper method, check if the device is currently discoverable by callinggetScanMode()
on theBluetoothAdapter
---it should return a value ofBluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
.
-
If this IS NOT the case, then you should send another Implicit Intent to handle the
BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE
action.-
You should also include (put) an extra that has the key
BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION
and a value of300
, so that we are in "discoverable" mode for 300 seconds. -
This intent does NOT need to be started for a result!
-
- The discovery of devices is controlled by the
DeviceListActivity
Activity. This is a separate Activity that will actually appear as a popup dialog (though it doesn't useDialogFragment
; it just "themes" the Activity as a dialog in theManifest
). The Activity'sonCreate()
does a lot of UI work (including setting up an Adapter!), but it also needs to set up aBroadcastReceiver
to listen for events like when devices are found.
-
This is the equivalent of declaring a
<receiver>
and<intent-filter>
in theManifest
, but we need to do it in Java since the Receiver isn't a separate class (and since we want to do it dynamically). -
First instantiate a new
IntentFilter
object (giving it theBluetoothDevice.ACTION_FOUND
action). -
Then use the
registerReceiver(receiver, intentFilter)
method, passing it the already-existing receiver (mReceiver
) and theIntentFilter
you just created! -
Then repeat the above two steps, but this time for the
Bluetooth.ACTION_DISCOVERY_FINISHED
action. This will register an additionalIntentFilter
on the same receiver.
- We can actually begin searching for devices by filling in the
doDiscovery()
helper method (called when the Scan button is pressed).
-
Add a check to see if the
BluetoothAdapter
currentlyisDiscovering()
. If so, then you should tell the adapter tocancelDiscovery()
. -
No matter if the check is true or false, tell the adapter to
startDiscovery()
to begin searching for devices!
- Once the user has selected a device to connect to, we handle that connection back in the
BluetoothChatFragment
. Fill in that class'sconnectDevice()
helper method to connect to the device!
-
First you'll want to get the device's "address" (a MAC address that acts as a unique identifier) from the Intent's extras: get the
Bundle
of extras from the Intent, then get the String with the keyDeviceListActivity.EXTRA_DEVICE_ADDRESS
. -
You can then find the device (a
BluetoothDevice
object) by calling the.getRemoteDevice()
method on theBluetoothAdapter
and passing this address -
Finally, you can use the
mChatService
's.connect()
method to connect to this device (passing down thesecure
option as a second parameter). TheBluetoothChatService.connect()
method creates a newThread
to do the communication work, and opens up network sockets so that messages can be passed between the devices. (This is actually part of the hard part or working with Bluetooth; luckily we have a class to abstract that for us!)
- The last part is to actually send a message! In the
sendMessage()
helper inBluetoothChatFragment
, fill in the details so that the String can be send to the socket in the chat service.
-
First you need to convert the message String into a
byte[]
(for communication over the socket). Use the String'sgetBytes()
method to convert. -
Then you can tell
mChatService
to.write()
those bytes! -
We then need to reset the
mOutStringBuffer
instance variable (which keeps track of the message that has been typed so far). Use.setLength()
to give it a length of 0, which will effectively make it empty. -
And finally, because we've changed the outgoing message, set the text of the
mOutEditText
TextView to be the (now empty)mOutStringBuffer
.
And that's it! You should now have a working chat system! Search for and connect to someone else's device and try saying "hello"! :)