mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-03 17:02:13 +01:00
multi-device-support (#2526)
this PR aims to add device for multiple connected devices at once. A lot of stuff already works, some things need to be done: - [x] change DeviceCommunicationService to hold multiple devices and supports - [x] implement connect / disconnect logic - [x] widgets, not really suited for multiple devices, so far - [x] change the notification to show multiple devices - [ ] change GBDeviceService#onFindDevice and similar API functions to target individual devices, not all connected. - [x] move auto-reconnect setting to device settings - [x] fix music event crash - [x] work out behaviour when pressing "connect" from notification - [ ] handle service crashes - [ ] suit coordinator methods for multiple devices of same kind - [x] change ACL_CONNECTED receiver to connect to devices that are not currently registered in DeviceCommunicationService - [ ] adjust after-boot auto-connection logic - [ ] fix hanging device support. Device says disconnected, GB says connected - [x] firmware updater doesn't work My attempt to make onFindDevice work was to change the arguments to ```EventHandler#onFindDevice(GBDevice device, boolean start)```. The Problem is that this forces the device-specific implementations to also accept GBDevice as an argument. Co-authored-by: Daniel Dakhno <dakhnod@gmail.com> Co-authored-by: Andreas Shimokawa <shimokawa@fsfe.org> Co-authored-by: dakhnod <dakhnod@gmail.com> Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/2526 Co-authored-by: dakhnod <dakhnod@noreply.codeberg.org> Co-committed-by: dakhnod <dakhnod@noreply.codeberg.org>
This commit is contained in:
parent
e683a5bc56
commit
4a8523f790
@ -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,8 +273,11 @@ public class DebugActivity extends AbstractGBActivity {
|
||||
|
||||
if (context instanceof GBApplication) {
|
||||
GBApplication gbApp = (GBApplication) context;
|
||||
final GBDevice device = gbApp.getDeviceManager().getSelectedDevice();
|
||||
if (device != null) {
|
||||
final List<GBDevice> 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) {
|
||||
@ -283,15 +287,14 @@ public class DebugActivity extends AbstractGBActivity {
|
||||
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<GBDevice> devices = gbApp.getDeviceManager().getSelectedDevices();
|
||||
for(GBDevice device : devices){
|
||||
GBApplication.deleteDeviceSpecificSharedPrefs(device.getAddress());
|
||||
}
|
||||
}
|
||||
|
@ -214,6 +214,19 @@ public class FwAppInstallerActivity extends AbstractGBActivity implements Instal
|
||||
} else {
|
||||
setInfoText(getString(R.string.installer_activity_wait_while_determining_status));
|
||||
|
||||
List<GBDevice> 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,13 +258,16 @@ public class FwAppInstallerActivity extends AbstractGBActivity implements Instal
|
||||
List<DeviceCoordinator> allCoordinators = DeviceHelper.getInstance().getAllCoordinators();
|
||||
List<DeviceCoordinator> sortedCoordinators = new ArrayList<>(allCoordinators.size());
|
||||
|
||||
GBDevice connectedDevice = deviceManager.getSelectedDevice();
|
||||
if (connectedDevice != null && connectedDevice.isConnected()) {
|
||||
List<GBDevice> 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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -154,7 +154,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
||||
public boolean onLongClick(View v) {
|
||||
if (device.getState() != GBDevice.State.NOT_CONNECTED) {
|
||||
showTransientSnackbar(R.string.controlcenter_snackbar_disconnecting);
|
||||
GBApplication.deviceService().disconnect();
|
||||
GBApplication.deviceService().disconnect(device);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -261,7 +261,7 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter<GBDeviceAdapterv2.Vi
|
||||
);
|
||||
|
||||
//device specific settings
|
||||
holder.deviceSpecificSettingsView.setVisibility(coordinator.getSupportedDeviceSpecificSettings(device) != null ? View.VISIBLE : View.GONE);
|
||||
holder.deviceSpecificSettingsView.setVisibility(coordinator.getSupportedDeviceSpecificConnectionSettings() != null ? View.VISIBLE : View.GONE);
|
||||
holder.deviceSpecificSettingsView.setOnClickListener(new View.OnClickListener()
|
||||
|
||||
{
|
||||
|
@ -0,0 +1,8 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices;
|
||||
|
||||
public abstract class AbstractBLClassicDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
@Override
|
||||
public ConnectionType getConnectionType() {
|
||||
return ConnectionType.BL_CLASSIC;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices;
|
||||
|
||||
public abstract class AbstractBLEDeviceCoordinator extends AbstractDeviceCoordinator{
|
||||
@Override
|
||||
public ConnectionType getConnectionType() {
|
||||
return ConnectionType.BLE;
|
||||
}
|
||||
}
|
@ -26,6 +26,7 @@ import android.bluetooth.le.ScanFilter;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@ -37,6 +38,7 @@ import java.util.Collections;
|
||||
import de.greenrobot.dao.query.QueryBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
@ -61,6 +63,11 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
return getSupportedType(candidate).isSupported();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionType getConnectionType() {
|
||||
return ConnectionType.BOTH;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(GBDevice device) {
|
||||
return getDeviceType().equals(device.getType());
|
||||
@ -86,7 +93,7 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
public void deleteDevice(final GBDevice gbDevice) throws GBException {
|
||||
LOG.info("will try to delete device: " + gbDevice.getName());
|
||||
if (gbDevice.isConnected() || gbDevice.isConnecting()) {
|
||||
GBApplication.deviceService().disconnect();
|
||||
GBApplication.deviceService().disconnect(gbDevice);
|
||||
}
|
||||
Prefs prefs = getPrefs();
|
||||
|
||||
@ -258,9 +265,24 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedDeviceSpecificConnectionSettings() {
|
||||
int[] settings = new int[0];
|
||||
ConnectionType connectionType = getConnectionType();
|
||||
|
||||
if(connectionType.usesBluetoothLE()){
|
||||
settings = ArrayUtils.insert(0, settings, R.xml.devicesettings_reconnect_ble);
|
||||
}
|
||||
if(connectionType.usesBluetoothClassic()){
|
||||
settings = ArrayUtils.insert(0, settings, R.xml.devicesettings_reconnect_bl_classic);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
|
||||
return null;
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,6 +77,27 @@ public interface DeviceCoordinator {
|
||||
*/
|
||||
int BONDING_STYLE_LAZY = 4;
|
||||
|
||||
enum ConnectionType{
|
||||
BLE(false, true),
|
||||
BL_CLASSIC(true, false),
|
||||
BOTH(true, true)
|
||||
;
|
||||
boolean usesBluetoothClassic, usesBluetoothLE;
|
||||
|
||||
ConnectionType(boolean usesBluetoothClassic, boolean usesBluetoothLE) {
|
||||
this.usesBluetoothClassic = usesBluetoothClassic;
|
||||
this.usesBluetoothLE = usesBluetoothLE;
|
||||
}
|
||||
|
||||
public boolean usesBluetoothLE(){
|
||||
return usesBluetoothLE;
|
||||
}
|
||||
|
||||
public boolean usesBluetoothClassic(){
|
||||
return usesBluetoothClassic;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this coordinator handles the given candidate.
|
||||
* Returns the supported device type for the given candidate or
|
||||
@ -88,6 +109,13 @@ public interface DeviceCoordinator {
|
||||
@NonNull
|
||||
DeviceType getSupportedType(GBDeviceCandidate candidate);
|
||||
|
||||
/**
|
||||
* Returns the type of connection, Classic of BLE
|
||||
*
|
||||
* @return ConnectionType
|
||||
*/
|
||||
ConnectionType getConnectionType();
|
||||
|
||||
/**
|
||||
* Checks whether this coordinator handles the given candidate.
|
||||
*
|
||||
@ -363,6 +391,13 @@ public interface DeviceCoordinator {
|
||||
*/
|
||||
boolean supportsUnicodeEmojis();
|
||||
|
||||
/**
|
||||
* Returns device specific settings related to connection
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
int[] getSupportedDeviceSpecificConnectionSettings();
|
||||
|
||||
/**
|
||||
* Indicates which device specific settings the device supports (not per device type or family, but unique per device).
|
||||
*/
|
||||
|
@ -67,7 +67,7 @@ public class DeviceManager {
|
||||
* This allows direct access to the list from ListAdapters.
|
||||
*/
|
||||
private final List<GBDevice> deviceList = new ArrayList<>();
|
||||
private GBDevice selectedDevice = null;
|
||||
private List<GBDevice> 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<GBDevice> getSelectedDevices() {
|
||||
return selectedDevices;
|
||||
}
|
||||
|
||||
private void notifyDevicesChanged() {
|
||||
|
@ -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<GBDevice> 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<GBDevice> 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;
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -54,13 +54,18 @@ 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");
|
||||
}
|
||||
String installedAppsJson = selected.getDeviceInfo("INSTALLED_APPS").getDetails();
|
||||
List<GBDevice> 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("cant get installed apps");
|
||||
throw new RuntimeException("can't get installed apps");
|
||||
}
|
||||
JSONArray apps = new JSONArray(installedAppsJson);
|
||||
appNames = new String[apps.length()];
|
||||
@ -68,11 +73,15 @@ public class AppsManagementActivity extends AbstractGBActivity {
|
||||
appNames[i] = apps.getString(i);
|
||||
}
|
||||
appsListView.setAdapter(new AppsListAdapter(this, appNames));
|
||||
} catch (Exception e) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
toast(e.getMessage());
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException("Device not connected");
|
||||
}
|
||||
|
||||
class AppsListAdapter extends ArrayAdapter<String> {
|
||||
|
@ -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<GBDevice> 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;
|
||||
|
@ -303,13 +303,15 @@ 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 {
|
||||
List<GBDevice> 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() {
|
||||
int timeOffset = prefs.getInt("QHYBRID_TIME_OFFSET", 0);
|
||||
|
@ -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,7 +170,10 @@ 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();
|
||||
List<GBDevice> 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) {
|
||||
@ -182,6 +187,9 @@ public class HRConfigActivity extends AbstractGBActivity {
|
||||
GB.toast(getString(R.string.fossil_hr_warning_firmware_too_new), Toast.LENGTH_LONG, GB.INFO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
|
@ -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<GBDevice> devices = GBApplication.app().getDeviceManager().getSelectedDevices();
|
||||
for(GBDevice device : devices){
|
||||
if(isFossilHybrid(device) && device.getState() == GBDevice.State.INITIALIZED){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -129,12 +136,15 @@ 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<GBDevice> 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 false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAlarmSlotCount() {
|
||||
@ -268,15 +278,20 @@ public class QHybridCoordinator extends AbstractDeviceCoordinator {
|
||||
}
|
||||
|
||||
private boolean isHybridHR() {
|
||||
GBDevice connectedDevice = GBApplication.app().getDeviceManager().getSelectedDevice();
|
||||
if (connectedDevice != null) {
|
||||
return connectedDevice.getName().startsWith("Hybrid HR");
|
||||
List<GBDevice> 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();
|
||||
List<GBDevice> 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()) {
|
||||
@ -284,6 +299,13 @@ public class QHybridCoordinator extends AbstractDeviceCoordinator {
|
||||
return new Version(firmware);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isFossilHybrid(GBDevice device){
|
||||
return device.getType() == DeviceType.FOSSILQHYBRID;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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) {
|
||||
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();
|
||||
GBApplication.deviceService().connect(gbDevice);
|
||||
}
|
||||
|
||||
private GBDevice getKnownDeviceByAddressOrNull(String deviceAddress){
|
||||
List<GBDevice> knownDevices = GBApplication.app().getDeviceManager().getDevices();
|
||||
for(GBDevice device : knownDevices){
|
||||
if(device.getAddress().equals(deviceAddress)){
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -47,13 +47,15 @@ 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;
|
||||
}
|
||||
|
||||
GBDevice gbDevice = null;
|
||||
try {
|
||||
gbDevice = service.getDeviceByAddress(device.getAddress());
|
||||
|
||||
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(gbDevice);
|
||||
try {
|
||||
if (coordinator.getBondingStyle() == DeviceCoordinator.BONDING_STYLE_NONE) {
|
||||
@ -63,5 +65,8 @@ public class BluetoothPairingRequestReceiver extends BroadcastReceiver {
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Could not abort pairing request process");
|
||||
}
|
||||
} catch (DeviceCommunicationService.DeviceNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
@ -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<GBDevice> 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");
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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<DeviceStruct> 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;
|
||||
}
|
||||
@ -250,18 +353,43 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
String action = intent.getAction();
|
||||
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,18 +470,38 @@ 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);
|
||||
}
|
||||
|
||||
DeviceStruct registeredStruct = getDeviceStructOrNull(gbDevice);
|
||||
if(registeredStruct != null){
|
||||
boolean deviceAlreadyConnected = isDeviceConnecting(registeredStruct.getDevice()) || isDeviceConnected(registeredStruct.getDevice());
|
||||
if(deviceAlreadyConnected){
|
||||
break;
|
||||
}
|
||||
try {
|
||||
removeDeviceSupport(gbDevice);
|
||||
} catch (DeviceNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}else{
|
||||
registeredStruct = new DeviceStruct();
|
||||
registeredStruct.setDevice(gbDevice);
|
||||
registeredStruct.setCoordinator(DeviceHelper.getInstance().getCoordinator(gbDevice));
|
||||
deviceStructs.add(registeredStruct);
|
||||
}
|
||||
|
||||
if (gbDevice != null && !isConnecting() && !isConnected()) {
|
||||
setDeviceSupport(null);
|
||||
try {
|
||||
DeviceSupport deviceSupport = mFactory.createDeviceSupport(gbDevice);
|
||||
if (deviceSupport != null) {
|
||||
setDeviceSupport(deviceSupport);
|
||||
setDeviceSupport(gbDevice, deviceSupport);
|
||||
if (firstTime) {
|
||||
deviceSupport.connectFirstTime();
|
||||
} else {
|
||||
@ -361,18 +513,30 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
}
|
||||
} catch (Exception e) {
|
||||
GB.toast(this, getString(R.string.cannot_connect, e.getMessage()), Toast.LENGTH_SHORT, GB.ERROR, e);
|
||||
setDeviceSupport(null);
|
||||
}
|
||||
} else if (mGBDevice != null) {
|
||||
// send an update at least
|
||||
mGBDevice.sendDeviceUpdateIntent(this);
|
||||
|
||||
for(DeviceStruct struct2 : deviceStructs){
|
||||
struct2.getDevice().sendDeviceUpdateIntent(this);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (mDeviceSupport == null || mGBDevice == null) {
|
||||
LOG.warn("device support:" + mDeviceSupport + ", device: " + mGBDevice + ", aborting");
|
||||
GBDevice targetedDevice = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
ArrayList<GBDevice> targetedDevices = new ArrayList<>();
|
||||
if(targetedDevice != null){
|
||||
targetedDevices.add(targetedDevice);
|
||||
}else{
|
||||
handleAction(intent, action, prefs);
|
||||
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<NotificationSpec.Action>) 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: {
|
||||
if(!getDeviceCoordinator(device).supportsActivityDataFetching()){
|
||||
break;
|
||||
}
|
||||
int dataTypes = intent.getIntExtra(EXTRA_RECORDED_DATA_TYPES, 0);
|
||||
mDeviceSupport.onFetchRecordedData(dataTypes);
|
||||
deviceSupport.onFetchRecordedData(dataTypes);
|
||||
break;
|
||||
}
|
||||
case ACTION_DISCONNECT: {
|
||||
mDeviceSupport.dispose();
|
||||
if (mGBDevice != null) {
|
||||
mGBDevice.setState(GBDevice.State.NOT_CONNECTED);
|
||||
mGBDevice.sendDeviceUpdateIntent(this);
|
||||
case ACTION_DISCONNECT:
|
||||
try {
|
||||
removeDeviceSupport(device);
|
||||
} catch (DeviceNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
setReceiversEnableState(false, false, null);
|
||||
mGBDevice = null;
|
||||
mDeviceSupport = null;
|
||||
mCoordinator = null;
|
||||
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<? extends Alarm> alarms = (ArrayList<? extends Alarm>) intent.getSerializableExtra(EXTRA_ALARMS);
|
||||
mDeviceSupport.onSetAlarms(alarms);
|
||||
deviceSupport.onSetAlarms(alarms);
|
||||
break;
|
||||
case ACTION_SET_REMINDERS:
|
||||
ArrayList<? extends Reminder> reminders = (ArrayList<? extends Reminder>) intent.getSerializableExtra(EXTRA_REMINDERS);
|
||||
mDeviceSupport.onSetReminders(reminders);
|
||||
deviceSupport.onSetReminders(reminders);
|
||||
break;
|
||||
case ACTION_SET_WORLD_CLOCKS:
|
||||
ArrayList<? extends WorldClock> clocks = (ArrayList<? extends WorldClock>) 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();
|
||||
}
|
||||
mDeviceSupport = deviceSupport;
|
||||
mGBDevice = mDeviceSupport != null ? mDeviceSupport.getDevice() : null;
|
||||
mCoordinator = mGBDevice != null ? DeviceHelper.getInstance().getCoordinator(mGBDevice) : null;
|
||||
deviceStruct.setDeviceSupport(deviceSupport);
|
||||
}
|
||||
|
||||
private void removeDeviceSupport(GBDevice device) throws DeviceNotFoundException {
|
||||
DeviceStruct struct = getDeviceStruct(device);
|
||||
if(struct.getDeviceSupport() != null){
|
||||
struct.getDeviceSupport().dispose();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -161,248 +161,170 @@ public class DeviceSupportFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private DeviceSupport createBTDeviceSupport(GBDevice gbDevice) throws GBException {
|
||||
if (mBtAdapter != null && mBtAdapter.isEnabled()) {
|
||||
DeviceSupport deviceSupport = null;
|
||||
|
||||
try {
|
||||
switch (gbDevice.getType()) {
|
||||
private ServiceDeviceSupport createServiceDeviceSupport(GBDevice device){
|
||||
switch (device.getType()) {
|
||||
case PEBBLE:
|
||||
deviceSupport = new ServiceDeviceSupport(new PebbleSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new PebbleSupport());
|
||||
case MIBAND:
|
||||
deviceSupport = new ServiceDeviceSupport(new MiBandSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new MiBandSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
case MIBAND2:
|
||||
deviceSupport = new ServiceDeviceSupport(new HuamiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new HuamiSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
case MIBAND3:
|
||||
deviceSupport = new ServiceDeviceSupport(new MiBand3Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new MiBand3Support());
|
||||
case MIBAND4:
|
||||
deviceSupport = new ServiceDeviceSupport(new MiBand4Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new MiBand4Support());
|
||||
case MIBAND5:
|
||||
deviceSupport = new ServiceDeviceSupport(new MiBand5Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new MiBand5Support());
|
||||
case MIBAND6:
|
||||
deviceSupport = new ServiceDeviceSupport(new MiBand6Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new MiBand6Support());
|
||||
case AMAZFITBIP:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitBipSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitBipSupport());
|
||||
case AMAZFITBIP_LITE:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitBipLiteSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitBipLiteSupport());
|
||||
case AMAZFITBIPS:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitBipSSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitBipSSupport());
|
||||
case AMAZFITBIPS_LITE:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitBipSLiteSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitBipSLiteSupport());
|
||||
case AMAZFITBIPU:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitBipUSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitBipUSupport());
|
||||
case AMAZFITBIPUPRO:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitBipUProSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitBipUProSupport());
|
||||
case AMAZFITPOP:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitPopSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitPopSupport());
|
||||
case AMAZFITPOPPRO:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitPopProSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitPopProSupport());
|
||||
case AMAZFITGTR:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitGTRSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitGTRSupport());
|
||||
case AMAZFITGTR_LITE:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitGTRLiteSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitGTRLiteSupport());
|
||||
case AMAZFITGTR2:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitGTR2Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitGTR2Support());
|
||||
case ZEPP_E:
|
||||
deviceSupport = new ServiceDeviceSupport(new ZeppESupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new ZeppESupport());
|
||||
case AMAZFITGTR2E:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitGTR2eSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitGTR2eSupport());
|
||||
case AMAZFITTREX:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitTRexSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitTRexSupport());
|
||||
case AMAZFITTREXPRO:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitTRexProSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitTRexProSupport());
|
||||
case AMAZFITGTS:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitGTSSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitGTSSupport());
|
||||
case AMAZFITVERGEL:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitVergeLSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitVergeLSupport());
|
||||
case AMAZFITGTS2:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitGTS2Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitGTS2Support());
|
||||
case AMAZFITGTS2_MINI:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitGTS2MiniSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitGTS2MiniSupport());
|
||||
case AMAZFITGTS2E:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitGTS2eSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitGTS2eSupport());
|
||||
case AMAZFITCOR:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitCorSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitCorSupport());
|
||||
case AMAZFITCOR2:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitCor2Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitCor2Support());
|
||||
case AMAZFITBAND5:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitBand5Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitBand5Support());
|
||||
case AMAZFITX:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitXSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitXSupport());
|
||||
case AMAZFITNEO:
|
||||
deviceSupport = new ServiceDeviceSupport(new AmazfitNeoSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new AmazfitNeoSupport());
|
||||
case VIBRATISSIMO:
|
||||
deviceSupport = new ServiceDeviceSupport(new VibratissimoSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new VibratissimoSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
case LIVEVIEW:
|
||||
deviceSupport = new ServiceDeviceSupport(new LiveviewSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new LiveviewSupport());
|
||||
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;
|
||||
return new ServiceDeviceSupport(new HPlusSupport(device.getType()));
|
||||
case NO1F1:
|
||||
deviceSupport = new ServiceDeviceSupport(new No1F1Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new No1F1Support());
|
||||
case TECLASTH30:
|
||||
deviceSupport = new ServiceDeviceSupport(new TeclastH30Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new TeclastH30Support());
|
||||
case XWATCH:
|
||||
deviceSupport = new ServiceDeviceSupport(new XWatchSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new XWatchSupport());
|
||||
case FOSSILQHYBRID:
|
||||
deviceSupport = new ServiceDeviceSupport(new QHybridSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new QHybridSupport());
|
||||
case ZETIME:
|
||||
deviceSupport = new ServiceDeviceSupport(new ZeTimeDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new ZeTimeDeviceSupport());
|
||||
case ID115:
|
||||
deviceSupport = new ServiceDeviceSupport(new ID115Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new ID115Support());
|
||||
case WATCH9:
|
||||
deviceSupport = new ServiceDeviceSupport(new Watch9DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new Watch9DeviceSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
case WATCHXPLUS:
|
||||
deviceSupport = new ServiceDeviceSupport(new WatchXPlusDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new WatchXPlusDeviceSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
case ROIDMI:
|
||||
deviceSupport = new ServiceDeviceSupport(new RoidmiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new RoidmiSupport());
|
||||
case ROIDMI3:
|
||||
deviceSupport = new ServiceDeviceSupport(new RoidmiSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new RoidmiSupport());
|
||||
case Y5:
|
||||
deviceSupport = new ServiceDeviceSupport(new Y5Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new Y5Support());
|
||||
case CASIOGB6900:
|
||||
deviceSupport = new ServiceDeviceSupport(new CasioGB6900DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new CasioGB6900DeviceSupport());
|
||||
case CASIOGBX100:
|
||||
deviceSupport = new ServiceDeviceSupport(new CasioGBX100DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new CasioGBX100DeviceSupport());
|
||||
case MISCALE2:
|
||||
deviceSupport = new ServiceDeviceSupport(new MiScale2DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new MiScale2DeviceSupport());
|
||||
case BFH16:
|
||||
deviceSupport = new ServiceDeviceSupport(new BFH16DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new BFH16DeviceSupport());
|
||||
case MIJIA_LYWSD02:
|
||||
deviceSupport = new ServiceDeviceSupport(new MijiaLywsd02Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new MijiaLywsd02Support());
|
||||
case MAKIBESHR3:
|
||||
deviceSupport = new ServiceDeviceSupport(new MakibesHR3DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new MakibesHR3DeviceSupport());
|
||||
case ITAG:
|
||||
deviceSupport = new ServiceDeviceSupport(new ITagSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new ITagSupport());
|
||||
case NUTMINI:
|
||||
deviceSupport = new ServiceDeviceSupport(new NutSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new NutSupport());
|
||||
case BANGLEJS:
|
||||
deviceSupport = new ServiceDeviceSupport(new BangleJSDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new BangleJSDeviceSupport());
|
||||
case TLW64:
|
||||
deviceSupport = new ServiceDeviceSupport(new TLW64Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new TLW64Support());
|
||||
case PINETIME_JF:
|
||||
deviceSupport = new ServiceDeviceSupport(new PineTimeJFSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new PineTimeJFSupport());
|
||||
case SG2:
|
||||
deviceSupport = new ServiceDeviceSupport(new HPlusSupport(DeviceType.SG2), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new HPlusSupport(DeviceType.SG2));
|
||||
case LEFUN:
|
||||
deviceSupport = new ServiceDeviceSupport(new LefunDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new LefunDeviceSupport());
|
||||
case SONY_SWR12:
|
||||
deviceSupport = new ServiceDeviceSupport(new SonySWR12DeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new SonySWR12DeviceSupport());
|
||||
case WASPOS:
|
||||
deviceSupport = new ServiceDeviceSupport(new WaspOSDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new WaspOSDeviceSupport());
|
||||
case SMAQ2OSS:
|
||||
deviceSupport = new ServiceDeviceSupport(new SMAQ2OSSSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new SMAQ2OSSSupport());
|
||||
case UM25:
|
||||
deviceSupport = new ServiceDeviceSupport(new UM25Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new UM25Support());
|
||||
case DOMYOS_T540:
|
||||
deviceSupport = new ServiceDeviceSupport(new DomyosT540Support(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new DomyosT540Support(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
case FITPRO:
|
||||
deviceSupport = new ServiceDeviceSupport(new FitProDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new FitProDeviceSupport(), ServiceDeviceSupport.Flags.THROTTLING, ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
case NOTHING_EAR1:
|
||||
deviceSupport = new ServiceDeviceSupport(new Ear1Support(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new Ear1Support());
|
||||
case GALAXY_BUDS:
|
||||
deviceSupport = new ServiceDeviceSupport(new GalaxyBudsDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new GalaxyBudsDeviceSupport());
|
||||
case GALAXY_BUDS_LIVE:
|
||||
deviceSupport = new ServiceDeviceSupport(new GalaxyBudsDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new GalaxyBudsDeviceSupport());
|
||||
case GALAXY_BUDS_PRO:
|
||||
deviceSupport = new ServiceDeviceSupport(new GalaxyBudsDeviceSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new GalaxyBudsDeviceSupport(), ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
case SONY_WH_1000XM3:
|
||||
deviceSupport = new ServiceDeviceSupport(new SonyHeadphonesSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new SonyHeadphonesSupport());
|
||||
case SONY_WH_1000XM4:
|
||||
deviceSupport = new ServiceDeviceSupport(new SonyHeadphonesSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new SonyHeadphonesSupport());
|
||||
case SONY_WF_SP800N:
|
||||
deviceSupport = new ServiceDeviceSupport(new SonyHeadphonesSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new SonyHeadphonesSupport(), ServiceDeviceSupport.Flags.BUSY_CHECKING);
|
||||
case SONY_WF_1000XM3:
|
||||
deviceSupport = new ServiceDeviceSupport(new SonyHeadphonesSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new SonyHeadphonesSupport());
|
||||
case VESC_NRF:
|
||||
case VESC_HM10:
|
||||
deviceSupport = new ServiceDeviceSupport(new VescDeviceSupport(gbDevice.getType()), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new VescDeviceSupport(device.getType()));
|
||||
case BOSE_QC35:
|
||||
deviceSupport = new ServiceDeviceSupport(new QC35BaseSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
|
||||
break;
|
||||
return new ServiceDeviceSupport(new QC35BaseSupport());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DeviceSupport createBTDeviceSupport(GBDevice gbDevice) throws GBException {
|
||||
if (mBtAdapter != null && mBtAdapter.isEnabled()) {
|
||||
try {
|
||||
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) {
|
||||
|
@ -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> flags;
|
||||
|
||||
public ServiceDeviceSupport(DeviceSupport delegate, EnumSet<Flags> 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
|
||||
|
@ -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<GBDevice> 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")) {
|
||||
|
@ -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<GBDevice> 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)) {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -58,24 +58,31 @@ public class AutoConnectIntervalReceiver extends BroadcastReceiver {
|
||||
return;
|
||||
}
|
||||
|
||||
GBDevice gbDevice = service.getGBDevice();
|
||||
if (gbDevice == null) {
|
||||
return;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (action.equals(DeviceManager.ACTION_DEVICES_CHANGED)) {
|
||||
if (gbDevice.isInitialized()) {
|
||||
LOG.info("will reset connection delay, device is initialized!");
|
||||
mDelay = 4;
|
||||
if(allDevicesInitialized){
|
||||
LOG.info("will reset connection delay, all devices are initialized!");
|
||||
return;
|
||||
}
|
||||
else if (gbDevice.getState() == GBDevice.State.WAITING_FOR_RECONNECT) {
|
||||
if(scheduleAutoConnect){
|
||||
scheduleReconnect();
|
||||
}
|
||||
}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);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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,7 +148,20 @@ public class GB {
|
||||
return pendingIntent;
|
||||
}
|
||||
|
||||
public static Notification createNotification(GBDevice device, Context context) {
|
||||
public static Notification createNotification(List<GBDevice> devices, Context context) {
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID);
|
||||
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));
|
||||
}
|
||||
}else if(devices.size() == 1) {
|
||||
GBDevice device = devices.get(0);
|
||||
String deviceName = device.getAliasOrName();
|
||||
String text = device.getStateString();
|
||||
if (device.getBatteryLevel() != GBDevice.BATTERY_UNKNOWN) {
|
||||
@ -153,7 +169,6 @@ public class GB {
|
||||
}
|
||||
|
||||
boolean connected = device.isInitialized();
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID);
|
||||
builder.setContentTitle(deviceName)
|
||||
.setTicker(deviceName + " - " + text)
|
||||
.setContentText(text)
|
||||
@ -183,6 +198,52 @@ public class GB {
|
||||
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(")<br>");
|
||||
}
|
||||
|
||||
SpannableString formated = new SpannableString(
|
||||
Html.fromHtml(contentText.substring(0, contentText.length() - 4)) // cut away last <br>
|
||||
);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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<GBDevice> devices, Context context) {
|
||||
Notification notification = createNotification(devices, context);
|
||||
notify(NOTIFICATION_ID, notification, context);
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -1628,4 +1628,7 @@
|
||||
<string name="about_activity_title_banglejs_nopebble">Über Bangle.js Gadgetbridge</string>
|
||||
<string name="pref_device_action_fitness_app_control_toggle">Fitness-App-Tracking umschalten</string>
|
||||
<string name="pref_title_banglejs_text_bitmap">Text als Bitmaps</string>
|
||||
|
||||
<string name="info_connected_count">%d Geräte verbunden</string>
|
||||
<string name="info_no_devices_connected">Keine Geräte verbunden</string>
|
||||
</resources>
|
@ -1666,4 +1666,7 @@
|
||||
<string name="pref_summary_opentracks_packagename">Used for starting/stopping GPS track recording in external fitness app.</string>
|
||||
<string name="watchface_dialog_pre_setting_position">pre-setting position to %s</string>
|
||||
<string name="watchface_setting_light_up_on_notification">Light up on new notification</string>
|
||||
|
||||
<string name="info_no_devices_connected">no devices connected</string>
|
||||
<string name="info_connected_count">%d devices connected</string>
|
||||
</resources>
|
||||
|
11
app/src/main/res/xml/devicesettings_reconnect_bl_classic.xml
Normal file
11
app/src/main/res/xml/devicesettings_reconnect_bl_classic.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory
|
||||
android:title="Connection over Bluetooth classic" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="prefs_key_device_reconnect_on_acl"
|
||||
android:title="connect on connection from device"
|
||||
android:summary="establish a connection when connection is initiated by device, like headphones"
|
||||
android:layout="@layout/preference_checkbox" />
|
||||
</PreferenceScreen>
|
11
app/src/main/res/xml/devicesettings_reconnect_ble.xml
Normal file
11
app/src/main/res/xml/devicesettings_reconnect_ble.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<PreferenceCategory
|
||||
android:title="Connection over BLE" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="prefs_key_device_auto_reconnect"
|
||||
android:title="auto-reconnect to device"
|
||||
android:summary="proactively try to connect to device periodically"
|
||||
android:layout="@layout/preference_checkbox" />
|
||||
</PreferenceScreen>
|
@ -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"/>
|
||||
<CheckBoxPreference
|
||||
android:layout="@layout/preference_checkbox"
|
||||
android:defaultValue="true"
|
||||
|
Loading…
Reference in New Issue
Block a user