package org.fdroid.fdroid.localrepo.peers;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothClass;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.util.Log;
import org.fdroid.fdroid.Utils;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;
final class BluetoothFinder extends PeerFinder {
public static Observable<Peer> createBluetoothObservable(final Context context) {
return Observable.create(new Observable.OnSubscribe<Peer>() {
@Override
public void call(Subscriber<? super Peer> subscriber) {
final BluetoothFinder finder = new BluetoothFinder(context, subscriber);
subscriber.add(Subscriptions.create(new Action0() {
@Override
public void call() {
finder.cancel();
}
}));
finder.scan();
}
});
}
private static final String TAG = "BluetoothFinder";
private final BluetoothAdapter adapter;
private BluetoothFinder(Context context, Subscriber<? super Peer> subscriber) {
super(context, subscriber);
adapter = BluetoothAdapter.getDefaultAdapter();
}
private BroadcastReceiver deviceFoundReceiver;
private BroadcastReceiver scanCompleteReceiver;
private void scan() {
if (adapter == null) {
Log.i(TAG, "Not scanning for bluetooth peers to swap with, couldn't find a bluetooth adapter on this device.");
return;
}
isScanning = true;
if (deviceFoundReceiver == null) {
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);
onDeviceFound(device);
}
}
};
context.registerReceiver(deviceFoundReceiver, new IntentFilter(BluetoothDevice.ACTION_FOUND));
}
if (scanCompleteReceiver == null) {
scanCompleteReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (isScanning) {
Utils.debugLog(TAG, "Scan complete, but we haven't been asked to stop scanning yet, so will restart scan.");
startDiscovery();
}
}
};
// TODO: Unregister this receiver at the appropriate time.
context.registerReceiver(scanCompleteReceiver, new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED));
}
startDiscovery();
}
private void startDiscovery() {
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? We could
// cancelDiscovery(), but then it will probably prompt the user again.
Utils.debugLog(TAG, "Requested bluetooth scan when already scanning, so will ignore request.");
return;
}
if (!adapter.startDiscovery()) {
Log.e(TAG, "Couldn't start bluetooth scanning.");
}
}
private void cancel() {
if (adapter != null) {
Utils.debugLog(TAG, "Stopping bluetooth discovery.");
adapter.cancelDiscovery();
}
isScanning = false;
}
private void onDeviceFound(BluetoothDevice device) {
if (device != null && device.getName() != null &&
(device.getBluetoothClass().getDeviceClass() == BluetoothClass.Device.COMPUTER_HANDHELD_PC_PDA ||
device.getBluetoothClass().getDeviceClass() == BluetoothClass.Device.COMPUTER_PALM_SIZE_PC_PDA ||
device.getBluetoothClass().getDeviceClass() == BluetoothClass.Device.PHONE_SMART)) {
subscriber.onNext(new BluetoothPeer(device));
}
}
}