Android Bluetooth Tutorial

In addition to interacting with vehicles by using Telematics (through an Internet connection), it's possible to use Bluetooth 4.0 to send and receive commands. This has the benefit of being able to receive new data from the vehicle pushed directly to the device as soon as states change.

Requirements

In order to use Bluetooth, the Android device has to support Bluetooth Low Energy (BLE) in peripheral mode. To see if your Android phone supports BLE in peripheral mode, have a look at this list.
The emulator uses Bluetooth connectivity through the Web Bluetooth initiative. At the moment it's only supported in Google Chrome on OS X, Linux and Chromebooks.

Bluetooth Broadcasting

This section outlines how to set the app to Bluetooth broadcasting mode, making it visible to vehicles.

The main access point is the class Broadcaster, which accepts incoming connections (Links). A Link handles the authorisation and different functionalities between the device and the connected vehicle.

Access to the Broadcaster is provided by the HMKit class.

Broadcaster broadcaster = HMKit.getInstance().getBroadcaster();

Once the SDK has been initialised, the Broadcaster is ready to be operated. In order to observe incoming links a listener must be set. Once this is done, broadcasting can be started.

broadcaster.setListener(new BroadcasterListener() {
    @Override
    public void onStateChanged(Broadcaster.State oldState) {}

    @Override
    public void onLinkReceived(ConnectedLink link) {}

    @Override
    public void onLinkLost(ConnectedLink link) {}
});

broadcaster.startBroadcasting(new Broadcaster.StartCallback() {
    @Override
    public void onBroadcastingStarted() {

    }

    @Override
    public void onBroadcastingFailed(BroadcastError error) {
            Log.e(TAG, "can't start broadcasting " + broadcastError.getType());
            // error handling
    }
});

onLinkLost is invoked when the Bluetooth connection is lost.

@Override
public void onLinkLost(ConnectedLink link) {
    // Application code after a Link has disconnected from the device
}

Interacting with a Vehicle

After a Link has been received via BroadcasterListener, it is possible to start managing the incoming events and send commands to the link. To receive link events, a ConnectedLinkListener has to be set.

The ConnectedLinkListener is the cornerstone class to interact with the linked car.

link.setListener(new ConnectedLinkListener() { ... });

Connecting from the Emulator

To connect to the Android device using the emulator, use the bottom left Bluetooth button. This will drop down the Bluetooth connect panel in Google Chrome and you should choose the device starting with "HM".

Responding to an Authorisation

If a connected vehicle tries to authorise the device, a confirmation is required by the ConnectedLinkListener, usually by involving user input. If the user does not respond before the timeout interval, the request is fails with a timeout error. If the user tries to respond after the timeout interval, an exception is thrown.

@Override
public void onAuthenticationRequest(ConnectedLink connectedLink, ConnectedLinkListener.AuthenticationCallback callback) {
    confirmButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        callback.approve();
        }
    });

    declineButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
        callback.decline();
        }
    });
}

Receive a Command

Incoming commands are dispatched via LinkListener. The content of command corresponds to the Auto API.

The callback provides raw bytes that can be parsed with CommandResolver.resolve() in order to construct the command object. Parsing and construction of all Auto APIs commands are built into HMKit.

@Override
public void onCommandReceived(Link link, Bytes bytes) {
    Command command = CommandResolver.resolve(bytes);

    if (command instanceof Doors.State) {
        Doors.State doorsState = (Doors.State) command;
        // access the doors state object
    }
}

Send a Command

To send a command from the app, the sendCommand() method is used. The bytes that need to be sent for different APIs can be found in Auto API class. Please note that this is only possible when the Link to the vehicle is authenticated. It's only allowed to send one command at a time. Queueing of several commands in a sequence has to be done on the application level.

Read more about Auto API

link.sendCommand(new Doors.LockUnlockDoors(LockState.UNLOCKED), new Link.CommandCallback() {
    @Override
    public void onCommandSent() {
        // command was sent
    }
    @Override
    public void onCommandFailed(LinkError error) {
        // error handling
    }
});

Queue Commands

There is a queue package that can be used to send multiple commands in a sequence. It is meant to be used as a layer between HMKit and the app, where all link communication is forwarded to the queue. It returns the commands or failure indications if the commands fail. The package is available in GitHub.

Terminate

Once the SDK is not used anymore, for instance when closing the app, it should be terminated. This clears the Bluetooth service and unregisters all BroadcastReceivers.

HMKit.getInstance().terminate();