package nodomain.freeyourgadget.gadgetbridge.devices; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.support.v4.content.LocalBroadcastManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper; /** * Provides access to the list of devices managed by Gadgetbridge. * Changes to the devices (e.g. connection state) or the list of devices * are broadcasted via #ACTION_DEVICE_CHANGED */ public class DeviceManager { private static final Logger LOG = LoggerFactory.getLogger(DeviceManager.class); /** * Intent action to notify that the list of devices has changed. */ public static final String ACTION_DEVICES_CHANGED = "nodomain.freeyourgadget.gadgetbridge.devices.devicemanager.action.devices_changed"; /** * Intent action to notify this class that the list of devices shall be refreshed. */ public static final String ACTION_REFRESH_DEVICELIST = "nodomain.freeyourgadget.gadgetbridge.devices.devicemanager.action.set_version"; private final Context context; /** * This list is final, it will never be recreated. Only its contents change. * This allows direct access to the list from ListAdapters. */ private final List deviceList = new ArrayList<>(); private GBDevice selectedDevice = null; private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); switch (action) { case ACTION_REFRESH_DEVICELIST: case BluetoothDevice.ACTION_BOND_STATE_CHANGED: refreshPairedDevices(); break; case GBDevice.ACTION_DEVICE_CHANGED: GBDevice dev = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE); if (dev.getAddress() != null) { int index = deviceList.indexOf(dev); // search by address if (index >= 0) { deviceList.set(index, dev); } else { deviceList.add(dev); } } updateSelectedDevice(dev); refreshPairedDevices(); break; } } }; public DeviceManager(Context context) { this.context = context; IntentFilter filterLocal = new IntentFilter(); filterLocal.addAction(DeviceManager.ACTION_REFRESH_DEVICELIST); filterLocal.addAction(GBDevice.ACTION_DEVICE_CHANGED); filterLocal.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED); LocalBroadcastManager.getInstance(context).registerReceiver(mReceiver, filterLocal); context.registerReceiver(mReceiver, new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED)); refreshPairedDevices(); } private void updateSelectedDevice(GBDevice dev) { if (selectedDevice == null) { selectedDevice = dev; } else { if (!selectedDevice.equals(dev)) { if (selectedDevice.isConnected() && dev.isConnected()) { LOG.warn("multiple connected devices -- this is currently not really supported"); selectedDevice = dev; // use the last one that changed } if (!selectedDevice.isConnected()) { selectedDevice = dev; // use the last one that changed } } } } private void refreshPairedDevices() { Set availableDevices = DeviceHelper.getInstance().getAvailableDevices(context); deviceList.retainAll(availableDevices); for (GBDevice availableDevice : availableDevices) { if (!deviceList.contains(availableDevice)) { deviceList.add(availableDevice); } } notifyDevicesChanged(); } /** * The returned list is final, it will never be recreated. Only its contents change. * This allows direct access to the list from ListAdapters. */ public List getDevices() { return Collections.unmodifiableList(deviceList); } public GBDevice getSelectedDevice() { return selectedDevice; } private void notifyDevicesChanged() { LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(ACTION_DEVICES_CHANGED)); } }