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)); } } }