WIP: Bluetooth can actually transfer indexes and apks over HTTPish!
It is very hacky, and I did it through the non-swap interface, and it only works once then the state stuffs up and it no longer accepts incomming connections, but it worked! Now to smooth out all the things.
This commit is contained in:
parent
9da6893ac3
commit
9180c9f5c0
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<org.fdroid.fdroid.views.swap.BluetoothDeviceListView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/white">
|
||||
|
||||
</org.fdroid.fdroid.views.swap.BluetoothDeviceListView>
|
@ -39,7 +39,6 @@ import org.fdroid.fdroid.localrepo.peers.BluetoothFinder;
|
||||
import org.fdroid.fdroid.localrepo.peers.BonjourFinder;
|
||||
import org.fdroid.fdroid.localrepo.peers.Peer;
|
||||
import org.fdroid.fdroid.localrepo.type.BluetoothSwap;
|
||||
import org.fdroid.fdroid.localrepo.type.BonjourBroadcast;
|
||||
import org.fdroid.fdroid.localrepo.type.SwapType;
|
||||
import org.fdroid.fdroid.localrepo.type.WifiSwap;
|
||||
import org.fdroid.fdroid.net.WifiStateChangeService;
|
||||
@ -65,8 +64,10 @@ import java.util.TimerTask;
|
||||
public class SwapService extends Service {
|
||||
|
||||
private static final String TAG = "SwapManager";
|
||||
private static final String SHARED_PREFERENCES = "swap-state";
|
||||
public static final String SHARED_PREFERENCES = "swap-state";
|
||||
private static final String KEY_APPS_TO_SWAP = "appsToSwap";
|
||||
private static final String KEY_BLUETOOTH_ENABLED = "bluetoothEnabled";
|
||||
private static final String KEY_WIFI_ENABLED = "wifiEnabled";
|
||||
|
||||
@NonNull
|
||||
private Set<String> appsToSwap = new HashSet<>();
|
||||
@ -353,6 +354,25 @@ public class SwapService extends Service {
|
||||
}
|
||||
|
||||
|
||||
// =============================================================
|
||||
// Remember which swap technologies a user used in the past
|
||||
// =============================================================
|
||||
|
||||
private void persistPreferredSwapTypes() {
|
||||
persistence().edit()
|
||||
.putBoolean(KEY_BLUETOOTH_ENABLED, bluetoothSwap.isConnected())
|
||||
.putBoolean(KEY_WIFI_ENABLED, wifiSwap.isConnected())
|
||||
.commit();
|
||||
}
|
||||
|
||||
private boolean wasBluetoothEnabled() {
|
||||
return persistence().getBoolean(KEY_BLUETOOTH_ENABLED, false);
|
||||
}
|
||||
|
||||
private boolean wasWifiEnabled() {
|
||||
return persistence().getBoolean(KEY_WIFI_ENABLED, false);
|
||||
}
|
||||
|
||||
// ==========================================
|
||||
// Local repo stop/start/restart handling
|
||||
// ==========================================
|
||||
@ -409,6 +429,14 @@ public class SwapService extends Service {
|
||||
// Interacting with Bluetooth adapter
|
||||
// ==========================================
|
||||
|
||||
public BonjourFinder getBonjourFinder() {
|
||||
return bonjourFinder;
|
||||
}
|
||||
|
||||
public BluetoothFinder getBluetoothFinder() {
|
||||
return bluetoothFinder;
|
||||
}
|
||||
|
||||
public boolean isBluetoothDiscoverable() {
|
||||
return bluetoothSwap.isConnected();
|
||||
}
|
||||
@ -487,6 +515,16 @@ public class SwapService extends Service {
|
||||
IntentFilter filter = new IntentFilter(BLUETOOTH_STATE_CHANGE);
|
||||
filter.addAction(WIFI_STATE_CHANGE);
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(receiveSwapStatusChanged, filter);
|
||||
|
||||
if (wasBluetoothEnabled()) {
|
||||
Log.d(TAG, "Previously the user enabled Bluetooth swap, so enabling again automatically.");
|
||||
bluetoothSwap.startInBackground();
|
||||
}
|
||||
|
||||
if (wasWifiEnabled()) {
|
||||
Log.d(TAG, "Previously the user enabled Wifi swap, so enabling again automatically.");
|
||||
wifiSwap.startInBackground();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -505,6 +543,7 @@ public class SwapService extends Service {
|
||||
detachService();
|
||||
}
|
||||
}
|
||||
persistPreferredSwapTypes();
|
||||
}
|
||||
};
|
||||
|
||||
@ -520,15 +559,10 @@ public class SwapService extends Service {
|
||||
}
|
||||
|
||||
public void disableAllSwapping() {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
getBluetoothSwap().stop();
|
||||
getWifiSwap().stop();
|
||||
Log.i(TAG, "Asked to stop swapping, will stop bluetooth, wifi, and move service to BG for GC.");
|
||||
getBluetoothSwap().stopInBackground();
|
||||
getWifiSwap().stopInBackground();
|
||||
detachService();
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -8,9 +8,8 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothServer;
|
||||
import org.fdroid.fdroid.localrepo.type.BluetoothSwap;
|
||||
|
||||
// TODO: Still to be implemented
|
||||
public class BluetoothFinder extends PeerFinder<BluetoothPeer> {
|
||||
|
||||
private static final String TAG = "BluetoothFinder";
|
||||
@ -69,8 +68,8 @@ public class BluetoothFinder extends PeerFinder<BluetoothPeer> {
|
||||
if (adapter.isDiscovering()) {
|
||||
// TODO: Can we reset the discovering timeout, so that it doesn't, e.g. time out
|
||||
// in 3 seconds because we had already almost completed the previous scan?
|
||||
Log.d(TAG, "Requested bluetooth scan when already scanning, will cancel previous scan before continuing.");
|
||||
adapter.cancelDiscovery();
|
||||
Log.d(TAG, "Requested bluetooth scan when already scanning, so will ignore request.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!adapter.startDiscovery()) {
|
||||
@ -90,7 +89,7 @@ public class BluetoothFinder extends PeerFinder<BluetoothPeer> {
|
||||
}
|
||||
|
||||
private void onDeviceFound(BluetoothDevice device) {
|
||||
if (device != null && device.getName() != null && device.getName().startsWith(BluetoothServer.BLUETOOTH_NAME_TAG)) {
|
||||
if (device != null && device.getName() != null && device.getName().startsWith(BluetoothSwap.BLUETOOTH_NAME_TAG)) {
|
||||
foundPeer(new BluetoothPeer(device));
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,8 @@ import android.bluetooth.BluetoothDevice;
|
||||
import android.os.Parcel;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothServer;
|
||||
import org.fdroid.fdroid.localrepo.type.BluetoothSwap;
|
||||
|
||||
// TODO: Still to be implemented.
|
||||
public class BluetoothPeer implements Peer {
|
||||
|
||||
private BluetoothDevice device;
|
||||
@ -22,7 +21,7 @@ public class BluetoothPeer implements Peer {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return device.getName().replaceAll("^" + BluetoothServer.BLUETOOTH_NAME_TAG, "");
|
||||
return device.getName().replaceAll("^" + BluetoothSwap.BLUETOOTH_NAME_TAG, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -37,7 +36,7 @@ public class BluetoothPeer implements Peer {
|
||||
|
||||
@Override
|
||||
public String getRepoAddress() {
|
||||
return "bluetooth://" + device.getAddress() + "/fdroid/repo";
|
||||
return "bluetooth://" + device.getAddress().replace(':', '-') + "/fdroid/repo";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -68,6 +68,7 @@ public class BonjourFinder extends PeerFinder<BonjourPeer> implements ServiceLis
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
// TODO: This is not threadsafe - cancelling the discovery will make jmdns null, but it could happen after this check and before call to addServiceListener().
|
||||
if (jmdns != null) {
|
||||
Log.d(TAG, "Adding mDNS service listeners for " + HTTP_SERVICE_TYPE + " and " + HTTPS_SERVICE_TYPE);
|
||||
jmdns.addServiceListener(HTTP_SERVICE_TYPE, BonjourFinder.this);
|
||||
@ -80,13 +81,16 @@ public class BonjourFinder extends PeerFinder<BonjourPeer> implements ServiceLis
|
||||
}
|
||||
|
||||
private void listServices() {
|
||||
|
||||
final JmDNS mdns = jmdns;
|
||||
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
Log.d(TAG, "Explicitly querying for services, in addition to waiting for notifications.");
|
||||
addFDroidServices(jmdns.list(HTTP_SERVICE_TYPE));
|
||||
addFDroidServices(jmdns.list(HTTPS_SERVICE_TYPE));
|
||||
addFDroidServices(mdns.list(HTTP_SERVICE_TYPE));
|
||||
addFDroidServices(mdns.list(HTTPS_SERVICE_TYPE));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
@ -14,11 +15,15 @@ import org.fdroid.fdroid.net.bluetooth.BluetoothServer;
|
||||
public class BluetoothSwap extends SwapType {
|
||||
|
||||
private static final String TAG = "BluetoothBroadcastType";
|
||||
public final static String BLUETOOTH_NAME_TAG = "FDroid:";
|
||||
|
||||
@NonNull
|
||||
private final BluetoothAdapter adapter;
|
||||
|
||||
private final BluetoothServer server;
|
||||
@Nullable
|
||||
private BluetoothServer server;
|
||||
|
||||
private String deviceBluetoothName = null;
|
||||
|
||||
public static SwapType create(@NonNull Context context) {
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
@ -27,12 +32,11 @@ public class BluetoothSwap extends SwapType {
|
||||
} else {
|
||||
return new BluetoothSwap(context, adapter);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private BluetoothSwap(@NonNull Context context, @NonNull BluetoothAdapter adapter) {
|
||||
super(context);
|
||||
this.adapter = adapter;
|
||||
this.server = new BluetoothServer(context, context.getFilesDir());
|
||||
|
||||
context.registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
@ -53,16 +57,38 @@ public class BluetoothSwap extends SwapType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (server.isAlive()) {
|
||||
Log.d(TAG, "Attempting to start Bluetooth swap, but it appears to be running already.");
|
||||
return;
|
||||
public boolean isConnected() {
|
||||
return server != null && server.isRunning() && super.isConnected();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (server != null) {
|
||||
Log.d(TAG, "Attempting to start Bluetooth swap, but it appears to be running already. Will cancel it so it can be restarted.");
|
||||
server.close();
|
||||
server = null;
|
||||
}
|
||||
|
||||
server = new BluetoothServer(this, context.getFilesDir());
|
||||
|
||||
sendBroadcast(SwapService.EXTRA_STARTING);
|
||||
|
||||
//store the original bluetoothname, and update this one to be unique
|
||||
deviceBluetoothName = adapter.getName();
|
||||
|
||||
Log.d(TAG, "Prefixing Bluetooth adapter name with " + BLUETOOTH_NAME_TAG + " to make it identifiable as a swap device.");
|
||||
if (!deviceBluetoothName.startsWith(BLUETOOTH_NAME_TAG))
|
||||
adapter.setName(BLUETOOTH_NAME_TAG + deviceBluetoothName);
|
||||
|
||||
if (!adapter.getName().startsWith(BLUETOOTH_NAME_TAG)) {
|
||||
Log.e(TAG, "Couldn't change the name of the Bluetooth adapter, it will not get recognized by other swap clients.");
|
||||
// TODO: Should we bail here?
|
||||
}
|
||||
|
||||
if (!adapter.isEnabled()) {
|
||||
Log.d(TAG, "Bluetooth adapter is disabled, attempting to enable.");
|
||||
if (!adapter.enable()) {
|
||||
Log.d(TAG, "Could not enable Bluetooth adapter, so bailing out of Bluetooth swap.");
|
||||
setConnected(false);
|
||||
return;
|
||||
}
|
||||
@ -79,7 +105,7 @@ public class BluetoothSwap extends SwapType {
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
if (server.isAlive()) {
|
||||
if (server != null && server.isAlive()) {
|
||||
server.close();
|
||||
setConnected(false);
|
||||
} else {
|
||||
@ -87,6 +113,11 @@ public class BluetoothSwap extends SwapType {
|
||||
}
|
||||
}
|
||||
|
||||
protected void onStopped() {
|
||||
Log.d(TAG, "Resetting bluetooth device name to " + deviceBluetoothName + " after swapping.");
|
||||
adapter.setName(deviceBluetoothName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBroadcastAction() {
|
||||
return SwapService.BLUETOOTH_STATE_CHANGE;
|
||||
|
@ -2,6 +2,7 @@ package org.fdroid.fdroid.localrepo.type;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
@ -38,10 +39,13 @@ public abstract class SwapType {
|
||||
sendBroadcast(SwapService.EXTRA_STARTED);
|
||||
} else {
|
||||
isConnected = false;
|
||||
onStopped();
|
||||
sendBroadcast(SwapService.EXTRA_STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onStopped() {}
|
||||
|
||||
/**
|
||||
* Sends either a {@link org.fdroid.fdroid.localrepo.SwapService#EXTRA_STARTING},
|
||||
* {@link org.fdroid.fdroid.localrepo.SwapService#EXTRA_STARTED} or
|
||||
@ -55,7 +59,7 @@ public abstract class SwapType {
|
||||
}
|
||||
}
|
||||
|
||||
public final boolean isConnected() {
|
||||
public boolean isConnected() {
|
||||
return isConnected;
|
||||
}
|
||||
|
||||
@ -84,4 +88,15 @@ public abstract class SwapType {
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
public void stopInBackground() {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
stop();
|
||||
return null;
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -60,19 +60,24 @@ public class WifiSwap extends SwapType {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
Log.i(TAG, "we've been asked to stop the webserver: " + msg.obj);
|
||||
setConnected(false);
|
||||
localHttpd.stop();
|
||||
}
|
||||
};
|
||||
try {
|
||||
Log.d(TAG, "Starting swap webserver...");
|
||||
sendBroadcast(SwapService.EXTRA_STARTING);
|
||||
localHttpd.start();
|
||||
setConnected(true);
|
||||
Log.d(TAG, "Swap webserver started.");
|
||||
} catch (BindException e) {
|
||||
int prev = FDroidApp.port;
|
||||
FDroidApp.port = FDroidApp.port + new Random().nextInt(1111);
|
||||
setConnected(false);
|
||||
Log.w(TAG, "port " + prev + " occupied, trying on " + FDroidApp.port + "!");
|
||||
context.startService(new Intent(context, WifiStateChangeService.class));
|
||||
} catch (IOException e) {
|
||||
setConnected(false);
|
||||
Log.e(TAG, "Could not start local repo HTTP server: " + e);
|
||||
Log.e(TAG, Log.getStackTraceString(e));
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.fdroid.fdroid.net;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import org.apache.commons.io.input.BoundedInputStream;
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothClient;
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothConnection;
|
||||
import org.fdroid.fdroid.net.bluetooth.FileDetails;
|
||||
import org.fdroid.fdroid.net.bluetooth.httpish.Request;
|
||||
@ -23,21 +24,15 @@ public class BluetoothDownloader extends Downloader {
|
||||
private FileDetails fileDetails;
|
||||
private final String sourcePath;
|
||||
|
||||
public BluetoothDownloader(BluetoothConnection connection, String sourcePath, Context ctx) throws IOException {
|
||||
public BluetoothDownloader(String macAddress, String sourcePath, Context ctx) throws IOException {
|
||||
super(ctx);
|
||||
this.connection = connection;
|
||||
this.connection = new BluetoothClient(macAddress).openConnection();
|
||||
this.sourcePath = sourcePath;
|
||||
}
|
||||
|
||||
public BluetoothDownloader(BluetoothConnection connection, String sourcePath, File destFile) throws FileNotFoundException, MalformedURLException {
|
||||
public BluetoothDownloader(String macAddress, String sourcePath, File destFile) throws IOException {
|
||||
super(destFile);
|
||||
this.connection = connection;
|
||||
this.sourcePath = sourcePath;
|
||||
}
|
||||
|
||||
public BluetoothDownloader(BluetoothConnection connection, String sourcePath, OutputStream output) throws MalformedURLException {
|
||||
super(output);
|
||||
this.connection = connection;
|
||||
this.connection = new BluetoothClient(macAddress).openConnection();
|
||||
this.sourcePath = sourcePath;
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,8 @@ public class DownloaderFactory {
|
||||
public static Downloader create(String url, Context context) throws IOException {
|
||||
Uri uri = Uri.parse(url);
|
||||
if (isBluetoothAddress(uri)) {
|
||||
// TODO: Don't pass null!!!
|
||||
return new BluetoothDownloader(null, uri.getPath(), context);
|
||||
String macAddress = uri.getHost().replace("-", ":");
|
||||
return new BluetoothDownloader(macAddress, uri.getPath(), context);
|
||||
} else if (isOnionAddress(url)) {
|
||||
return new TorHttpDownloader(url, context);
|
||||
} else {
|
||||
@ -23,8 +23,8 @@ public class DownloaderFactory {
|
||||
public static Downloader create(String url, File destFile) throws IOException {
|
||||
Uri uri = Uri.parse(url);
|
||||
if (isBluetoothAddress(uri)) {
|
||||
// TODO: Don't pass null!!!
|
||||
return new BluetoothDownloader(null, uri.getPath(), destFile);
|
||||
String macAddress = uri.getHost().replace("-", ":");
|
||||
return new BluetoothDownloader(macAddress, uri.getPath(), destFile);
|
||||
} else if (isOnionAddress(url)) {
|
||||
return new TorHttpDownloader(url, destFile);
|
||||
} else {
|
||||
|
@ -1,5 +1,6 @@
|
||||
package org.fdroid.fdroid.net.bluetooth;
|
||||
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
|
||||
@ -10,12 +11,16 @@ public class BluetoothClient {
|
||||
@SuppressWarnings("unused")
|
||||
private static final String TAG = "BluetoothClient";
|
||||
|
||||
private BluetoothDevice device;
|
||||
private final BluetoothDevice device;
|
||||
|
||||
public BluetoothClient(BluetoothDevice device) {
|
||||
this.device = device;
|
||||
}
|
||||
|
||||
public BluetoothClient(String macAddress) {
|
||||
device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(macAddress);
|
||||
}
|
||||
|
||||
public BluetoothConnection openConnection() throws IOException {
|
||||
BluetoothSocket socket = device.createInsecureRfcommSocketToServiceRecord(BluetoothConstants.fdroidUuid());
|
||||
BluetoothConnection connection = new BluetoothConnection(socket);
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.fdroid.fdroid.net.bluetooth;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
@ -3,25 +3,19 @@ package org.fdroid.fdroid.net.bluetooth;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothServerSocket;
|
||||
import android.bluetooth.BluetoothSocket;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import org.fdroid.fdroid.FDroidApp;
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.net.HttpDownloader;
|
||||
import org.fdroid.fdroid.localrepo.type.BluetoothSwap;
|
||||
import org.fdroid.fdroid.net.bluetooth.httpish.Request;
|
||||
import org.fdroid.fdroid.net.bluetooth.httpish.Response;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -37,23 +31,23 @@ public class BluetoothServer extends Thread {
|
||||
private static final String TAG = "BluetoothServer";
|
||||
|
||||
private BluetoothServerSocket serverSocket;
|
||||
private List<Connection> clients = new ArrayList<>();
|
||||
private List<ClientConnection> clients = new ArrayList<>();
|
||||
|
||||
private final Context context;
|
||||
|
||||
private String deviceBluetoothName = null;
|
||||
public final static String BLUETOOTH_NAME_TAG = "FDroid:";
|
||||
private final File webRoot;
|
||||
private final BluetoothSwap swap;
|
||||
private boolean isRunning = false;
|
||||
|
||||
public BluetoothServer(Context context, File webRoot) {
|
||||
this.context = context.getApplicationContext();
|
||||
public BluetoothServer(BluetoothSwap swap, File webRoot) {
|
||||
this.webRoot = webRoot;
|
||||
this.swap = swap;
|
||||
}
|
||||
|
||||
public boolean isRunning() { return isRunning; }
|
||||
|
||||
public void close() {
|
||||
|
||||
for (Connection connection : clients) {
|
||||
connection.interrupt();
|
||||
for (ClientConnection clientConnection : clients) {
|
||||
clientConnection.interrupt();
|
||||
}
|
||||
|
||||
interrupt();
|
||||
@ -61,61 +55,53 @@ public class BluetoothServer extends Thread {
|
||||
if (serverSocket != null) {
|
||||
Utils.closeQuietly(serverSocket);
|
||||
}
|
||||
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
adapter.setName(deviceBluetoothName.replaceAll("/^" + BLUETOOTH_NAME_TAG + "/",""));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
isRunning = true;
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
|
||||
//store the original bluetoothname, and update this one to be unique
|
||||
deviceBluetoothName = adapter.getName();
|
||||
|
||||
if (!deviceBluetoothName.startsWith(BLUETOOTH_NAME_TAG))
|
||||
adapter.setName(BLUETOOTH_NAME_TAG + deviceBluetoothName);
|
||||
|
||||
|
||||
try {
|
||||
serverSocket = adapter.listenUsingInsecureRfcommWithServiceRecord("FDroid App Swap", BluetoothConstants.fdroidUuid());
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error starting Bluetooth server socket, will stop the server now - " + e.getMessage());
|
||||
Log.e(TAG, "Error starting Bluetooth server socket, will stop the server now: " + e.getMessage());
|
||||
swap.stop();
|
||||
isRunning = false;
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (isInterrupted()) {
|
||||
Log.d(TAG, "Server stopped so will terminate loop looking for client connections.");
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
BluetoothSocket clientSocket = serverSocket.accept();
|
||||
if (clientSocket != null && !isInterrupted()) {
|
||||
Connection client = new Connection(context, clientSocket, webRoot);
|
||||
client.start();
|
||||
clients.add(client);
|
||||
} else {
|
||||
if (clientSocket != null) {
|
||||
if (!isInterrupted()) {
|
||||
Log.d(TAG, "Server stopped after socket accepted from client, but before initiating connection.");
|
||||
break;
|
||||
}
|
||||
ClientConnection client = new ClientConnection(clientSocket, webRoot);
|
||||
client.start();
|
||||
clients.add(client);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error receiving client connection over Bluetooth server socket, will continue listening for other clients - " + e.getMessage());
|
||||
Log.e(TAG, "Error receiving client connection over Bluetooth server socket, will continue listening for other clients: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
private static class Connection extends Thread {
|
||||
private static class ClientConnection extends Thread {
|
||||
|
||||
private final Context context;
|
||||
private final BluetoothSocket socket;
|
||||
private final File webRoot;
|
||||
|
||||
public Connection(Context context, BluetoothSocket socket, File webRoot) {
|
||||
this.context = context.getApplicationContext();
|
||||
public ClientConnection(BluetoothSocket socket, File webRoot) {
|
||||
this.socket = socket;
|
||||
this.webRoot = webRoot;
|
||||
}
|
||||
@ -142,13 +128,11 @@ public class BluetoothServer extends Thread {
|
||||
handleRequest(incomingRequest).send(connection);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error receiving incoming connection over bluetooth - " + e.getMessage());
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (isInterrupted())
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -160,7 +144,6 @@ public class BluetoothServer extends Thread {
|
||||
Response.Builder builder = null;
|
||||
|
||||
try {
|
||||
// HttpDownloader downloader = new HttpDownloader("http://127.0.0.1:" + ( FDroidApp.port) + "/" + request.getPath(), context);
|
||||
int statusCode = 404;
|
||||
int totalSize = -1;
|
||||
|
||||
|
@ -1,376 +0,0 @@
|
||||
package org.fdroid.fdroid.views.swap;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.MenuItemCompat;
|
||||
import android.support.v4.widget.ContentLoadingProgressBar;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.fdroid.fdroid.R;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
import org.fdroid.fdroid.net.BluetoothDownloader;
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothClient;
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothConnection;
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothServer;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
public class BluetoothDeviceListView extends ListView implements
|
||||
SwapWorkflowActivity.InnerView,
|
||||
ListView.OnItemClickListener {
|
||||
|
||||
private static final String TAG = "BluetoothDeviceListView";
|
||||
|
||||
private Adapter adapter = null;
|
||||
|
||||
private MenuItem scanMenuItem;
|
||||
private MenuItem cancelMenuItem;
|
||||
|
||||
private boolean firstScan = true;
|
||||
|
||||
public BluetoothDeviceListView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public BluetoothDeviceListView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public BluetoothDeviceListView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public BluetoothDeviceListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean buildMenu(Menu menu, @NonNull MenuInflater menuInflater) {
|
||||
menuInflater.inflate(R.menu.swap_scan, menu);
|
||||
|
||||
final int flags = MenuItemCompat.SHOW_AS_ACTION_ALWAYS | MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT;
|
||||
|
||||
scanMenuItem = menu.findItem(R.id.action_scan);
|
||||
scanMenuItem.setVisible(true);
|
||||
MenuItemCompat.setShowAsAction(scanMenuItem, flags);
|
||||
|
||||
scanMenuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
initiateBluetoothScan();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
cancelMenuItem = menu.findItem(R.id.action_cancel);
|
||||
cancelMenuItem.setVisible(false);
|
||||
MenuItemCompat.setShowAsAction(cancelMenuItem, flags);
|
||||
|
||||
cancelMenuItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
cancelBluetoothScan();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStep() {
|
||||
return SwapService.STEP_BLUETOOTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
return SwapService.STEP_JOIN_WIFI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getToolbarColour() {
|
||||
return R.color.swap_blue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolbarTitle() {
|
||||
return getContext().getString(R.string.swap_use_bluetooth);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
adapter = new Adapter(
|
||||
getContext(),
|
||||
R.layout.select_local_apps_list_item
|
||||
);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
View headerView = inflater.inflate(R.layout.swap_bluetooth_header, this, false);
|
||||
addHeaderView(headerView);
|
||||
|
||||
setAdapter(adapter);
|
||||
setOnItemClickListener(this);
|
||||
|
||||
final BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
final TextView deviceName = (TextView) headerView.findViewById(R.id.device_name);
|
||||
deviceName.setText(bluetooth.getName());
|
||||
|
||||
final TextView address = (TextView) headerView.findViewById(R.id.device_address);
|
||||
address.setText(bluetooth.getAddress());
|
||||
|
||||
initiateBluetoothScan();
|
||||
|
||||
// populateBondedDevices();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void cancelBluetoothScan() {
|
||||
|
||||
Log.d(TAG, "Cancelling bluetooth scan.");
|
||||
|
||||
cancelMenuItem.setVisible(false);
|
||||
scanMenuItem.setVisible(true);
|
||||
|
||||
final BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
|
||||
bluetooth.cancelDiscovery();
|
||||
|
||||
getLoadingIndicator().hide();
|
||||
|
||||
}
|
||||
|
||||
private ContentLoadingProgressBar getLoadingIndicator() {
|
||||
return ((ContentLoadingProgressBar)findViewById(R.id.loading_indicator));
|
||||
}
|
||||
|
||||
private void initiateBluetoothScan()
|
||||
{
|
||||
Log.d(TAG, "Starting bluetooth scan...");
|
||||
|
||||
if (cancelMenuItem != null) {
|
||||
cancelMenuItem.setVisible(true);
|
||||
scanMenuItem.setVisible(false);
|
||||
}
|
||||
|
||||
final ContentLoadingProgressBar loadingBar = getLoadingIndicator();
|
||||
|
||||
loadingBar.show();
|
||||
|
||||
final BluetoothAdapter bluetooth = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
if (firstScan) {
|
||||
final BroadcastReceiver deviceFoundReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
||||
if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
|
||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
Log.d(TAG, "Found bluetooth device: " + device.toString());
|
||||
|
||||
if (device != null && device.getName() != null)
|
||||
if (device.getName().contains(BluetoothServer.BLUETOOTH_NAME_TAG)) {
|
||||
boolean exists = false;
|
||||
for (int i = 0; i < adapter.getCount(); i++) {
|
||||
if (adapter.getItem(i).getAddress().equals(device.getAddress())) {
|
||||
exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
adapter.add(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final BroadcastReceiver scanCompleteReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "Scan complete: " + intent.getAction());
|
||||
loadingBar.hide();
|
||||
cancelMenuItem.setVisible(false);
|
||||
scanMenuItem.setVisible(true);
|
||||
}
|
||||
};
|
||||
|
||||
getContext().registerReceiver(deviceFoundReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
|
||||
getContext().registerReceiver(scanCompleteReceiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED));
|
||||
|
||||
firstScan = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bluetooth.isDiscovering())
|
||||
{
|
||||
bluetooth.cancelDiscovery();
|
||||
}
|
||||
}
|
||||
|
||||
if (!bluetooth.startDiscovery()) {
|
||||
// TODO: Discovery did not start for some reason :(
|
||||
Log.e(TAG, "Could not start bluetooth discovery, but am not sure why :(");
|
||||
Toast.makeText(getContext(),"There was a problem looking for Bluetooth devices",Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void populateBondedDevices()
|
||||
{
|
||||
for (BluetoothDevice device : BluetoothAdapter.getDefaultAdapter().getBondedDevices()) {
|
||||
adapter.add(device);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
|
||||
// "position" includes the header view, so ignore that.
|
||||
if (position == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
BluetoothDevice device = adapter.getItem(position - 1);
|
||||
|
||||
// TODO: I think that I can connect regardless of the bond state.
|
||||
// It sounds like when I attempt to connect to a non-bonded peer, then
|
||||
// Android initiates the pairing dialog on our behalf.
|
||||
|
||||
BluetoothClient client = new BluetoothClient(device);
|
||||
|
||||
try {
|
||||
Log.d(TAG, "Testing bluetooth connection (opening connection first).");
|
||||
BluetoothConnection connection = client.openConnection();
|
||||
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream(4096);
|
||||
BluetoothDownloader downloader = new BluetoothDownloader(connection, "/", stream);
|
||||
downloader.downloadUninterrupted();
|
||||
String result = stream.toString();
|
||||
Log.d(TAG, "Download complete.");
|
||||
Log.d(TAG, result);
|
||||
|
||||
Log.d(TAG, "Downloading again...");
|
||||
downloader = new BluetoothDownloader(connection, "/fdroid/repo/index.xml", stream);
|
||||
downloader.downloadUninterrupted();
|
||||
result = stream.toString();
|
||||
Log.d(TAG, "Download complete.");
|
||||
Log.d(TAG, result);
|
||||
|
||||
/*Log.d(TAG, "Creating HEAD request for resource at \"/\"...");
|
||||
Request head = Request.createGET("/", connection);
|
||||
Log.d(TAG, "Sending request...");
|
||||
Response response = head.send();
|
||||
Log.d(TAG, "Response from bluetooth: " + response.getStatusCode());
|
||||
String contents = response.readContents();
|
||||
Log.d(TAG, contents);*/
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error: " + e.getMessage());
|
||||
}
|
||||
|
||||
/*if (device.getBondState() == BluetoothDevice.BOND_NONE) {
|
||||
// attempt to bond
|
||||
|
||||
} else if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
|
||||
// wait for bonding to finish
|
||||
|
||||
} else if (device.getBondState() == BluetoothDevice.BOND_BONDED) {
|
||||
// connect
|
||||
BluetoothClient client = new BluetoothClient(device);
|
||||
}*/
|
||||
}
|
||||
|
||||
private class Adapter extends ArrayAdapter<BluetoothDevice> {
|
||||
|
||||
public Adapter(Context context, int resource) {
|
||||
super(context, resource);
|
||||
}
|
||||
|
||||
public Adapter(Context context, int resource, int textViewResourceId) {
|
||||
super(context, resource, textViewResourceId);
|
||||
}
|
||||
|
||||
public Adapter(Context context, int resource, BluetoothDevice[] objects) {
|
||||
super(context, resource, objects);
|
||||
}
|
||||
|
||||
public Adapter(Context context, int resource, int textViewResourceId, BluetoothDevice[] objects) {
|
||||
super(context, resource, textViewResourceId, objects);
|
||||
}
|
||||
|
||||
public Adapter(Context context, int resource, List<BluetoothDevice> objects) {
|
||||
super(context, resource, objects);
|
||||
}
|
||||
|
||||
public Adapter(Context context, int resource, int textViewResourceId, List<BluetoothDevice> objects) {
|
||||
super(context, resource, textViewResourceId, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
View view;
|
||||
if (convertView == null) {
|
||||
LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
view = inflater.inflate(R.layout.simple_list_item_3, null);
|
||||
} else {
|
||||
view = convertView;
|
||||
}
|
||||
|
||||
BluetoothDevice device = getItem(position);
|
||||
TextView nameView = (TextView)view.findViewById(android.R.id.text1);
|
||||
TextView addressView = (TextView)view.findViewById(android.R.id.text2);
|
||||
//TextView descriptionView = (TextView)view.findViewById(R.id.text3);
|
||||
|
||||
nameView.setText(device.getName() == null ? getContext().getString(R.string.unknown) : device.getName());
|
||||
addressView.setText(device.getAddress());
|
||||
//descriptionView.setText(bondStateToLabel(device.getBondState()));
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private String bondStateToLabel(int deviceBondState)
|
||||
{
|
||||
if (deviceBondState == BluetoothDevice.BOND_BONDED) {
|
||||
// TODO: Is the term "Bonded device" common parlance among phone users?
|
||||
// It sounds a bit technical to me, maybe something more lay like "Previously connected".
|
||||
// Although it is technically not as accurate, it would make sense to more people...
|
||||
return getContext().getString(R.string.swap_bluetooth_bonded_device);
|
||||
} else if (deviceBondState == BluetoothDevice.BOND_BONDING) {
|
||||
return getContext().getString(R.string.swap_bluetooth_bonding_device);
|
||||
} else {
|
||||
// TODO: Might be a little bit harsh, makes it sound more malicious than it should.
|
||||
return getContext().getString(R.string.swap_bluetooth_unknown_device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -124,7 +124,7 @@ public class SelectAppsView extends ListView implements
|
||||
|
||||
@Override
|
||||
public int getPreviousStep() {
|
||||
return getState().isConnectingWithPeer() ? SwapService.STEP_JOIN_WIFI : SwapService.STEP_INTRO;
|
||||
return getState().isConnectingWithPeer() ? SwapService.STEP_INTRO : SwapService.STEP_JOIN_WIFI;
|
||||
}
|
||||
|
||||
@ColorRes
|
||||
|
@ -39,9 +39,9 @@ import org.fdroid.fdroid.data.NewRepoConfig;
|
||||
import org.fdroid.fdroid.localrepo.LocalRepoManager;
|
||||
import org.fdroid.fdroid.localrepo.SwapService;
|
||||
import org.fdroid.fdroid.localrepo.peers.Peer;
|
||||
import org.fdroid.fdroid.net.bluetooth.BluetoothServer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
@ -105,11 +105,12 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
private final ServiceConnection serviceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName className, IBinder binder) {
|
||||
Log.d(TAG, "Swap service connected, enabling SwapManager to communicate with SwapService.");
|
||||
Log.d(TAG, "Swap service connected. Will hold onto it so we can talk to it regularly.");
|
||||
service = ((SwapService.Binder)binder).getService();
|
||||
showRelevantView();
|
||||
}
|
||||
|
||||
// TODO: What causes this? Do we need to stop swapping explicitly when this is invoked?
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName className) {
|
||||
Log.d(TAG, "Swap service disconnected");
|
||||
@ -133,6 +134,9 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (currentView.getStep() == SwapService.STEP_INTRO) {
|
||||
if (service != null) {
|
||||
service.disableAllSwapping();
|
||||
}
|
||||
finish();
|
||||
} else {
|
||||
int nextStep = currentView.getPreviousStep();
|
||||
@ -235,6 +239,10 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
case SwapService.STEP_SUCCESS:
|
||||
showSwapConnected();
|
||||
break;
|
||||
case SwapService.STEP_CONNECTING:
|
||||
// TODO: Properly decide what to do here...
|
||||
inflateInnerView(R.layout.swap_blank);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -287,6 +295,10 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void showIntro() {
|
||||
// If we were previously swapping with a specific client, forget that we were doing that,
|
||||
// as we are starting over now.
|
||||
getService().swapWith(null);
|
||||
|
||||
if (!getService().isEnabled()) {
|
||||
prepareInitialRepo();
|
||||
}
|
||||
@ -303,7 +315,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
public void sendFDroid() {
|
||||
// TODO: What is availble here? Currently we support Bluetooth (see main menu in F-Droid)
|
||||
// TODO: What is available here? Currently we support Bluetooth (see main menu in F-Droid)
|
||||
// and Android Beam (try touching two devices together when in the app details view).
|
||||
}
|
||||
|
||||
@ -314,8 +326,8 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
if (updateSwappableAppsTask == null && !hasPreparedLocalRepo) {
|
||||
updateSwappableAppsTask = new PrepareFullSwapRepo(getService().getAppsToSwap());
|
||||
updateSwappableAppsTask.execute();
|
||||
} else if (!attemptToShowNfc()) {
|
||||
showWifiQr();
|
||||
} else {
|
||||
onLocalRepoPrepared();
|
||||
}
|
||||
}
|
||||
|
||||
@ -355,10 +367,6 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
inflateInnerView(R.layout.swap_join_wifi);
|
||||
}
|
||||
|
||||
private void showBluetoothDeviceList() {
|
||||
inflateInnerView(R.layout.swap_bluetooth_devices);
|
||||
}
|
||||
|
||||
public void showWifiQr() {
|
||||
inflateInnerView(R.layout.swap_wifi_qr);
|
||||
}
|
||||
@ -384,6 +392,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
public void swapWith(Peer peer) {
|
||||
getService().stopScanningForPeers();
|
||||
getService().swapWith(peer);
|
||||
showSelectApps();
|
||||
}
|
||||
@ -443,7 +452,7 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
/**
|
||||
* The process for setting up bluetooth is as follows:
|
||||
* * Assume we have bluetooth available (otherwise the button which allowed us to start
|
||||
* the bluetooth process should not have been available). TODO: Remove button if bluetooth unavailable.
|
||||
* the bluetooth process should not have been available).
|
||||
* * Ask user to enable (if not enabled yet).
|
||||
* * Start bluetooth server socket.
|
||||
* * Enable bluetooth discoverability, so that people can connect to our server socket.
|
||||
@ -609,36 +618,53 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to try and make sense of what the swap workflow is currently doing.
|
||||
* The more technologies are involved in the process (e.g. Bluetooth/Wifi/NFC/etc)
|
||||
* the harder it becomes to reason about and debug the whole thing. Thus,this class
|
||||
* will periodically dump the state to logcat so that it is easier to see when certain
|
||||
* protocols are enabled/disabled.
|
||||
*
|
||||
* To view only this output from logcat:
|
||||
*
|
||||
* adb logcat | grep 'Swap Status'
|
||||
*
|
||||
* To exclude this output from logcat (it is very noisy):
|
||||
*
|
||||
* adb logcat | grep -v 'Swap Status'
|
||||
*
|
||||
*/
|
||||
class SwapDebug {
|
||||
|
||||
private StringBuilder status = new StringBuilder("\n");
|
||||
|
||||
public void logStatus() {
|
||||
append("service = " + service);
|
||||
if (service != null) {
|
||||
append("Swap Services:");
|
||||
append(" service.getBluetoothSwap() = " + service.getBluetoothSwap());
|
||||
append(" service.getBluetoothSwap().isConnected() = " + service.getBluetoothSwap().isConnected());
|
||||
append(" service.getWifiSwap() = " + service.getWifiSwap());
|
||||
append(" service.getWifiSwap().isConnected() = " + service.getWifiSwap().isConnected());
|
||||
append(" service.getWifiSwap().getBonjour() = " + service.getWifiSwap().getBonjour());
|
||||
append(" service.getWifiSwap().getBonjour().isConnected() = " + service.getWifiSwap().getBonjour().isConnected());
|
||||
append("Discovering Services:");
|
||||
String message = "";
|
||||
if (service == null) {
|
||||
message = "No swap service";
|
||||
} else {
|
||||
{
|
||||
String bluetooth = service.getBluetoothSwap().isConnected() ? "Yes" : " No";
|
||||
String wifi = service.getWifiSwap().isConnected() ? "Yes" : " No";
|
||||
String mdns = service.getWifiSwap().getBonjour().isConnected() ? "Yes" : " No";
|
||||
message += "Broadcast { BT: " + bluetooth + ", WiFi: " + wifi + ", mDNS: " + mdns + "}, ";
|
||||
}
|
||||
|
||||
{
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
String bluetooth = "N/A";
|
||||
if (adapter != null) {
|
||||
|
||||
Map<Integer, String> scanModes = new HashMap<>(3);
|
||||
scanModes.put(BluetoothAdapter.SCAN_MODE_CONNECTABLE, "SCAN_MODE_CONNECTABLE");
|
||||
scanModes.put(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, "SCAN_MODE_CONNECTABLE_DISCOVERABLE");
|
||||
scanModes.put(BluetoothAdapter.SCAN_MODE_NONE, "SCAN_MODE_NONE");
|
||||
scanModes.put(BluetoothAdapter.SCAN_MODE_CONNECTABLE, "CONNECTABLE");
|
||||
scanModes.put(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, "CONNECTABLE_DISCOVERABLE");
|
||||
scanModes.put(BluetoothAdapter.SCAN_MODE_NONE, "NONE");
|
||||
bluetooth = "\"" + adapter.getName() + "\" - " + scanModes.get(adapter.getScanMode());
|
||||
}
|
||||
|
||||
append(" Bluetooth.isEnabled() = " + adapter.isEnabled());
|
||||
append(" Bluetooth.isDiscovering() = " + adapter.isDiscovering());
|
||||
append(" Bluetooth.getScanMode() = " + scanModes.get(adapter.getScanMode()));
|
||||
String wifi = service.getBonjourFinder().isScanning() ? "Yes" : " No";
|
||||
message += "Discover { BT: " + bluetooth + ", WiFi: " + wifi + "}";
|
||||
}
|
||||
}
|
||||
Log.d("SwapStatus", status.toString());
|
||||
|
||||
Log.d("Swap Status", new Date().toLocaleString() + " " + message);
|
||||
|
||||
new Timer().schedule(new TimerTask() {
|
||||
@Override
|
||||
@ -646,13 +672,9 @@ public class SwapWorkflowActivity extends AppCompatActivity {
|
||||
new SwapDebug().logStatus();
|
||||
}
|
||||
},
|
||||
2000
|
||||
1000
|
||||
);
|
||||
}
|
||||
|
||||
private void append(String line) {
|
||||
status.append(" ").append(line).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user