package org.fdroid.fdroid.localrepo.type; import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; 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.Utils; import org.fdroid.fdroid.localrepo.SwapService; import org.fdroid.fdroid.net.bluetooth.BluetoothServer; public final class BluetoothSwap extends SwapType { private static final String TAG = "BluetoothSwap"; public static final String BLUETOOTH_NAME_TAG = "FDroid:"; private static BluetoothSwap mInstance; @NonNull private final BluetoothAdapter adapter; private boolean isDiscoverable; @Nullable private BluetoothServer server; private String deviceBluetoothName; public static SwapType create(@NonNull Context context) { BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter == null) { return new NoBluetoothType(context); } if (mInstance == null) { mInstance = new BluetoothSwap(context, adapter); } return mInstance; } private BluetoothSwap(@NonNull Context context, @NonNull BluetoothAdapter adapter) { super(context); this.adapter = adapter; } @Override public boolean isDiscoverable() { return isDiscoverable; } @Override public boolean isConnected() { return server != null && server.isRunning() && super.isConnected(); } @Override public synchronized void start() { if (isConnected()) { return; } BroadcastReceiver receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE, -1)) { case BluetoothAdapter.SCAN_MODE_NONE: setConnected(false); break; case BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE: isDiscoverable = true; if (server != null && server.isRunning()) { setConnected(true); } break; // Only other is BluetoothAdapter.SCAN_MODE_CONNECTABLE. For now don't handle that. } } }; context.registerReceiver(receiver, new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED)); /* if (server != null) { Utils.debugLog(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; }*/ if (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(); /* Utils.debugLog(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()) { Utils.debugLog(TAG, "Bluetooth adapter is disabled, attempting to enable."); if (!adapter.enable()) { Utils.debugLog(TAG, "Could not enable Bluetooth adapter, so bailing out of Bluetooth swap."); setConnected(false); return; } } if (adapter.isEnabled()) { setConnected(true); } else { Log.i(TAG, "Didn't start Bluetooth swapping server, because Bluetooth is disabled and couldn't be enabled."); setConnected(false); } } /** * Don't try to start BT in the background. you can only start/stop a BT server once, else new connections don't work. */ @Override public void stopInBackground() { stop(); } @Override public void stop() { if (server != null && server.isAlive()) { server.close(); setConnected(false); /* if (receiver != null) { context.unregisterReceiver(receiver); receiver = null; } */ } else { Log.i(TAG, "Attempting to stop Bluetooth swap, but it is not currently running."); } } protected void onStopped() { Utils.debugLog(TAG, "Resetting bluetooth device name to " + deviceBluetoothName + " after swapping."); adapter.setName(deviceBluetoothName); } @Override public String getBroadcastAction() { return SwapService.BLUETOOTH_STATE_CHANGE; } private static class NoBluetoothType extends SwapType { NoBluetoothType(@NonNull Context context) { super(context); } @Override public void start() { } @Override public void stop() { } @Override protected String getBroadcastAction() { return null; } } }