diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java index a1a1dc3ee..33987a5f6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java @@ -68,6 +68,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Calendar; import java.util.LinkedHashMap; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -272,26 +273,28 @@ public class DebugActivity extends AbstractGBActivity { if (context instanceof GBApplication) { GBApplication gbApp = (GBApplication) context; - final GBDevice device = gbApp.getDeviceManager().getSelectedDevice(); - if (device != null) { - new DatePickerDialog(DebugActivity.this, new DatePickerDialog.OnDateSetListener() { - @Override - public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { - Calendar date = Calendar.getInstance(); - date.set(year, monthOfYear, dayOfMonth); + final List devices = gbApp.getDeviceManager().getSelectedDevices(); + if(devices.size() == 0){ + GB.toast("Device not selected/connected", Toast.LENGTH_LONG, GB.INFO); + return; + } + new DatePickerDialog(DebugActivity.this, new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { + Calendar date = Calendar.getInstance(); + date.set(year, monthOfYear, dayOfMonth); - long timestamp = date.getTimeInMillis() - 1000; - GB.toast("Setting lastSyncTimeMillis: " + timestamp, Toast.LENGTH_LONG, GB.INFO); + long timestamp = date.getTimeInMillis() - 1000; + GB.toast("Setting lastSyncTimeMillis: " + timestamp, Toast.LENGTH_LONG, GB.INFO); + for(GBDevice device : devices){ SharedPreferences.Editor editor = GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()).edit(); editor.remove("lastSyncTimeMillis"); //FIXME: key reconstruction is BAD editor.putLong("lastSyncTimeMillis", timestamp); editor.apply(); } - }, currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE)).show(); - } else { - GB.toast("Device not selected/connected", Toast.LENGTH_LONG, GB.INFO); - } + } + }, currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE)).show(); } @@ -411,8 +414,8 @@ public class DebugActivity extends AbstractGBActivity { public void onClick(View v) { Context context = getApplicationContext(); GBApplication gbApp = (GBApplication) context; - final GBDevice device = gbApp.getDeviceManager().getSelectedDevice(); - if (device != null) { + List devices = gbApp.getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ GBApplication.deleteDeviceSpecificSharedPrefs(device.getAddress()); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java index db6b1ec24..868ac188b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java @@ -214,6 +214,19 @@ public class FwAppInstallerActivity extends AbstractGBActivity implements Instal } else { setInfoText(getString(R.string.installer_activity_wait_while_determining_status)); + List selectedDevices = GBApplication.app().getDeviceManager().getSelectedDevices(); + if(selectedDevices.size() == 0){ + GB.toast("please connect the device you want to send to", Toast.LENGTH_LONG, GB.ERROR); + finish(); + return; + } + if(selectedDevices.size() != 1){ + GB.toast("please connect ONLY the device you want to send to", Toast.LENGTH_LONG, GB.ERROR); + finish(); + return; + } + device = selectedDevices.get(0); + // needed to get the device if (device == null || !device.isConnected()) { connect(); @@ -245,14 +258,17 @@ public class FwAppInstallerActivity extends AbstractGBActivity implements Instal List allCoordinators = DeviceHelper.getInstance().getAllCoordinators(); List sortedCoordinators = new ArrayList<>(allCoordinators.size()); - GBDevice connectedDevice = deviceManager.getSelectedDevice(); - if (connectedDevice != null && connectedDevice.isConnected()) { - DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(connectedDevice); - if (coordinator != null) { - connectedCoordinators.add(coordinator); + List devices = deviceManager.getSelectedDevices(); + for(GBDevice connectedDevice : devices){ + if (connectedDevice.isConnected()) { + DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(connectedDevice); + if (coordinator != null) { + connectedCoordinators.add(coordinator); + } } } + sortedCoordinators.addAll(connectedCoordinators); for (DeviceCoordinator coordinator : allCoordinators) { if (!connectedCoordinators.contains(coordinator)) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java index 53808daff..7490be798 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSpecificSettingsFragment.java @@ -811,6 +811,8 @@ public class DeviceSpecificSettingsFragment extends PreferenceFragmentCompat imp int[] supportedSettings = coordinator.getSupportedDeviceSpecificSettings(device); String[] supportedLanguages = coordinator.getSupportedLanguageSettings(device); + supportedSettings = ArrayUtils.insert(0, supportedSettings, coordinator.getSupportedDeviceSpecificConnectionSettings()); + if (supportedLanguages != null) { supportedSettings = ArrayUtils.insert(0, supportedSettings, R.xml.devicesettings_language_generic); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java index 5b4f2a3b4..fd2a8900a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java @@ -154,7 +154,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter deviceList = new ArrayList<>(); - private GBDevice selectedDevice = null; + private List selectedDevices = new ArrayList<>(); private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override @@ -137,22 +137,13 @@ public class DeviceManager { } private void updateSelectedDevice(GBDevice dev) { - if (selectedDevice == null) { - selectedDevice = dev; - } else { - if (selectedDevice.equals(dev)) { - selectedDevice = dev; // equality vs identity! - } else { - if (selectedDevice.isConnected() && dev.isConnected()) { - LOG.warn("multiple connected devices -- this is currently not really supported"); - selectedDevice = dev; // use the last one that changed - } else if (!selectedDevice.isConnected()) { - selectedDevice = dev; // use the last one that changed - } + selectedDevices.clear(); + for(GBDevice device : deviceList){ + if(device.isInitialized()){ + selectedDevices.add(device); } } - GB.updateNotification(selectedDevice, context); - + GB.updateNotification(selectedDevices, context); } private void refreshPairedDevices() { @@ -184,9 +175,8 @@ public class DeviceManager { return Collections.unmodifiableList(deviceList); } - @Nullable - public GBDevice getSelectedDevice() { - return selectedDevice; + public List getSelectedDevices() { + return selectedDevices; } private void notifyDevicesChanged() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleCoordinator.java index 1131b1a91..499f3b7fd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleCoordinator.java @@ -25,6 +25,7 @@ import androidx.annotation.NonNull; import java.io.File; import java.io.IOException; +import java.util.List; import de.greenrobot.dao.query.QueryBuilder; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -168,18 +169,27 @@ public class PebbleCoordinator extends AbstractDeviceCoordinator { @Override public boolean supportsAppListFetching() { - GBDevice mGBDevice = GBApplication.app().getDeviceManager().getSelectedDevice(); - if (mGBDevice != null && mGBDevice.getFirmwareVersion() != null) { - return PebbleUtils.getFwMajor(mGBDevice.getFirmwareVersion()) < 3; + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ + if(device.getType() == DeviceType.PEBBLE){ + if (device.getFirmwareVersion() != null) { + return PebbleUtils.getFwMajor(device.getFirmwareVersion()) < 3; + } + } } + return false; } @Override public boolean supportsAppReordering() { - GBDevice mGBDevice = GBApplication.app().getDeviceManager().getSelectedDevice(); - if (mGBDevice != null && mGBDevice.getFirmwareVersion() != null) { - return PebbleUtils.getFwMajor(mGBDevice.getFirmwareVersion()) >= 3; + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ + if(device.getType() == DeviceType.PEBBLE){ + if (device.getFirmwareVersion() != null) { + return PebbleUtils.getFwMajor(device.getFirmwareVersion()) >= 3; + } + } } return false; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qc35/QC35Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qc35/QC35Coordinator.java index ff144f3e2..992136454 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qc35/QC35Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qc35/QC35Coordinator.java @@ -25,7 +25,7 @@ import androidx.annotation.Nullable; import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLClassicDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession; @@ -35,7 +35,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; -public class QC35Coordinator extends AbstractDeviceCoordinator { +public class QC35Coordinator extends AbstractBLClassicDeviceCoordinator { @Override protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/AppsManagementActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/AppsManagementActivity.java index fa78dba20..9b2309dff 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/AppsManagementActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/AppsManagementActivity.java @@ -54,25 +54,34 @@ public class AppsManagementActivity extends AbstractGBActivity { private void refreshInstalledApps() { try { - GBDevice selected = GBApplication.app().getDeviceManager().getSelectedDevice(); - if (selected.getType() != DeviceType.FOSSILQHYBRID || !selected.isConnected() || !selected.getModel().startsWith("DN") || selected.getState() != GBDevice.State.INITIALIZED) { - throw new RuntimeException("Device not connected"); + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + boolean deviceFound = false; + for(GBDevice device : devices){ + if ( + device.getType() == DeviceType.FOSSILQHYBRID && + device.isConnected() && + device.getModel().startsWith("DN") && + device.getState() == GBDevice.State.INITIALIZED + ) { + String installedAppsJson = device.getDeviceInfo("INSTALLED_APPS").getDetails(); + if (installedAppsJson == null || installedAppsJson.isEmpty()) { + throw new RuntimeException("can't get installed apps"); + } + JSONArray apps = new JSONArray(installedAppsJson); + appNames = new String[apps.length()]; + for (int i = 0; i < apps.length(); i++) { + appNames[i] = apps.getString(i); + } + appsListView.setAdapter(new AppsListAdapter(this, appNames)); + } + return; } - String installedAppsJson = selected.getDeviceInfo("INSTALLED_APPS").getDetails(); - if (installedAppsJson == null || installedAppsJson.isEmpty()) { - throw new RuntimeException("cant get installed apps"); - } - JSONArray apps = new JSONArray(installedAppsJson); - appNames = new String[apps.length()]; - for (int i = 0; i < apps.length(); i++) { - appNames[i] = apps.getString(i); - } - appsListView.setAdapter(new AppsListAdapter(this, appNames)); - } catch (Exception e) { + } catch (JSONException e) { toast(e.getMessage()); finish(); return; } + throw new RuntimeException("Device not connected"); } class AppsListAdapter extends ArrayAdapter { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/CalibrationActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/CalibrationActivity.java index eb248efe2..87d23e2ed 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/CalibrationActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/CalibrationActivity.java @@ -29,6 +29,8 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import java.util.List; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity; @@ -85,9 +87,16 @@ public class CalibrationActivity extends AbstractGBActivity { super.onCreate(savedInstanceState); setContentView(R.layout.activity_qhybrid_calibration); - GBDevice device = GBApplication.app().getDeviceManager().getSelectedDevice(); + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + boolean atLeastOneConnected = false; + for(GBDevice device : devices){ + if(device.getType() == DeviceType.FOSSILQHYBRID){ + atLeastOneConnected = true; + break; + } + } - if(device == null || device.getType() != DeviceType.FOSSILQHYBRID){ + if(!atLeastOneConnected){ Toast.makeText(this, R.string.watch_not_connected, Toast.LENGTH_LONG).show(); finish(); return; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/ConfigActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/ConfigActivity.java index 3b8cbb429..37c600347 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/ConfigActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/ConfigActivity.java @@ -303,12 +303,14 @@ public class ConfigActivity extends AbstractGBActivity { } }); - device = GBApplication.app().getDeviceManager().getSelectedDevice(); - if (device == null || device.getType() != DeviceType.FOSSILQHYBRID || device.getFirmwareVersion().charAt(2) != '0') { - setSettingsError(getString(R.string.watch_not_connected)); - } else { - updateSettings(); + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ + if (device.getType() == DeviceType.FOSSILQHYBRID && device.getFirmwareVersion().charAt(2) == '0') { + updateSettings(); + return; + } } + setSettingsError(getString(R.string.watch_not_connected)); } private void updateTimeOffset() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HRConfigActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HRConfigActivity.java index fd7537f1d..d57e38d60 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HRConfigActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/HRConfigActivity.java @@ -46,6 +46,8 @@ import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomBackgroundWidgetElement; import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.widget.CustomTextWidgetElement; @@ -168,19 +170,25 @@ public class HRConfigActivity extends AbstractGBActivity { } // Disable some functions on watches with too new firmware (from official app 4.6.0 and higher) - String fwVersion_str = GBApplication.app().getDeviceManager().getSelectedDevice().getFirmwareVersion(); - fwVersion_str = fwVersion_str.replaceFirst("^DN", "").replaceFirst("r\\.v.*", ""); - Version fwVersion = new Version(fwVersion_str); - if (fwVersion.compareTo(new Version("1.0.2.20")) >= 0) { - findViewById(R.id.qhybrid_widget_add).setEnabled(false); - for (int i = 0; i < widgetButtonsMapping.size(); i++) { - final int widgetButtonId = widgetButtonsMapping.keyAt(i); - findViewById(widgetButtonId).setEnabled(false); + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ + if(device.getType() == DeviceType.FOSSILQHYBRID){ + String fwVersion_str = device.getFirmwareVersion(); + fwVersion_str = fwVersion_str.replaceFirst("^DN", "").replaceFirst("r\\.v.*", ""); + Version fwVersion = new Version(fwVersion_str); + if (fwVersion.compareTo(new Version("1.0.2.20")) >= 0) { + findViewById(R.id.qhybrid_widget_add).setEnabled(false); + for (int i = 0; i < widgetButtonsMapping.size(); i++) { + final int widgetButtonId = widgetButtonsMapping.keyAt(i); + findViewById(widgetButtonId).setEnabled(false); + } + findViewById(R.id.qhybrid_set_background).setEnabled(false); + findViewById(R.id.qhybrid_unset_background).setEnabled(false); + GB.toast(getString(R.string.fossil_hr_warning_firmware_too_new), Toast.LENGTH_LONG, GB.INFO); + } } - findViewById(R.id.qhybrid_set_background).setEnabled(false); - findViewById(R.id.qhybrid_unset_background).setEnabled(false); - GB.toast(getString(R.string.fossil_hr_warning_firmware_too_new), Toast.LENGTH_LONG, GB.INFO); } + } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/QHybridCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/QHybridCoordinator.java index 90eebd59e..e22b7b73a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/QHybridCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/qhybrid/QHybridCoordinator.java @@ -35,6 +35,7 @@ import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -42,6 +43,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActivity; +import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; @@ -54,7 +56,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; import nodomain.freeyourgadget.gadgetbridge.util.Version; -public class QHybridCoordinator extends AbstractDeviceCoordinator { +public class QHybridCoordinator extends AbstractBLEDeviceCoordinator { private static final Logger LOG = LoggerFactory.getLogger(QHybridCoordinator.class); @NonNull @@ -89,8 +91,13 @@ public class QHybridCoordinator extends AbstractDeviceCoordinator { @Override public boolean supportsActivityDataFetching() { - GBDevice connectedDevice = GBApplication.app().getDeviceManager().getSelectedDevice(); - return connectedDevice != null && connectedDevice.getType() == DeviceType.FOSSILQHYBRID && connectedDevice.getState() == GBDevice.State.INITIALIZED; + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ + if(isFossilHybrid(device) && device.getState() == GBDevice.State.INITIALIZED){ + return true; + } + } + return false; } @Override @@ -129,11 +136,14 @@ public class QHybridCoordinator extends AbstractDeviceCoordinator { } private boolean supportsAlarmConfiguration() { - GBDevice connectedDevice = GBApplication.app().getDeviceManager().getSelectedDevice(); - if(connectedDevice == null || connectedDevice.getType() != DeviceType.FOSSILQHYBRID || connectedDevice.getState() != GBDevice.State.INITIALIZED){ - return false; + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + LOG.debug("devices count: " + devices.size()); + for(GBDevice device : devices){ + if(isFossilHybrid(device) && device.getState() == GBDevice.State.INITIALIZED){ + return true; + } } - return true; + return false; } @Override @@ -268,22 +278,34 @@ public class QHybridCoordinator extends AbstractDeviceCoordinator { } private boolean isHybridHR() { - GBDevice connectedDevice = GBApplication.app().getDeviceManager().getSelectedDevice(); - if (connectedDevice != null) { - return connectedDevice.getName().startsWith("Hybrid HR"); + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ + if(isFossilHybrid(device) && device.getName().startsWith("Hybrid HR")){ + return true; + } } return false; } private Version getFirmwareVersion() { - String firmware = GBApplication.app().getDeviceManager().getSelectedDevice().getFirmwareVersion(); - if (firmware != null) { - Matcher matcher = Pattern.compile("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+").matcher(firmware); // DN1.0.2.19r.v5 - if (matcher.find()) { - firmware = matcher.group(0); - return new Version(firmware); + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ + if(isFossilHybrid(device)){ + String firmware = device.getFirmwareVersion(); + if (firmware != null) { + Matcher matcher = Pattern.compile("[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+").matcher(firmware); // DN1.0.2.19r.v5 + if (matcher.find()) { + firmware = matcher.group(0); + return new Version(firmware); + } + } } } + return null; } + + private boolean isFossilHybrid(GBDevice device){ + return device.getType() == DeviceType.FOSSILQHYBRID; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/um25/Coordinator/UM25Coordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/um25/Coordinator/UM25Coordinator.java index 4acf35b94..e24f017d3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/um25/Coordinator/UM25Coordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/um25/Coordinator/UM25Coordinator.java @@ -14,6 +14,7 @@ import java.util.Collections; import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; @@ -26,7 +27,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; import nodomain.freeyourgadget.gadgetbridge.service.devices.um25.Support.UM25Support; -public class UM25Coordinator extends AbstractDeviceCoordinator { +public class UM25Coordinator extends AbstractBLEDeviceCoordinator { @Override protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescCoordinator.java index 773b7e6a1..da084a95a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescCoordinator.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.GBException; +import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; @@ -36,7 +37,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; -public class VescCoordinator extends AbstractDeviceCoordinator { +public class VescCoordinator extends AbstractBLEDeviceCoordinator { public final static String UUID_SERVICE_SERIAL_HM10 = "0000ffe0-0000-1000-8000-00805f9b34fb"; public final static String UUID_CHARACTERISTIC_SERIAL_TX_HM10 = "0000ffe1-0000-1000-8000-00805f9b34fb"; public final static String UUID_CHARACTERISTIC_SERIAL_RX_HM10 = "0000ffe1-0000-1000-8000-00805f9b34fb"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java index c60b3ac76..b6bc4c84b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothConnectReceiver.java @@ -20,13 +20,17 @@ import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.List; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; +import nodomain.freeyourgadget.gadgetbridge.util.GBPrefs; public class BluetoothConnectReceiver extends BroadcastReceiver { @@ -46,14 +50,30 @@ public class BluetoothConnectReceiver extends BroadcastReceiver { } BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - LOG.info("connection attempt detected from or to " + device.getAddress() + "(" + device.getName() + ")"); + LOG.info("connection attempt detected from " + device.getAddress() + "(" + device.getName() + ")"); - GBDevice gbDevice = service.getGBDevice(); - if (gbDevice != null) { - if (device.getAddress().equals(gbDevice.getAddress()) && gbDevice.getState() == GBDevice.State.WAITING_FOR_RECONNECT) { - LOG.info("Will re-connect to " + gbDevice.getAddress() + "(" + gbDevice.getName() + ")"); - GBApplication.deviceService().connect(); + GBDevice gbDevice = getKnownDeviceByAddressOrNull(device.getAddress()); + if(gbDevice == null){ + LOG.info("connected device {} unknown", device.getAddress()); + return; + } + SharedPreferences deviceSpecificPreferences = GBApplication.getDeviceSpecificSharedPrefs(gbDevice.getAddress()); + boolean reactToConnection = deviceSpecificPreferences.getBoolean(GBPrefs.DEVICE_CONNECT_BACK, false); + reactToConnection |= gbDevice.getState() == GBDevice.State.WAITING_FOR_RECONNECT; + if(!reactToConnection){ + return; + } + LOG.info("Will re-connect to " + gbDevice.getAddress() + "(" + gbDevice.getName() + ")"); + GBApplication.deviceService().connect(gbDevice); + } + + private GBDevice getKnownDeviceByAddressOrNull(String deviceAddress){ + List knownDevices = GBApplication.app().getDeviceManager().getDevices(); + for(GBDevice device : knownDevices){ + if(device.getAddress().equals(deviceAddress)){ + return device; } } + return null; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothPairingRequestReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothPairingRequestReceiver.java index 56104c5cf..efb90d8a5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothPairingRequestReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothPairingRequestReceiver.java @@ -47,21 +47,26 @@ public class BluetoothPairingRequestReceiver extends BroadcastReceiver { if (!action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) { return; } - - GBDevice gbDevice = service.getGBDevice(); BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); - if (gbDevice == null || device == null) { + if (device == null) { return; } - DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice); + GBDevice gbDevice = null; try { - if (coordinator.getBondingStyle() == DeviceCoordinator.BONDING_STYLE_NONE) { - LOG.info("Aborting unwanted pairing request"); - abortBroadcast(); + gbDevice = service.getDeviceByAddress(device.getAddress()); + + DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice); + try { + if (coordinator.getBondingStyle() == DeviceCoordinator.BONDING_STYLE_NONE) { + LOG.info("Aborting unwanted pairing request"); + abortBroadcast(); + } + } catch (Exception e) { + LOG.warn("Could not abort pairing request process"); } - } catch (Exception e) { - LOG.warn("Could not abort pairing request process"); + } catch (DeviceCommunicationService.DeviceNotFoundException e) { + e.printStackTrace(); } } } \ No newline at end of file diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index 547afd723..38e641787 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -767,9 +767,9 @@ public class NotificationListener extends NotificationListenerService { notificationsActive.removeAll(notificationsToRemove); // Send notification remove request to device - GBDevice connectedDevice = GBApplication.app().getDeviceManager().getSelectedDevice(); - if (connectedDevice != null) { - Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(connectedDevice.getAddress())); + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ + Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress())); if (prefs.getBoolean("autoremove_notifications", true)) { for (int id : notificationsToRemove) { LOG.info("Notification " + id + " removed, will ask device to delete it"); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index ff04bde7c..409ff088b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -118,6 +118,13 @@ public class GBDeviceService implements DeviceService { invokeService(intent); } + @Override + public void disconnect(@Nullable GBDevice device) { + Intent intent = createIntent().setAction(ACTION_DISCONNECT) + .putExtra(GBDevice.EXTRA_DEVICE, device); + invokeService(intent); + } + @Override public void disconnect() { Intent intent = createIntent().setAction(ACTION_DISCONNECT); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index c653dae77..d26f55944 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -154,6 +154,8 @@ public interface DeviceService extends EventHandler { void connect(@Nullable GBDevice device, boolean firstTime); + void disconnect(@Nullable GBDevice device); + void disconnect(); void quit(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index defa78adf..8e251f03c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -44,9 +44,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Arrays; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.GBException; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; @@ -189,6 +191,108 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEA import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WORLD_CLOCKS; public class DeviceCommunicationService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener { + public static class DeviceStruct{ + private GBDevice device; + private DeviceCoordinator coordinator; + private DeviceSupport deviceSupport; + + public GBDevice getDevice() { + return device; + } + + public void setDevice(GBDevice device) { + this.device = device; + } + + public DeviceCoordinator getCoordinator() { + return coordinator; + } + + public void setCoordinator(DeviceCoordinator coordinator) { + this.coordinator = coordinator; + } + + public DeviceSupport getDeviceSupport() { + return deviceSupport; + } + + public void setDeviceSupport(DeviceSupport deviceSupport) { + this.deviceSupport = deviceSupport; + } + } + + private class FeatureSet{ + private boolean supportsWeather = false; + private boolean supportsActivityDataFetching = false; + private boolean supportsCalendarEvents = false; + private boolean supportsMusicInfo = false; + + public boolean supportsWeather() { + return supportsWeather; + } + + public void setSupportsWeather(boolean supportsWeather) { + this.supportsWeather = supportsWeather; + } + + public boolean supportsActivityDataFetching() { + return supportsActivityDataFetching; + } + + public void setSupportsActivityDataFetching(boolean supportsActivityDataFetching) { + this.supportsActivityDataFetching = supportsActivityDataFetching; + } + + public boolean supportsCalendarEvents() { + return supportsCalendarEvents; + } + + public void setSupportsCalendarEvents(boolean supportsCalendarEvents) { + this.supportsCalendarEvents = supportsCalendarEvents; + } + + public boolean supportsMusicInfo() { + return supportsMusicInfo; + } + + public void setSupportsMusicInfo(boolean supportsMusicInfo) { + this.supportsMusicInfo = supportsMusicInfo; + } + + public void logicalOr(DeviceCoordinator operand){ + if(operand.supportsCalendarEvents()){ + setSupportsCalendarEvents(true); + } + if(operand.supportsWeather()){ + setSupportsWeather(true); + } + if(operand.supportsActivityDataFetching()){ + setSupportsActivityDataFetching(true); + } + if(operand.supportsMusicInfo()){ + setSupportsMusicInfo(true); + } + } + } + + public static class DeviceNotFoundException extends GBException{ + private final String address; + + public DeviceNotFoundException(GBDevice device) { + this.address = device.getAddress(); + } + + public DeviceNotFoundException(String address) { + this.address = address; + } + + @Nullable + @Override + public String getMessage() { + return String.format("device %s not found cached", address); + } + } + private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class); @SuppressLint("StaticFieldLeak") // only used for test cases private static DeviceSupportFactory DEVICE_SUPPORT_FACTORY = null; @@ -196,9 +300,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere private boolean mStarted = false; private DeviceSupportFactory mFactory; - private GBDevice mGBDevice = null; - private DeviceSupport mDeviceSupport; - private DeviceCoordinator mCoordinator = null; + private final ArrayList deviceStructs = new ArrayList<>(1); private PhoneCallReceiver mPhoneCallReceiver = null; private SMSReceiver mSMSReceiver = null; @@ -236,6 +338,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere * * @param factory */ + @SuppressWarnings("JavaDoc") public static void setDeviceSupportFactory(DeviceSupportFactory factory) { DEVICE_SUPPORT_FACTORY = factory; } @@ -248,20 +351,45 @@ public class DeviceCommunicationService extends Service implements SharedPrefere @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (GBDevice.ACTION_DEVICE_CHANGED.equals(action)) { + if(GBDevice.ACTION_DEVICE_CHANGED.equals(action)){ GBDevice device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE); - if (mGBDevice != null && mGBDevice.equals(device)) { - mGBDevice = device; - mCoordinator = DeviceHelper.getInstance().getCoordinator(device); - boolean enableReceivers = mDeviceSupport != null && (mDeviceSupport.useAutoConnect() || mGBDevice.isInitialized()); - setReceiversEnableState(enableReceivers, mGBDevice.isInitialized(), mCoordinator); - } else { - LOG.error("Got ACTION_DEVICE_CHANGED from unexpected device: " + device); + + // create a new instance of the changed devices coordinator, in case it's capabilities changed + DeviceStruct cachedStruct = getDeviceStructOrNull(device); + if(cachedStruct != null) { + cachedStruct.setDevice(device); + DeviceCoordinator newCoordinator = DeviceHelper.getInstance().getCoordinator(device); + cachedStruct.setCoordinator(newCoordinator); } + updateReceiversState(); } } }; + private void updateReceiversState(){ + boolean enableReceivers = false; + boolean anyDeviceInitialized = false; + + FeatureSet features = new FeatureSet(); + + for(DeviceStruct struct: deviceStructs){ + DeviceSupport deviceSupport = struct.getDeviceSupport(); + if((deviceSupport != null && deviceSupport.useAutoConnect()) || isDeviceInitialized(struct.getDevice())){ + enableReceivers = true; + } + if(isDeviceInitialized(struct.getDevice())){ + anyDeviceInitialized = true; + } + + DeviceCoordinator coordinator = struct.getCoordinator(); + if(coordinator != null){ + features.logicalOr(coordinator); + } + } + + setReceiversEnableState(enableReceivers, anyDeviceInitialized, features); + } + @Override public void onCreate() { LOG.debug("DeviceCommunicationService is being created"); @@ -269,6 +397,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, new IntentFilter(GBDevice.ACTION_DEVICE_CHANGED)); mFactory = getDeviceSupportFactory(); + mBlueToothConnectReceiver = new BluetoothConnectReceiver(this); + registerReceiver(mBlueToothConnectReceiver, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)); + if (hasPrefs()) { getPrefs().getPreferences().registerOnSharedPreferenceChangeListener(this); } @@ -306,14 +437,15 @@ public class DeviceCommunicationService extends Service implements SharedPrefere return START_NOT_STICKY; } - if (mDeviceSupport == null || (!isInitialized() && !action.equals(ACTION_DISCONNECT) && (!mDeviceSupport.useAutoConnect() || isConnected()))) { + // TODO + /*if (mDeviceSupport == null || (!isInitialized() && !action.equals(ACTION_DISCONNECT) && (!mDeviceSupport.useAutoConnect() || isConnected()))) { // trying to send notification without valid Bluetooth connection if (mGBDevice != null) { // at least send back the current device state mGBDevice.sendDeviceUpdateIntent(this); } return START_STICKY; - } + }*/ } // when we get past this, we should have valid mDeviceSupport and mGBDevice instances @@ -338,41 +470,73 @@ public class DeviceCommunicationService extends Service implements SharedPrefere btDeviceAddress = gbDevice.getAddress(); } + if(gbDevice == null){ + return START_NOT_STICKY; + } + boolean autoReconnect = GBPrefs.AUTO_RECONNECT_DEFAULT; if (prefs != null && prefs.getPreferences() != null) { prefs.getPreferences().edit().putString("last_device_address", btDeviceAddress).apply(); - autoReconnect = getGBPrefs().getAutoReconnect(); + autoReconnect = getGBPrefs().getAutoReconnect(gbDevice); } - if (gbDevice != null && !isConnecting() && !isConnected()) { - setDeviceSupport(null); - try { - DeviceSupport deviceSupport = mFactory.createDeviceSupport(gbDevice); - if (deviceSupport != null) { - setDeviceSupport(deviceSupport); - if (firstTime) { - deviceSupport.connectFirstTime(); - } else { - deviceSupport.setAutoReconnect(autoReconnect); - deviceSupport.connect(); - } - } else { - GB.toast(this, getString(R.string.cannot_connect, "Can't create device support"), Toast.LENGTH_SHORT, GB.ERROR); - } - } catch (Exception e) { - GB.toast(this, getString(R.string.cannot_connect, e.getMessage()), Toast.LENGTH_SHORT, GB.ERROR, e); - setDeviceSupport(null); + DeviceStruct registeredStruct = getDeviceStructOrNull(gbDevice); + if(registeredStruct != null){ + boolean deviceAlreadyConnected = isDeviceConnecting(registeredStruct.getDevice()) || isDeviceConnected(registeredStruct.getDevice()); + if(deviceAlreadyConnected){ + break; } - } else if (mGBDevice != null) { - // send an update at least - mGBDevice.sendDeviceUpdateIntent(this); + try { + removeDeviceSupport(gbDevice); + } catch (DeviceNotFoundException e) { + e.printStackTrace(); + } + }else{ + registeredStruct = new DeviceStruct(); + registeredStruct.setDevice(gbDevice); + registeredStruct.setCoordinator(DeviceHelper.getInstance().getCoordinator(gbDevice)); + deviceStructs.add(registeredStruct); + } + + try { + DeviceSupport deviceSupport = mFactory.createDeviceSupport(gbDevice); + if (deviceSupport != null) { + setDeviceSupport(gbDevice, deviceSupport); + if (firstTime) { + deviceSupport.connectFirstTime(); + } else { + deviceSupport.setAutoReconnect(autoReconnect); + deviceSupport.connect(); + } + } else { + GB.toast(this, getString(R.string.cannot_connect, "Can't create device support"), Toast.LENGTH_SHORT, GB.ERROR); + } + } catch (Exception e) { + GB.toast(this, getString(R.string.cannot_connect, e.getMessage()), Toast.LENGTH_SHORT, GB.ERROR, e); + } + + for(DeviceStruct struct2 : deviceStructs){ + struct2.getDevice().sendDeviceUpdateIntent(this); } break; default: - if (mDeviceSupport == null || mGBDevice == null) { - LOG.warn("device support:" + mDeviceSupport + ", device: " + mGBDevice + ", aborting"); - } else { - handleAction(intent, action, prefs); + GBDevice targetedDevice = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE); + ArrayList targetedDevices = new ArrayList<>(); + if(targetedDevice != null){ + targetedDevices.add(targetedDevice); + }else{ + for(GBDevice device : getGBDevices()){ + if(isDeviceInitialized(device)){ + targetedDevices.add(device); + } + } + } + for (GBDevice device1 : targetedDevices) { + try { + handleAction(intent, action, device1); + } catch (DeviceNotFoundException e) { + e.printStackTrace(); + } } break; } @@ -383,21 +547,35 @@ public class DeviceCommunicationService extends Service implements SharedPrefere * @param text original text * @return 'text' or a new String without non supported chars like emoticons, etc. */ - private String sanitizeNotifText(String text) { + private String sanitizeNotifText(String text, GBDevice device) throws DeviceNotFoundException { if (text == null || text.length() == 0) return text; - text = mDeviceSupport.customStringFilter(text); + text = getDeviceSupport(device).customStringFilter(text); - if (!mCoordinator.supportsUnicodeEmojis()) { + if (!getDeviceCoordinator(device).supportsUnicodeEmojis()) { return EmojiConverter.convertUnicodeEmojiToAscii(text, getApplicationContext()); } return text; } - private void handleAction(Intent intent, String action, Prefs prefs) { - Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(mGBDevice.getAddress())); + private DeviceCoordinator getDeviceCoordinator(GBDevice device) throws DeviceNotFoundException { + if(device == null){ + throw new DeviceNotFoundException("null"); + } + for(DeviceStruct struct : deviceStructs){ + if(struct.getDevice().equals(device)){ + return struct.getCoordinator(); + } + } + throw new DeviceNotFoundException(device); + } + + private void handleAction(Intent intent, String action, GBDevice device) throws DeviceNotFoundException { + DeviceSupport deviceSupport = getDeviceSupport(device); + + Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress())); boolean transliterate = devicePrefs.getBoolean(PREF_TRANSLITERATION_ENABLED, false); if (transliterate) { @@ -410,16 +588,16 @@ public class DeviceCommunicationService extends Service implements SharedPrefere switch (action) { case ACTION_REQUEST_DEVICEINFO: - mGBDevice.sendDeviceUpdateIntent(this); + device.sendDeviceUpdateIntent(this); break; case ACTION_NOTIFICATION: { int desiredId = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1); NotificationSpec notificationSpec = new NotificationSpec(desiredId); notificationSpec.phoneNumber = intent.getStringExtra(EXTRA_NOTIFICATION_PHONENUMBER); - notificationSpec.sender = sanitizeNotifText(intent.getStringExtra(EXTRA_NOTIFICATION_SENDER)); - notificationSpec.subject = sanitizeNotifText(intent.getStringExtra(EXTRA_NOTIFICATION_SUBJECT)); - notificationSpec.title = sanitizeNotifText(intent.getStringExtra(EXTRA_NOTIFICATION_TITLE)); - notificationSpec.body = sanitizeNotifText(intent.getStringExtra(EXTRA_NOTIFICATION_BODY)); + notificationSpec.sender = sanitizeNotifText(intent.getStringExtra(EXTRA_NOTIFICATION_SENDER), device); + notificationSpec.subject = sanitizeNotifText(intent.getStringExtra(EXTRA_NOTIFICATION_SUBJECT), device); + notificationSpec.title = sanitizeNotifText(intent.getStringExtra(EXTRA_NOTIFICATION_TITLE), device); + notificationSpec.body = sanitizeNotifText(intent.getStringExtra(EXTRA_NOTIFICATION_BODY), device); notificationSpec.sourceName = intent.getStringExtra(EXTRA_NOTIFICATION_SOURCENAME); notificationSpec.type = (NotificationType) intent.getSerializableExtra(EXTRA_NOTIFICATION_TYPE); notificationSpec.attachedActions = (ArrayList) intent.getSerializableExtra(EXTRA_NOTIFICATION_ACTIONS); @@ -449,11 +627,11 @@ public class DeviceCommunicationService extends Service implements SharedPrefere notificationSpec.cannedReplies = replies.toArray(new String[0]); } - mDeviceSupport.onNotification(notificationSpec); + deviceSupport.onNotification(notificationSpec); break; } case ACTION_DELETE_NOTIFICATION: { - mDeviceSupport.onDeleteNotification(intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)); + deviceSupport.onDeleteNotification(intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1)); break; } case ACTION_ADD_CALENDAREVENT: { @@ -462,61 +640,62 @@ public class DeviceCommunicationService extends Service implements SharedPrefere calendarEventSpec.type = intent.getByteExtra(EXTRA_CALENDAREVENT_TYPE, (byte) -1); calendarEventSpec.timestamp = intent.getIntExtra(EXTRA_CALENDAREVENT_TIMESTAMP, -1); calendarEventSpec.durationInSeconds = intent.getIntExtra(EXTRA_CALENDAREVENT_DURATION, -1); - calendarEventSpec.title = sanitizeNotifText(intent.getStringExtra(EXTRA_CALENDAREVENT_TITLE)); - calendarEventSpec.description = sanitizeNotifText(intent.getStringExtra(EXTRA_CALENDAREVENT_DESCRIPTION)); - calendarEventSpec.location = sanitizeNotifText(intent.getStringExtra(EXTRA_CALENDAREVENT_LOCATION)); - mDeviceSupport.onAddCalendarEvent(calendarEventSpec); + calendarEventSpec.title = sanitizeNotifText(intent.getStringExtra(EXTRA_CALENDAREVENT_TITLE), device); + calendarEventSpec.description = sanitizeNotifText(intent.getStringExtra(EXTRA_CALENDAREVENT_DESCRIPTION), device); + calendarEventSpec.location = sanitizeNotifText(intent.getStringExtra(EXTRA_CALENDAREVENT_LOCATION), device); + deviceSupport.onAddCalendarEvent(calendarEventSpec); break; } case ACTION_DELETE_CALENDAREVENT: { long id = intent.getLongExtra(EXTRA_CALENDAREVENT_ID, -1); byte type = intent.getByteExtra(EXTRA_CALENDAREVENT_TYPE, (byte) -1); - mDeviceSupport.onDeleteCalendarEvent(type, id); + deviceSupport.onDeleteCalendarEvent(type, id); break; } case ACTION_RESET: { int flags = intent.getIntExtra(EXTRA_RESET_FLAGS, 0); - mDeviceSupport.onReset(flags); + deviceSupport.onReset(flags); break; } case ACTION_HEARTRATE_TEST: { - mDeviceSupport.onHeartRateTest(); + deviceSupport.onHeartRateTest(); break; } case ACTION_FETCH_RECORDED_DATA: { - int dataTypes = intent.getIntExtra(EXTRA_RECORDED_DATA_TYPES, 0); - mDeviceSupport.onFetchRecordedData(dataTypes); - break; - } - case ACTION_DISCONNECT: { - mDeviceSupport.dispose(); - if (mGBDevice != null) { - mGBDevice.setState(GBDevice.State.NOT_CONNECTED); - mGBDevice.sendDeviceUpdateIntent(this); + if(!getDeviceCoordinator(device).supportsActivityDataFetching()){ + break; } - setReceiversEnableState(false, false, null); - mGBDevice = null; - mDeviceSupport = null; - mCoordinator = null; + int dataTypes = intent.getIntExtra(EXTRA_RECORDED_DATA_TYPES, 0); + deviceSupport.onFetchRecordedData(dataTypes); break; } + case ACTION_DISCONNECT: + try { + removeDeviceSupport(device); + } catch (DeviceNotFoundException e) { + e.printStackTrace(); + } + device.setState(GBDevice.State.NOT_CONNECTED); + device.sendDeviceUpdateIntent(this); + updateReceiversState(); + break; case ACTION_FIND_DEVICE: { boolean start = intent.getBooleanExtra(EXTRA_FIND_START, false); - mDeviceSupport.onFindDevice(start); + deviceSupport.onFindDevice(start); break; } case ACTION_SET_CONSTANT_VIBRATION: { int intensity = intent.getIntExtra(EXTRA_VIBRATION_INTENSITY, 0); - mDeviceSupport.onSetConstantVibration(intensity); + deviceSupport.onSetConstantVibration(intensity); break; } case ACTION_CALLSTATE: CallSpec callSpec = new CallSpec(); callSpec.command = intent.getIntExtra(EXTRA_CALL_COMMAND, CallSpec.CALL_UNDEFINED); callSpec.number = intent.getStringExtra(EXTRA_CALL_PHONENUMBER); - callSpec.name = sanitizeNotifText(intent.getStringExtra(EXTRA_CALL_DISPLAYNAME)); + callSpec.name = sanitizeNotifText(intent.getStringExtra(EXTRA_CALL_DISPLAYNAME), device); callSpec.dndSuppressed = intent.getIntExtra(EXTRA_CALL_DNDSUPPRESSED, 0); - mDeviceSupport.onSetCallState(callSpec); + deviceSupport.onSetCallState(callSpec); break; case ACTION_SETCANNEDMESSAGES: int type = intent.getIntExtra(EXTRA_CANNEDMESSAGES_TYPE, -1); @@ -525,24 +704,24 @@ public class DeviceCommunicationService extends Service implements SharedPrefere CannedMessagesSpec cannedMessagesSpec = new CannedMessagesSpec(); cannedMessagesSpec.type = type; cannedMessagesSpec.cannedMessages = cannedMessages; - mDeviceSupport.onSetCannedMessages(cannedMessagesSpec); + deviceSupport.onSetCannedMessages(cannedMessagesSpec); break; case ACTION_SETTIME: - mDeviceSupport.onSetTime(); + deviceSupport.onSetTime(); break; case ACTION_SETMUSICINFO: MusicSpec musicSpec = new MusicSpec(); - musicSpec.artist = sanitizeNotifText(intent.getStringExtra(EXTRA_MUSIC_ARTIST)); - musicSpec.album = sanitizeNotifText(intent.getStringExtra(EXTRA_MUSIC_ALBUM)); - musicSpec.track = sanitizeNotifText(intent.getStringExtra(EXTRA_MUSIC_TRACK)); + musicSpec.artist = sanitizeNotifText(intent.getStringExtra(EXTRA_MUSIC_ARTIST), device); + musicSpec.album = sanitizeNotifText(intent.getStringExtra(EXTRA_MUSIC_ALBUM), device); + musicSpec.track = sanitizeNotifText(intent.getStringExtra(EXTRA_MUSIC_TRACK), device); musicSpec.duration = intent.getIntExtra(EXTRA_MUSIC_DURATION, 0); musicSpec.trackCount = intent.getIntExtra(EXTRA_MUSIC_TRACKCOUNT, 0); musicSpec.trackNr = intent.getIntExtra(EXTRA_MUSIC_TRACKNR, 0); - mDeviceSupport.onSetMusicInfo(musicSpec); + deviceSupport.onSetMusicInfo(musicSpec); break; case ACTION_SET_PHONE_VOLUME: float phoneVolume = intent.getFloatExtra(EXTRA_PHONE_VOLUME, 0); - mDeviceSupport.onSetPhoneVolume(phoneVolume); + deviceSupport.onSetPhoneVolume(phoneVolume); break; case ACTION_SETMUSICSTATE: MusicStateSpec stateSpec = new MusicStateSpec(); @@ -551,23 +730,23 @@ public class DeviceCommunicationService extends Service implements SharedPrefere stateSpec.position = intent.getIntExtra(EXTRA_MUSIC_POSITION, 0); stateSpec.playRate = intent.getIntExtra(EXTRA_MUSIC_RATE, 0); stateSpec.state = intent.getByteExtra(EXTRA_MUSIC_STATE, (byte) 0); - mDeviceSupport.onSetMusicState(stateSpec); + deviceSupport.onSetMusicState(stateSpec); break; case ACTION_REQUEST_APPINFO: - mDeviceSupport.onAppInfoReq(); + deviceSupport.onAppInfoReq(); break; case ACTION_REQUEST_SCREENSHOT: - mDeviceSupport.onScreenshotReq(); + deviceSupport.onScreenshotReq(); break; case ACTION_STARTAPP: { UUID uuid = (UUID) intent.getSerializableExtra(EXTRA_APP_UUID); boolean start = intent.getBooleanExtra(EXTRA_APP_START, true); - mDeviceSupport.onAppStart(uuid, start); + deviceSupport.onAppStart(uuid, start); break; } case ACTION_DELETEAPP: { UUID uuid = (UUID) intent.getSerializableExtra(EXTRA_APP_UUID); - mDeviceSupport.onAppDelete(uuid); + deviceSupport.onAppDelete(uuid); break; } case ACTION_APP_CONFIGURE: { @@ -577,87 +756,87 @@ public class DeviceCommunicationService extends Service implements SharedPrefere if (intent.hasExtra(EXTRA_APP_CONFIG_ID)) { id = intent.getIntExtra(EXTRA_APP_CONFIG_ID, 0); } - mDeviceSupport.onAppConfiguration(uuid, config, id); + deviceSupport.onAppConfiguration(uuid, config, id); break; } case ACTION_APP_REORDER: { UUID[] uuids = (UUID[]) intent.getSerializableExtra(EXTRA_APP_UUID); - mDeviceSupport.onAppReorder(uuids); + deviceSupport.onAppReorder(uuids); break; } case ACTION_INSTALL: Uri uri = intent.getParcelableExtra(EXTRA_URI); if (uri != null) { LOG.info("will try to install app/fw"); - mDeviceSupport.onInstallApp(uri); + deviceSupport.onInstallApp(uri); } break; case ACTION_SET_ALARMS: ArrayList alarms = (ArrayList) intent.getSerializableExtra(EXTRA_ALARMS); - mDeviceSupport.onSetAlarms(alarms); + deviceSupport.onSetAlarms(alarms); break; case ACTION_SET_REMINDERS: ArrayList reminders = (ArrayList) intent.getSerializableExtra(EXTRA_REMINDERS); - mDeviceSupport.onSetReminders(reminders); + deviceSupport.onSetReminders(reminders); break; case ACTION_SET_WORLD_CLOCKS: ArrayList clocks = (ArrayList) intent.getSerializableExtra(EXTRA_WORLD_CLOCKS); - mDeviceSupport.onSetWorldClocks(clocks); + deviceSupport.onSetWorldClocks(clocks); break; case ACTION_ENABLE_REALTIME_STEPS: { boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false); - mDeviceSupport.onEnableRealtimeSteps(enable); + deviceSupport.onEnableRealtimeSteps(enable); break; } case ACTION_ENABLE_HEARTRATE_SLEEP_SUPPORT: { boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false); - mDeviceSupport.onEnableHeartRateSleepSupport(enable); + deviceSupport.onEnableHeartRateSleepSupport(enable); break; } case ACTION_SET_HEARTRATE_MEASUREMENT_INTERVAL: { int seconds = intent.getIntExtra(EXTRA_INTERVAL_SECONDS, 0); - mDeviceSupport.onSetHeartRateMeasurementInterval(seconds); + deviceSupport.onSetHeartRateMeasurementInterval(seconds); break; } case ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT: { boolean enable = intent.getBooleanExtra(EXTRA_BOOLEAN_ENABLE, false); - mDeviceSupport.onEnableRealtimeHeartRateMeasurement(enable); + deviceSupport.onEnableRealtimeHeartRateMeasurement(enable); break; } case ACTION_SEND_CONFIGURATION: { String config = intent.getStringExtra(EXTRA_CONFIG); - mDeviceSupport.onSendConfiguration(config); + deviceSupport.onSendConfiguration(config); break; } case ACTION_READ_CONFIGURATION: { String config = intent.getStringExtra(EXTRA_CONFIG); - mDeviceSupport.onReadConfiguration(config); + deviceSupport.onReadConfiguration(config); break; } case ACTION_TEST_NEW_FUNCTION: { - mDeviceSupport.onTestNewFunction(); + deviceSupport.onTestNewFunction(); break; } case ACTION_SEND_WEATHER: { WeatherSpec weatherSpec = intent.getParcelableExtra(EXTRA_WEATHER); if (weatherSpec != null) { - mDeviceSupport.onSendWeather(weatherSpec); + deviceSupport.onSendWeather(weatherSpec); } break; } case ACTION_SET_LED_COLOR: int color = intent.getIntExtra(EXTRA_LED_COLOR, 0); if (color != 0) { - mDeviceSupport.onSetLedColor(color); + deviceSupport.onSetLedColor(color); } break; case ACTION_POWER_OFF: - mDeviceSupport.onPowerOff(); + deviceSupport.onPowerOff(); break; case ACTION_SET_FM_FREQUENCY: float frequency = intent.getFloatExtra(EXTRA_FM_FREQUENCY, -1); if (frequency != -1) { - mDeviceSupport.onSetFmFrequency(frequency); + deviceSupport.onSetFmFrequency(frequency); } break; case ACTION_SET_GPS_LOCATION: @@ -671,18 +850,79 @@ public class DeviceCommunicationService extends Service implements SharedPrefere * Disposes the current DeviceSupport instance (if any) and sets a new device support instance * (if not null). * - * @param deviceSupport + * @param deviceSupport deviceSupport to reokace/add */ - private void setDeviceSupport(@Nullable DeviceSupport deviceSupport) { - if (deviceSupport != mDeviceSupport && mDeviceSupport != null) { - mDeviceSupport.dispose(); - mDeviceSupport = null; - mGBDevice = null; - mCoordinator = null; + private void setDeviceSupport(GBDevice device, DeviceSupport deviceSupport) throws DeviceNotFoundException { + DeviceStruct deviceStruct = getDeviceStruct(device); + DeviceSupport cachedDeviceSupport = deviceStruct.getDeviceSupport(); + if (deviceSupport != cachedDeviceSupport && cachedDeviceSupport != null) { + cachedDeviceSupport.dispose(); + } + deviceStruct.setDeviceSupport(deviceSupport); + } + + private void removeDeviceSupport(GBDevice device) throws DeviceNotFoundException { + DeviceStruct struct = getDeviceStruct(device); + if(struct.getDeviceSupport() != null){ + struct.getDeviceSupport().dispose(); } - mDeviceSupport = deviceSupport; - mGBDevice = mDeviceSupport != null ? mDeviceSupport.getDevice() : null; - mCoordinator = mGBDevice != null ? DeviceHelper.getInstance().getCoordinator(mGBDevice) : null; + struct.setDeviceSupport(null); + } + + private DeviceStruct getDeviceStructOrNull(GBDevice device){ + DeviceStruct deviceStruct = null; + try { + deviceStruct = getDeviceStruct(device); + } catch (DeviceNotFoundException e) { + e.printStackTrace(); + } + return deviceStruct; + } + + public DeviceStruct getDeviceStruct(GBDevice device) throws DeviceNotFoundException { + if(device == null){ + throw new DeviceNotFoundException("null"); + } + for(DeviceStruct struct : deviceStructs){ + if(struct.getDevice().equals(device)){ + return struct; + } + } + throw new DeviceNotFoundException(device); + } + + public GBDevice getDeviceByAddress(String deviceAddress) throws DeviceNotFoundException { + if(deviceAddress == null){ + throw new DeviceNotFoundException(deviceAddress); + } + for(DeviceStruct struct : deviceStructs){ + if(struct.getDevice().getAddress().equals(deviceAddress)){ + return struct.getDevice(); + } + } + throw new DeviceNotFoundException(deviceAddress); + } + + public GBDevice getDeviceByAddressOrNull(String deviceAddress){ + GBDevice device = null; + try { + device = getDeviceByAddress(deviceAddress); + } catch (DeviceNotFoundException e) { + e.printStackTrace(); + } + return device; + } + + private DeviceSupport getDeviceSupport(GBDevice device) throws DeviceNotFoundException { + if(device == null){ + throw new DeviceNotFoundException("null"); + } + for(DeviceStruct struct : deviceStructs){ + if(struct.getDevice().equals(device)){ + return struct.getDeviceSupport(); + } + } + throw new DeviceNotFoundException(device); } private void start() { @@ -697,30 +937,49 @@ public class DeviceCommunicationService extends Service implements SharedPrefere return mStarted; } - private boolean isConnected() { - return mGBDevice != null && mGBDevice.isConnected(); + private boolean isDeviceConnected(GBDevice device) { + for(DeviceStruct struct : deviceStructs){ + if(struct.getDevice().equals(device) ){ + return struct.getDevice().isConnected(); + } + } + return false; } - private boolean isConnecting() { - return mGBDevice != null && mGBDevice.isConnecting(); + private boolean isDeviceConnecting(GBDevice device) { + for(DeviceStruct struct : deviceStructs){ + if(struct.getDevice().equals(device) ){ + return struct.getDevice().isConnecting(); + } + } + return false; } - private boolean isInitialized() { - return mGBDevice != null && mGBDevice.isInitialized(); + private boolean isDeviceInitialized(GBDevice device) { + for(DeviceStruct struct : deviceStructs){ + if(struct.getDevice().equals(device) ){ + return struct.getDevice().isInitialized(); + } + } + return false; } - private void setReceiversEnableState(boolean enable, boolean initialized, DeviceCoordinator coordinator) { + private void setReceiversEnableState(boolean enable, boolean initialized, FeatureSet features) { LOG.info("Setting broadcast receivers to: " + enable); - if (enable && initialized && coordinator != null && coordinator.supportsCalendarEvents()) { + if(enable && features == null){ + throw new RuntimeException("features cannot be null when enabling receivers"); + } + + if (enable && initialized && features.supportsCalendarEvents()) { if (mCalendarReceiver == null && getPrefs().getBoolean("enable_calendar_sync", true)) { if (!(GBApplication.isRunningMarshmallowOrLater() && ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) == PackageManager.PERMISSION_DENIED)) { IntentFilter calendarIntentFilter = new IntentFilter(); calendarIntentFilter.addAction("android.intent.action.PROVIDER_CHANGED"); calendarIntentFilter.addDataScheme("content"); calendarIntentFilter.addDataAuthority("com.android.calendar", null); - mCalendarReceiver = new CalendarReceiver(mGBDevice); + mCalendarReceiver = new CalendarReceiver(null); registerReceiver(mCalendarReceiver, calendarIntentFilter); } } @@ -756,7 +1015,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere mPebbleReceiver = new PebbleReceiver(); registerReceiver(mPebbleReceiver, new IntentFilter("com.getpebble.action.SEND_NOTIFICATION")); } - if (mMusicPlaybackReceiver == null && coordinator != null && coordinator.supportsMusicInfo()) { + if (mMusicPlaybackReceiver == null && features.supportsMusicInfo()) { mMusicPlaybackReceiver = new MusicPlaybackReceiver(); IntentFilter filter = new IntentFilter(); for (String action : mMusicActions) { @@ -771,10 +1030,6 @@ public class DeviceCommunicationService extends Service implements SharedPrefere filter.addAction("android.intent.action.TIMEZONE_CHANGED"); registerReceiver(mTimeChangeReceiver, filter); } - if (mBlueToothConnectReceiver == null) { - mBlueToothConnectReceiver = new BluetoothConnectReceiver(this); - registerReceiver(mBlueToothConnectReceiver, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED)); - } if (mBlueToothPairingRequestReceiver == null) { mBlueToothPairingRequestReceiver = new BluetoothPairingRequestReceiver(this); registerReceiver(mBlueToothPairingRequestReceiver, new IntentFilter(BluetoothDevice.ACTION_PAIRING_REQUEST)); @@ -790,7 +1045,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere } // Weather receivers - if ( coordinator != null && coordinator.supportsWeather()) { + if (features.supportsWeather()) { if (GBApplication.isRunningOreoOrLater()) { if (mLineageOsWeatherReceiver == null) { mLineageOsWeatherReceiver = new LineageOsWeatherReceiver(); @@ -818,7 +1073,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere } if (GBApplication.getPrefs().getBoolean("auto_fetch_enabled", false) && - coordinator != null && coordinator.supportsActivityDataFetching() && mGBAutoFetchReceiver == null) { + features.supportsActivityDataFetching() && mGBAutoFetchReceiver == null) { mGBAutoFetchReceiver = new GBAutoFetchReceiver(); registerReceiver(mGBAutoFetchReceiver, new IntentFilter("android.intent.action.USER_PRESENT")); } @@ -847,10 +1102,6 @@ public class DeviceCommunicationService extends Service implements SharedPrefere unregisterReceiver(mTimeChangeReceiver); mTimeChangeReceiver = null; } - if (mBlueToothConnectReceiver != null) { - unregisterReceiver(mBlueToothConnectReceiver); - mBlueToothConnectReceiver = null; - } if (mBlueToothPairingRequestReceiver != null) { unregisterReceiver(mBlueToothPairingRequestReceiver); @@ -900,7 +1151,15 @@ public class DeviceCommunicationService extends Service implements SharedPrefere LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver); setReceiversEnableState(false, false, null); // disable BroadcastReceivers - setDeviceSupport(null); + unregisterReceiver(mBlueToothConnectReceiver); + + for(GBDevice device : getGBDevices()){ + try { + removeDeviceSupport(device); + } catch (DeviceNotFoundException e) { + e.printStackTrace(); + } + } GB.removeNotification(GB.NOTIFICATION_ID, this); // need to do this because the updated notification won't be cancelled when service stops } @@ -911,10 +1170,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - if (GBPrefs.AUTO_RECONNECT.equals(key)) { - boolean autoReconnect = getGBPrefs().getAutoReconnect(); - if (mDeviceSupport != null) { - mDeviceSupport.setAutoReconnect(autoReconnect); + if (GBPrefs.DEVICE_AUTO_RECONNECT.equals(key)) { + for(DeviceStruct deviceStruct : deviceStructs){ + boolean autoReconnect = getGBPrefs().getAutoReconnect(deviceStruct.getDevice()); + deviceStruct.getDeviceSupport().setAutoReconnect(autoReconnect); } } if (GBPrefs.CHART_MAX_HEART_RATE.equals(key) || GBPrefs.CHART_MIN_HEART_RATE.equals(key)) { @@ -934,7 +1193,11 @@ public class DeviceCommunicationService extends Service implements SharedPrefere return GBApplication.getGBPrefs(); } - public GBDevice getGBDevice() { - return mGBDevice; + public GBDevice[] getGBDevices() { + GBDevice[] devices = new GBDevice[deviceStructs.size()]; + for(int i = 0; i < devices.length; i++){ + devices[i] = deviceStructs.get(i).getDevice(); + } + return devices; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java index 0172aef6c..e1c7c6cc5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java @@ -161,248 +161,170 @@ public class DeviceSupportFactory { } } + private ServiceDeviceSupport createServiceDeviceSupport(GBDevice device){ + switch (device.getType()) { + case PEBBLE: + return new ServiceDeviceSupport(new PebbleSupport()); + case MIBAND: + return new ServiceDeviceSupport(new MiBandSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING); + case MIBAND2: + return new ServiceDeviceSupport(new HuamiSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING); + case MIBAND3: + return new ServiceDeviceSupport(new MiBand3Support()); + case MIBAND4: + return new ServiceDeviceSupport(new MiBand4Support()); + case MIBAND5: + return new ServiceDeviceSupport(new MiBand5Support()); + case MIBAND6: + return new ServiceDeviceSupport(new MiBand6Support()); + case AMAZFITBIP: + return new ServiceDeviceSupport(new AmazfitBipSupport()); + case AMAZFITBIP_LITE: + return new ServiceDeviceSupport(new AmazfitBipLiteSupport()); + case AMAZFITBIPS: + return new ServiceDeviceSupport(new AmazfitBipSSupport()); + case AMAZFITBIPS_LITE: + return new ServiceDeviceSupport(new AmazfitBipSLiteSupport()); + case AMAZFITBIPU: + return new ServiceDeviceSupport(new AmazfitBipUSupport()); + case AMAZFITBIPUPRO: + return new ServiceDeviceSupport(new AmazfitBipUProSupport()); + case AMAZFITPOP: + return new ServiceDeviceSupport(new AmazfitPopSupport()); + case AMAZFITPOPPRO: + return new ServiceDeviceSupport(new AmazfitPopProSupport()); + case AMAZFITGTR: + return new ServiceDeviceSupport(new AmazfitGTRSupport()); + case AMAZFITGTR_LITE: + return new ServiceDeviceSupport(new AmazfitGTRLiteSupport()); + case AMAZFITGTR2: + return new ServiceDeviceSupport(new AmazfitGTR2Support()); + case ZEPP_E: + return new ServiceDeviceSupport(new ZeppESupport()); + case AMAZFITGTR2E: + return new ServiceDeviceSupport(new AmazfitGTR2eSupport()); + case AMAZFITTREX: + return new ServiceDeviceSupport(new AmazfitTRexSupport()); + case AMAZFITTREXPRO: + return new ServiceDeviceSupport(new AmazfitTRexProSupport()); + case AMAZFITGTS: + return new ServiceDeviceSupport(new AmazfitGTSSupport()); + case AMAZFITVERGEL: + return new ServiceDeviceSupport(new AmazfitVergeLSupport()); + case AMAZFITGTS2: + return new ServiceDeviceSupport(new AmazfitGTS2Support()); + case AMAZFITGTS2_MINI: + return new ServiceDeviceSupport(new AmazfitGTS2MiniSupport()); + case AMAZFITGTS2E: + return new ServiceDeviceSupport(new AmazfitGTS2eSupport()); + case AMAZFITCOR: + return new ServiceDeviceSupport(new AmazfitCorSupport()); + case AMAZFITCOR2: + return new ServiceDeviceSupport(new AmazfitCor2Support()); + case AMAZFITBAND5: + return new ServiceDeviceSupport(new AmazfitBand5Support()); + case AMAZFITX: + return new ServiceDeviceSupport(new AmazfitXSupport()); + case AMAZFITNEO: + return new ServiceDeviceSupport(new AmazfitNeoSupport()); + case VIBRATISSIMO: + return new ServiceDeviceSupport(new VibratissimoSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING); + case LIVEVIEW: + return new ServiceDeviceSupport(new LiveviewSupport()); + case HPLUS: + case MAKIBESF68: + case EXRIZUK8: + case Q8: + return new ServiceDeviceSupport(new HPlusSupport(device.getType())); + case NO1F1: + return new ServiceDeviceSupport(new No1F1Support()); + case TECLASTH30: + return new ServiceDeviceSupport(new TeclastH30Support()); + case XWATCH: + return new ServiceDeviceSupport(new XWatchSupport()); + case FOSSILQHYBRID: + return new ServiceDeviceSupport(new QHybridSupport()); + case ZETIME: + return new ServiceDeviceSupport(new ZeTimeDeviceSupport()); + case ID115: + return new ServiceDeviceSupport(new ID115Support()); + case WATCH9: + return new ServiceDeviceSupport(new Watch9DeviceSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING); + case WATCHXPLUS: + return new ServiceDeviceSupport(new WatchXPlusDeviceSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING); + case ROIDMI: + return new ServiceDeviceSupport(new RoidmiSupport()); + case ROIDMI3: + return new ServiceDeviceSupport(new RoidmiSupport()); + case Y5: + return new ServiceDeviceSupport(new Y5Support()); + case CASIOGB6900: + return new ServiceDeviceSupport(new CasioGB6900DeviceSupport()); + case CASIOGBX100: + return new ServiceDeviceSupport(new CasioGBX100DeviceSupport()); + case MISCALE2: + return new ServiceDeviceSupport(new MiScale2DeviceSupport()); + case BFH16: + return new ServiceDeviceSupport(new BFH16DeviceSupport()); + case MIJIA_LYWSD02: + return new ServiceDeviceSupport(new MijiaLywsd02Support()); + case MAKIBESHR3: + return new ServiceDeviceSupport(new MakibesHR3DeviceSupport()); + case ITAG: + return new ServiceDeviceSupport(new ITagSupport()); + case NUTMINI: + return new ServiceDeviceSupport(new NutSupport()); + case BANGLEJS: + return new ServiceDeviceSupport(new BangleJSDeviceSupport()); + case TLW64: + return new ServiceDeviceSupport(new TLW64Support()); + case PINETIME_JF: + return new ServiceDeviceSupport(new PineTimeJFSupport()); + case SG2: + return new ServiceDeviceSupport(new HPlusSupport(DeviceType.SG2)); + case LEFUN: + return new ServiceDeviceSupport(new LefunDeviceSupport()); + case SONY_SWR12: + return new ServiceDeviceSupport(new SonySWR12DeviceSupport()); + case WASPOS: + return new ServiceDeviceSupport(new WaspOSDeviceSupport()); + case SMAQ2OSS: + return new ServiceDeviceSupport(new SMAQ2OSSSupport()); + case UM25: + return new ServiceDeviceSupport(new UM25Support()); + case DOMYOS_T540: + return new ServiceDeviceSupport(new DomyosT540Support(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING); + case FITPRO: + return new ServiceDeviceSupport(new FitProDeviceSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING); + case NOTHING_EAR1: + return new ServiceDeviceSupport(new Ear1Support()); + case GALAXY_BUDS: + return new ServiceDeviceSupport(new GalaxyBudsDeviceSupport()); + case GALAXY_BUDS_LIVE: + return new ServiceDeviceSupport(new GalaxyBudsDeviceSupport()); + case GALAXY_BUDS_PRO: + return new ServiceDeviceSupport(new GalaxyBudsDeviceSupport(), ServiceDeviceSupport.Flags.BUSY_CHECKING); + case SONY_WH_1000XM3: + return new ServiceDeviceSupport(new SonyHeadphonesSupport()); + case SONY_WH_1000XM4: + return new ServiceDeviceSupport(new SonyHeadphonesSupport()); + case SONY_WF_SP800N: + return new ServiceDeviceSupport(new SonyHeadphonesSupport(), ServiceDeviceSupport.Flags.BUSY_CHECKING); + case SONY_WF_1000XM3: + return new ServiceDeviceSupport(new SonyHeadphonesSupport()); + case VESC_NRF: + case VESC_HM10: + return new ServiceDeviceSupport(new VescDeviceSupport(device.getType())); + case BOSE_QC35: + return new ServiceDeviceSupport(new QC35BaseSupport()); + } + return null; + } + private DeviceSupport createBTDeviceSupport(GBDevice gbDevice) throws GBException { if (mBtAdapter != null && mBtAdapter.isEnabled()) { - DeviceSupport deviceSupport = null; - try { - switch (gbDevice.getType()) { - case PEBBLE: - deviceSupport = new ServiceDeviceSupport(new PebbleSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MIBAND: - deviceSupport = new ServiceDeviceSupport(new MiBandSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MIBAND2: - deviceSupport = new ServiceDeviceSupport(new HuamiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MIBAND3: - deviceSupport = new ServiceDeviceSupport(new MiBand3Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MIBAND4: - deviceSupport = new ServiceDeviceSupport(new MiBand4Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MIBAND5: - deviceSupport = new ServiceDeviceSupport(new MiBand5Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MIBAND6: - deviceSupport = new ServiceDeviceSupport(new MiBand6Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITBIP: - deviceSupport = new ServiceDeviceSupport(new AmazfitBipSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITBIP_LITE: - deviceSupport = new ServiceDeviceSupport(new AmazfitBipLiteSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITBIPS: - deviceSupport = new ServiceDeviceSupport(new AmazfitBipSSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITBIPS_LITE: - deviceSupport = new ServiceDeviceSupport(new AmazfitBipSLiteSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITBIPU: - deviceSupport = new ServiceDeviceSupport(new AmazfitBipUSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITBIPUPRO: - deviceSupport = new ServiceDeviceSupport(new AmazfitBipUProSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITPOP: - deviceSupport = new ServiceDeviceSupport(new AmazfitPopSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITPOPPRO: - deviceSupport = new ServiceDeviceSupport(new AmazfitPopProSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITGTR: - deviceSupport = new ServiceDeviceSupport(new AmazfitGTRSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITGTR_LITE: - deviceSupport = new ServiceDeviceSupport(new AmazfitGTRLiteSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITGTR2: - deviceSupport = new ServiceDeviceSupport(new AmazfitGTR2Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case ZEPP_E: - deviceSupport = new ServiceDeviceSupport(new ZeppESupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITGTR2E: - deviceSupport = new ServiceDeviceSupport(new AmazfitGTR2eSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITTREX: - deviceSupport = new ServiceDeviceSupport(new AmazfitTRexSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITTREXPRO: - deviceSupport = new ServiceDeviceSupport(new AmazfitTRexProSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITGTS: - deviceSupport = new ServiceDeviceSupport(new AmazfitGTSSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITVERGEL: - deviceSupport = new ServiceDeviceSupport(new AmazfitVergeLSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITGTS2: - deviceSupport = new ServiceDeviceSupport(new AmazfitGTS2Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITGTS2_MINI: - deviceSupport = new ServiceDeviceSupport(new AmazfitGTS2MiniSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITGTS2E: - deviceSupport = new ServiceDeviceSupport(new AmazfitGTS2eSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITCOR: - deviceSupport = new ServiceDeviceSupport(new AmazfitCorSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITCOR2: - deviceSupport = new ServiceDeviceSupport(new AmazfitCor2Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITBAND5: - deviceSupport = new ServiceDeviceSupport(new AmazfitBand5Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITX: - deviceSupport = new ServiceDeviceSupport(new AmazfitXSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case AMAZFITNEO: - deviceSupport = new ServiceDeviceSupport(new AmazfitNeoSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case VIBRATISSIMO: - deviceSupport = new ServiceDeviceSupport(new VibratissimoSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case LIVEVIEW: - deviceSupport = new ServiceDeviceSupport(new LiveviewSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case HPLUS: - deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.HPLUS), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MAKIBESF68: - deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.MAKIBESF68), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case EXRIZUK8: - deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.EXRIZUK8), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case Q8: - deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.Q8), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case NO1F1: - deviceSupport = new ServiceDeviceSupport(new No1F1Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case TECLASTH30: - deviceSupport = new ServiceDeviceSupport(new TeclastH30Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case XWATCH: - deviceSupport = new ServiceDeviceSupport(new XWatchSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case FOSSILQHYBRID: - deviceSupport = new ServiceDeviceSupport(new QHybridSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case ZETIME: - deviceSupport = new ServiceDeviceSupport(new ZeTimeDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case ID115: - deviceSupport = new ServiceDeviceSupport(new ID115Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case WATCH9: - deviceSupport = new ServiceDeviceSupport(new Watch9DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case WATCHXPLUS: - deviceSupport = new ServiceDeviceSupport(new WatchXPlusDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case ROIDMI: - deviceSupport = new ServiceDeviceSupport(new RoidmiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case ROIDMI3: - deviceSupport = new ServiceDeviceSupport(new RoidmiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case Y5: - deviceSupport = new ServiceDeviceSupport(new Y5Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case CASIOGB6900: - deviceSupport = new ServiceDeviceSupport(new CasioGB6900DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case CASIOGBX100: - deviceSupport = new ServiceDeviceSupport(new CasioGBX100DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MISCALE2: - deviceSupport = new ServiceDeviceSupport(new MiScale2DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case BFH16: - deviceSupport = new ServiceDeviceSupport(new BFH16DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MIJIA_LYWSD02: - deviceSupport = new ServiceDeviceSupport(new MijiaLywsd02Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case MAKIBESHR3: - deviceSupport = new ServiceDeviceSupport(new MakibesHR3DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case ITAG: - deviceSupport = new ServiceDeviceSupport(new ITagSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case NUTMINI: - deviceSupport = new ServiceDeviceSupport(new NutSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case BANGLEJS: - deviceSupport = new ServiceDeviceSupport(new BangleJSDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case TLW64: - deviceSupport = new ServiceDeviceSupport(new TLW64Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case PINETIME_JF: - deviceSupport = new ServiceDeviceSupport(new PineTimeJFSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case SG2: - deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.SG2), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case LEFUN: - deviceSupport = new ServiceDeviceSupport(new LefunDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case SONY_SWR12: - deviceSupport = new ServiceDeviceSupport(new SonySWR12DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case WASPOS: - deviceSupport = new ServiceDeviceSupport(new WaspOSDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case SMAQ2OSS: - deviceSupport = new ServiceDeviceSupport(new SMAQ2OSSSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case UM25: - deviceSupport = new ServiceDeviceSupport(new UM25Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case DOMYOS_T540: - deviceSupport = new ServiceDeviceSupport(new DomyosT540Support(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case FITPRO: - deviceSupport = new ServiceDeviceSupport(new FitProDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case NOTHING_EAR1: - deviceSupport = new ServiceDeviceSupport(new Ear1Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case GALAXY_BUDS: - deviceSupport = new ServiceDeviceSupport(new GalaxyBudsDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case GALAXY_BUDS_LIVE: - deviceSupport = new ServiceDeviceSupport(new GalaxyBudsDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case GALAXY_BUDS_PRO: - deviceSupport = new ServiceDeviceSupport(new GalaxyBudsDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case SONY_WH_1000XM3: - deviceSupport = new ServiceDeviceSupport(new SonyHeadphonesSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case SONY_WH_1000XM4: - deviceSupport = new ServiceDeviceSupport(new SonyHeadphonesSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case SONY_WF_SP800N: - deviceSupport = new ServiceDeviceSupport(new SonyHeadphonesSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case SONY_WF_1000XM3: - deviceSupport = new ServiceDeviceSupport(new SonyHeadphonesSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case VESC_NRF: - case VESC_HM10: - deviceSupport = new ServiceDeviceSupport(new VescDeviceSupport(gbDevice.getType()), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - case BOSE_QC35: - deviceSupport = new ServiceDeviceSupport(new QC35BaseSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); - break; - } + DeviceSupport deviceSupport = createServiceDeviceSupport(gbDevice); if (deviceSupport != null) { deviceSupport.setContext(gbDevice, mBtAdapter, mContext); return deviceSupport; @@ -416,7 +338,7 @@ public class DeviceSupportFactory { private DeviceSupport createTCPDeviceSupport(GBDevice gbDevice) throws GBException { try { - DeviceSupport deviceSupport = new ServiceDeviceSupport(new PebbleSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING)); + DeviceSupport deviceSupport = new ServiceDeviceSupport(new PebbleSupport(), ServiceDeviceSupport.Flags.BUSY_CHECKING); deviceSupport.setContext(gbDevice, mBtAdapter, mContext); return deviceSupport; } catch (Exception e) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index fe6fffd30..2bc337687 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -27,6 +27,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Arrays; import java.util.EnumSet; import java.util.UUID; @@ -61,9 +62,14 @@ public class ServiceDeviceSupport implements DeviceSupport { private String lastNotificationKind; private final EnumSet flags; - public ServiceDeviceSupport(DeviceSupport delegate, EnumSet flags) { + public ServiceDeviceSupport(DeviceSupport delegate, Flags... flags) { this.delegate = delegate; - this.flags = flags; + this.flags = EnumSet.noneOf(Flags.class); + this.flags.addAll(Arrays.asList(flags)); + } + + public ServiceDeviceSupport(DeviceSupport delegate){ + this(delegate, Flags.BUSY_CHECKING); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipLiteFirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipLiteFirmwareInfo.java index 313b80941..76cf7b0dd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipLiteFirmwareInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbip/AmazfitBipLiteFirmwareInfo.java @@ -17,6 +17,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.amazfitbip; import java.util.HashMap; +import java.util.List; import java.util.Map; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -69,8 +70,8 @@ public class AmazfitBipLiteFirmwareInfo extends HuamiFirmwareInfo { if (searchString32BitAligned(bytes, "Amazfit Bip Lite")) { return HuamiFirmwareType.FIRMWARE; } - GBDevice device = GBApplication.app().getDeviceManager().getSelectedDevice(); - if (device != null) { + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for(GBDevice device : devices){ Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress())); if (prefs.getBoolean(DeviceSettingsPreferenceConst.PREF_RELAX_FIRMWARE_CHECKS, false)) { if (searchString32BitAligned(bytes, "Amazfit Bip")) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSFirmwareInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSFirmwareInfo.java index 7ee832f89..e31eb8d60 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSFirmwareInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/huami/amazfitbips/AmazfitBipSFirmwareInfo.java @@ -17,6 +17,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.amazfitbips; import java.util.HashMap; +import java.util.List; import java.util.Map; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -66,10 +67,8 @@ public class AmazfitBipSFirmwareInfo extends HuamiFirmwareInfo { @Override protected HuamiFirmwareType determineFirmwareType(byte[] bytes) { - - GBDevice device = GBApplication.app().getDeviceManager().getSelectedDevice(); - - if (device != null) { + List devices = GBApplication.app().getDeviceManager().getSelectedDevices(); + for (GBDevice device : devices) { if (device.getFirmwareVersion().startsWith("2.")) { //For devices on firmware 2.x it is a tonleasp device and needs a header which looks like Mi Band 4 if (ArrayUtils.equals(bytes, MiBand4FirmwareInfo.FW_HEADER, MiBand4FirmwareInfo.FW_HEADER_OFFSET)) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 628488c27..67df664ac 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -242,7 +242,7 @@ class PebbleIoThread extends GBDeviceIoThread { public void run() { mIsConnected = connect(); if (!mIsConnected) { - if (GBApplication.getGBPrefs().getAutoReconnect() && !mQuit) { + if (GBApplication.getGBPrefs().getAutoReconnect(getDevice()) && !mQuit) { gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT); gbDevice.sendDeviceUpdateIntent(getContext()); } @@ -406,7 +406,7 @@ class PebbleIoThread extends GBDeviceIoThread { enablePebbleKitSupport(false); - if (mQuit || !GBApplication.getGBPrefs().getAutoReconnect()) { + if (mQuit || !GBApplication.getGBPrefs().getAutoReconnect(getDevice())) { gbDevice.setState(GBDevice.State.NOT_CONNECTED); } else { gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qc35/QC35BaseSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qc35/QC35BaseSupport.java index 9aea24b28..e0aa4776e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qc35/QC35BaseSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qc35/QC35BaseSupport.java @@ -69,7 +69,7 @@ public class QC35BaseSupport extends AbstractSerialDeviceSupport { public boolean connect() { getDeviceProtocol(); getDeviceIOThread().start(); - getDevice().setBatteryThresholdPercent((short)15); + getDevice().setBatteryThresholdPercent((short)25); return true; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qc35/QC35Protocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qc35/QC35Protocol.java index c7f026a46..cdd4b5162 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qc35/QC35Protocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/qc35/QC35Protocol.java @@ -29,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSett import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; import nodomain.freeyourgadget.gadgetbridge.util.StringUtils; @@ -57,6 +58,7 @@ public class QC35Protocol extends GBDeviceProtocol { if(third == 0x03){ GBDeviceEventBatteryInfo batteryInfo = new GBDeviceEventBatteryInfo(); batteryInfo.level = data[0]; + batteryInfo.state = BatteryState.BATTERY_NORMAL; events.add(batteryInfo); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/AutoConnectIntervalReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/AutoConnectIntervalReceiver.java index 3e11e7c24..fe424c4e6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/AutoConnectIntervalReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/AutoConnectIntervalReceiver.java @@ -58,24 +58,31 @@ public class AutoConnectIntervalReceiver extends BroadcastReceiver { return; } - GBDevice gbDevice = service.getGBDevice(); - if (gbDevice == null) { - return; - } - - if (action.equals(DeviceManager.ACTION_DEVICES_CHANGED)) { - if (gbDevice.isInitialized()) { - LOG.info("will reset connection delay, device is initialized!"); - mDelay = 4; + GBDevice[] devices = service.getGBDevices(); + if (action.equals(DeviceManager.ACTION_DEVICES_CHANGED)){ + boolean scheduleAutoConnect = false; + boolean allDevicesInitialized = true; + for(GBDevice device : devices){ + if(!device.isInitialized()){ + allDevicesInitialized = false; + }else if(device.getState() == GBDevice.State.WAITING_FOR_RECONNECT){ + scheduleAutoConnect = true; + } } - else if (gbDevice.getState() == GBDevice.State.WAITING_FOR_RECONNECT) { + + if(allDevicesInitialized){ + LOG.info("will reset connection delay, all devices are initialized!"); + return; + } + if(scheduleAutoConnect){ scheduleReconnect(); } - } - else if (action.equals("GB_RECONNECT")) { - if (gbDevice.getState() == GBDevice.State.WAITING_FOR_RECONNECT) { - LOG.info("Will re-connect to " + gbDevice.getAddress() + "(" + gbDevice.getName() + ")"); - GBApplication.deviceService().connect(); + }else if (action.equals("GB_RECONNECT")){ + for(GBDevice device : devices){ + if(device.getState() == GBDevice.State.WAITING_FOR_RECONNECT) { + LOG.info("Will re-connect to " + device.getAddress() + "(" + device.getName() + ")"); + GBApplication.deviceService().connect(device); + } } } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/BondingUtil.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/BondingUtil.java index b7279f799..0dafb618f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/BondingUtil.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/BondingUtil.java @@ -180,7 +180,7 @@ public class BondingUtil { public static void connectThenComplete(BondingInterface bondingInterface, GBDevice device) { toast(bondingInterface.getContext(), bondingInterface.getContext().getString(R.string.discovery_trying_to_connect_to, device.getName()), Toast.LENGTH_SHORT, GB.INFO); // Disconnect when LE Pebble so that the user can manually initiate a connection - GBApplication.deviceService().disconnect(); + GBApplication.deviceService().disconnect(device); GBApplication.deviceService().connect(device, true); bondingInterface.onBondingComplete(true); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index 53b7c1c51..e55f0ee0b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -29,6 +29,8 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; +import android.text.Html; +import android.text.SpannableString; import android.widget.Toast; import androidx.annotation.NonNull; @@ -44,6 +46,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.List; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBEnvironment; @@ -145,44 +148,102 @@ public class GB { return pendingIntent; } - public static Notification createNotification(GBDevice device, Context context) { - String deviceName = device.getAliasOrName(); - String text = device.getStateString(); - if (device.getBatteryLevel() != GBDevice.BATTERY_UNKNOWN) { - text += ": " + context.getString(R.string.battery) + " " + device.getBatteryLevel() + "%"; - } - - boolean connected = device.isInitialized(); + public static Notification createNotification(List devices, Context context) { NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID); - builder.setContentTitle(deviceName) - .setTicker(deviceName + " - " + text) - .setContentText(text) - .setSmallIcon(connected ? device.getNotificationIconConnected() : device.getNotificationIconDisconnected()) - .setContentIntent(getContentIntent(context)) - .setShowWhen(false) - .setOngoing(true); + if(devices.size() == 0){ + builder.setContentTitle(context.getString(R.string.info_no_devices_connected)) + .setSmallIcon(R.drawable.ic_notification_disconnected) + .setContentIntent(getContentIntent(context)) + .setShowWhen(false) + .setOngoing(true); - if (!GBApplication.isRunningTwelveOrLater()) { - builder.setColor(context.getResources().getColor(R.color.accent)); - } + if (!GBApplication.isRunningTwelveOrLater()) { + builder.setColor(context.getResources().getColor(R.color.accent)); + } + }else if(devices.size() == 1) { + GBDevice device = devices.get(0); + String deviceName = device.getAliasOrName(); + String text = device.getStateString(); + if (device.getBatteryLevel() != GBDevice.BATTERY_UNKNOWN) { + text += ": " + context.getString(R.string.battery) + " " + device.getBatteryLevel() + "%"; + } - Intent deviceCommunicationServiceIntent = new Intent(context, DeviceCommunicationService.class); - if (connected) { - deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_DISCONNECT); - PendingIntent disconnectPendingIntent = PendingIntent.getService(context, 0, deviceCommunicationServiceIntent, PendingIntent.FLAG_ONE_SHOT); - builder.addAction(R.drawable.ic_notification_disconnected, context.getString(R.string.controlcenter_disconnect), disconnectPendingIntent); - if (GBApplication.isRunningLollipopOrLater() && DeviceHelper.getInstance().getCoordinator(device).supportsActivityDataFetching()) { //for some reason this fails on KK + boolean connected = device.isInitialized(); + builder.setContentTitle(deviceName) + .setTicker(deviceName + " - " + text) + .setContentText(text) + .setSmallIcon(connected ? device.getNotificationIconConnected() : device.getNotificationIconDisconnected()) + .setContentIntent(getContentIntent(context)) + .setShowWhen(false) + .setOngoing(true); + + if (!GBApplication.isRunningTwelveOrLater()) { + builder.setColor(context.getResources().getColor(R.color.accent)); + } + + Intent deviceCommunicationServiceIntent = new Intent(context, DeviceCommunicationService.class); + if (connected) { + deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_DISCONNECT); + PendingIntent disconnectPendingIntent = PendingIntent.getService(context, 0, deviceCommunicationServiceIntent, PendingIntent.FLAG_ONE_SHOT); + builder.addAction(R.drawable.ic_notification_disconnected, context.getString(R.string.controlcenter_disconnect), disconnectPendingIntent); + if (GBApplication.isRunningLollipopOrLater() && DeviceHelper.getInstance().getCoordinator(device).supportsActivityDataFetching()) { //for some reason this fails on KK + deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_FETCH_RECORDED_DATA); + deviceCommunicationServiceIntent.putExtra(EXTRA_RECORDED_DATA_TYPES, ActivityKind.TYPE_ACTIVITY); + PendingIntent fetchPendingIntent = PendingIntent.getService(context, 1, deviceCommunicationServiceIntent, PendingIntent.FLAG_ONE_SHOT); + builder.addAction(R.drawable.ic_refresh, context.getString(R.string.controlcenter_fetch_activity_data), fetchPendingIntent); + } + } else if (device.getState().equals(GBDevice.State.WAITING_FOR_RECONNECT) || device.getState().equals(GBDevice.State.NOT_CONNECTED)) { + deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_CONNECT); + deviceCommunicationServiceIntent.putExtra(GBDevice.EXTRA_DEVICE, device); + PendingIntent reconnectPendingIntent = PendingIntent.getService(context, 2, deviceCommunicationServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT); + builder.addAction(R.drawable.ic_notification, context.getString(R.string.controlcenter_connect), reconnectPendingIntent); + } + }else{ + StringBuilder contentText = new StringBuilder(); + boolean isConnected = true; + boolean anyDeviceSupportesActivityDataFetching = false; + for(GBDevice device : devices){ + if(!device.isInitialized()){ + isConnected = false; + } + + anyDeviceSupportesActivityDataFetching |= DeviceHelper.getInstance().getCoordinator(device).supportsActivityDataFetching(); + + String deviceName = device.getAliasOrName(); + String text = device.getStateString(); + if (device.getBatteryLevel() != GBDevice.BATTERY_UNKNOWN) { + text += ": " + context.getString(R.string.battery) + " " + device.getBatteryLevel() + "%"; + } + contentText.append(deviceName).append(" (").append(text).append(")
"); + } + + SpannableString formated = new SpannableString( + Html.fromHtml(contentText.substring(0, contentText.length() - 4)) // cut away last
+ ); + + String title = context.getString(R.string.info_connected_count, devices.size()); + + builder.setContentTitle(title) + .setContentText(formated) + .setSmallIcon(isConnected ? R.drawable.ic_notification : R.drawable.ic_notification_disconnected) + .setContentIntent(getContentIntent(context)) + .setStyle(new NotificationCompat.BigTextStyle().bigText(formated).setBigContentTitle(title)) + .setShowWhen(false) + .setOngoing(true); + + if (!GBApplication.isRunningTwelveOrLater()) { + builder.setColor(context.getResources().getColor(R.color.accent)); + } + + if (GBApplication.isRunningLollipopOrLater() && anyDeviceSupportesActivityDataFetching) { //for some reason this fails on KK + Intent deviceCommunicationServiceIntent = new Intent(context, DeviceCommunicationService.class); deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_FETCH_RECORDED_DATA); deviceCommunicationServiceIntent.putExtra(EXTRA_RECORDED_DATA_TYPES, ActivityKind.TYPE_ACTIVITY); PendingIntent fetchPendingIntent = PendingIntent.getService(context, 1, deviceCommunicationServiceIntent, PendingIntent.FLAG_ONE_SHOT); builder.addAction(R.drawable.ic_refresh, context.getString(R.string.controlcenter_fetch_activity_data), fetchPendingIntent); } - } else if (device.getState().equals(GBDevice.State.WAITING_FOR_RECONNECT) || device.getState().equals(GBDevice.State.NOT_CONNECTED)) { - deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_CONNECT); - deviceCommunicationServiceIntent.putExtra(GBDevice.EXTRA_DEVICE, device); - PendingIntent reconnectPendingIntent = PendingIntent.getService(context, 2, deviceCommunicationServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT); - builder.addAction(R.drawable.ic_notification, context.getString(R.string.controlcenter_connect), reconnectPendingIntent); } + if (GBApplication.isRunningLollipopOrLater()) { builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC); } @@ -220,8 +281,8 @@ public class GB { return builder.build(); } - public static void updateNotification(GBDevice device, Context context) { - Notification notification = createNotification(device, context); + public static void updateNotification(List devices, Context context) { + Notification notification = createNotification(devices, context); notify(NOTIFICATION_ID, notification, context); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java index ebaecc0c2..d848a8de0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GBPrefs.java @@ -19,6 +19,7 @@ package nodomain.freeyourgadget.gadgetbridge.util; import android.Manifest; import android.content.Context; +import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.location.Criteria; import android.location.Location; @@ -33,6 +34,7 @@ import java.util.Date; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; public class GBPrefs { // Since this class must not log to slf4j, we use plain android.util.Log @@ -41,7 +43,8 @@ public class GBPrefs { public static final String PACKAGE_BLACKLIST = "package_blacklist"; public static final String PACKAGE_PEBBLEMSG_BLACKLIST = "package_pebblemsg_blacklist"; public static final String CALENDAR_BLACKLIST = "calendar_blacklist"; - public static final String AUTO_RECONNECT = "general_autocreconnect"; + public static final String DEVICE_AUTO_RECONNECT = "prefs_key_device_auto_reconnect"; + public static final String DEVICE_CONNECT_BACK = "prefs_key_device_reconnect_on_acl"; private static final String AUTO_START = "general_autostartonboot"; public static final String AUTO_EXPORT_ENABLED = "auto_export_enabled"; public static final String AUTO_EXPORT_LOCATION = "auto_export_location"; @@ -67,8 +70,9 @@ public class GBPrefs { mPrefs = prefs; } - public boolean getAutoReconnect() { - return mPrefs.getBoolean(AUTO_RECONNECT, AUTO_RECONNECT_DEFAULT); + public boolean getAutoReconnect(GBDevice device) { + SharedPreferences deviceSpecificPreferences = GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()); + return deviceSpecificPreferences.getBoolean(DEVICE_AUTO_RECONNECT, AUTO_RECONNECT_DEFAULT); } public boolean getAutoStart() { diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 06f9c1833..86bcf6289 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1628,4 +1628,7 @@ Über Bangle.js Gadgetbridge Fitness-App-Tracking umschalten Text als Bitmaps + + %d Geräte verbunden + Keine Geräte verbunden \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 469facb0b..20d95325d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1666,4 +1666,7 @@ Used for starting/stopping GPS track recording in external fitness app. pre-setting position to %s Light up on new notification + + no devices connected + %d devices connected diff --git a/app/src/main/res/xml/devicesettings_reconnect_bl_classic.xml b/app/src/main/res/xml/devicesettings_reconnect_bl_classic.xml new file mode 100644 index 000000000..4bc3cd59d --- /dev/null +++ b/app/src/main/res/xml/devicesettings_reconnect_bl_classic.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/devicesettings_reconnect_ble.xml b/app/src/main/res/xml/devicesettings_reconnect_ble.xml new file mode 100644 index 000000000..194be53e0 --- /dev/null +++ b/app/src/main/res/xml/devicesettings_reconnect_ble.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 1b2ab2787..53eae5040 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -17,7 +17,9 @@ android:layout="@layout/preference_checkbox" android:defaultValue="false" android:key="general_autocreconnect" - android:title="@string/pref_title_general_autoreconnect" /> + android:title="@string/pref_title_general_autoreconnect" + android:enabled="false" + android:summary="setting has been moved to device specific settings"/>