Swap over bluetooth (in development)

Overview

Most of the bluetooth connection stuff is stock standard stuff from the Android SDK. However, once we move beyond connecting, and to requesting and serving information over Bluetooth, it becomes more specific. Most bluetooth stuff (communication related, not UI related) should be in org.fdroid.fdroid.net.bluetooth.* and the .httpish package below that.

Communication protocol

I figured there was going to be a bit of arbitrary information exchange, so I went ahead and made something which works essentially like HTTP (hence the .httpish package name). Each request will begin with a request type (GET or HEAD) and then HTTP headers. The server responses have headers and optionally a body.

The BluetoothServerSocket is encapsulated in a BluetoothServer, which continually listens for incoming connections, then handles them in a BluetoothServer.Connection object.

The BluetoothServer.Connection object will continually monitor its socket for incoming info, and parse them as if they were HTTP requests (i.e. request method, headers and body).

Bluetooth swap workflow

(Until UX stuff comes through from carrie, I've made it pretty generic, purely so that I can test the protocol stuff, so this is subject to change)

  1. User starts a swap
  2. Selects apps to swap
  3. Presented with the wifi connection screen (and a button to use Bluetooth)
  4. When pressing the use bluetooth button, F-Droid:

Getting the code and contributing

The code currently lives in a branch called bluetooth-swap in the main F-Droid repo on GitLab.

I'll try to ensure that I (pserwylo) don't push directly to that, but rather create MR's so that others can review code if necessary. In the near future, I'm also going to create a Milestone in the issue tracker on gitlab to deal with bluetooth swap, so that we can create issues and assign them to that milestone, and see progress towards a stable implementation.

Outstanding tasks

Currently, you are able to start a Bluetooth swap server, which is able to listen for incoming client connections, parse any incoming data, forward it to a local proxy webserver which is the same thing that handles WiFi swapping, and serves relevant files from the webroot in response.

The client side still needs much more work though, in that the infrastructure which downloads icons, repo indexes, and .apk files does not yet know about how to do this over Bluetooth.

Connect to a bluetooth swap

This is distinct from creating a swap (which is already implemented). We need to be able to create a new repo on the swap client, so that the UpdateService is able to pull down an index from that repo and populate the database with apps from that repo.

There are two ways in which this happens with the WiFi swap right now.

All three of them have the same effect, which is to send an intent to F-Droid which tells it to add a repo (e.g. "http://10.0.0.1:8888/fdroid/repo?swap=1&fingerprint=ABC"). Thus, they all end up in the same location, but use a different method to get there.

For Bluetooth, it could happen in a similar way, but this time the intent would look like, e.g. "bluetooth://aa:bb:cc:00:11:22/?fingerprint=ABC" (probably doesn't even need "swap=1", at least not until someone builds an fdroidserver repo which works over Bluetooth somehow):

We can't get people to visit a URL over the browser, because that will depend on the devices being on the same TCP/IP network. But if they are using Bluetooth, than this is not the case. That is, even though I've mimicked HTTP with my bluetooth protocol (see above), it is not for the purpose of interoperating with existing HTTP clients.

The end goal is to have the clients F-Droid end up here, which will require modification of the NewRepoConfig class so that it doesn't assume HTTP, and also have the manifest register interest in the relevant bluetooth URLs.

Decide more on the UX (not exactly UI at this point) for Bluetooth swap

The server is relatively straightforward.

I'm presuming from here, that we do the same as with WiFi, which is to offer NFC, and then display a QR Code with the relevant "bluetooth://.../" URL encoded in it.

The things which are different from wifi though, are:

Make BluetoothDownloader work for client

Currently, you can instantiate a BluetoothDownloader, and actually send http(ish) requests to a F-Droid app with a running BluetoothServer running. An example of this can be seen in some test code here.

However, notice that that code requires a BluetoothConnection to be passed to it?

The typical way in which F-Droid connects to a remote repository to download either an icon, an index, or indeed a .apk is to use the DownloaderFactory to create the relevant downloader for a URL. The API for this class does not know about BluetoothConnections, nor should it need to (because the vast majority of downloads will be from a HTTP repo).

To solve this, we need one of two things:

The second would be more resiliant to Bluetooth turning off and on again, because between requests for files, it wont try and maintain an open socket, whereas the global connection would. To make the global connection (option 1) resiliant in this way, it will essentially have to work like 2. anyway, and be able to reconnect when required. However, I'm not sure about the other implications of option 2, such as having to prompt the user to connect to bluetooth because F-Droid needs to download an icon, or the performance overhead of continually creating new connections, e.g. for downloading several icons to display in the swap app list.