diff --git a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java index 872962bec..870374c80 100644 --- a/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java +++ b/GBDaoGenerator/src/nodomain/freeyourgadget/gadgetbridge/daogen/GBDaoGenerator.java @@ -43,7 +43,7 @@ public class GBDaoGenerator { public static void main(String[] args) throws Exception { - Schema schema = new Schema(34, MAIN_PACKAGE + ".entities"); + Schema schema = new Schema(35, MAIN_PACKAGE + ".entities"); Entity userAttributes = addUserAttributes(schema); Entity user = addUserInfo(schema, userAttributes); @@ -613,6 +613,7 @@ public class GBDaoGenerator { Property deviceId = batteryLevel.addLongProperty("deviceId").primaryKey().notNull().getProperty(); batteryLevel.addToOne(device, deviceId); batteryLevel.addIntProperty("level").notNull(); + batteryLevel.addIntProperty("batteryIndex").notNull().primaryKey();; return batteryLevel; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/BatteryInfoActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/BatteryInfoActivity.java index c8dcd6eb0..2a23e55af 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/BatteryInfoActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/BatteryInfoActivity.java @@ -22,11 +22,13 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; -public class BatteryInfoActivity extends AbstractGBActivity { +public class +BatteryInfoActivity extends AbstractGBActivity { private static final Logger LOG = LoggerFactory.getLogger(BatteryInfoActivity.class); GBDevice gbDevice; private int timeFrom; private int timeTo; + private int batteryIndex = 0; @Override protected void onCreate(Bundle savedInstanceState) { @@ -42,6 +44,7 @@ public class BatteryInfoActivity extends AbstractGBActivity { Bundle bundle = intent.getExtras(); if (bundle != null) { gbDevice = bundle.getParcelable(GBDevice.EXTRA_DEVICE); + batteryIndex = bundle.getInt("BATTERY_INDEX", 0); } else { throw new IllegalArgumentException("Must provide a device when invoking this activity"); } @@ -55,7 +58,7 @@ public class BatteryInfoActivity extends AbstractGBActivity { timeTo = (int) (System.currentTimeMillis() / 1000); - batteryInfoChartFragment.setDateAndGetData(gbDevice, timeFrom, timeTo); + batteryInfoChartFragment.setDateAndGetData(gbDevice, batteryIndex, timeFrom, timeTo); TextView battery_status_device_name_text = (TextView) findViewById(R.id.battery_status_device_name); TextView battery_status_battery_voltage = (TextView) findViewById(R.id.battery_status_battery_voltage); @@ -105,7 +108,7 @@ public class BatteryInfoActivity extends AbstractGBActivity { battery_status_time_span_text.setText(text); battery_status_date_from_text.setText(DateTimeUtils.formatDate(new Date(timeFrom * 1000L))); battery_status_date_to_text.setText(DateTimeUtils.formatDate(new Date(timeTo * 1000L))); - batteryInfoChartFragment.setDateAndGetData(gbDevice, timeFrom, timeTo); + batteryInfoChartFragment.setDateAndGetData(gbDevice, batteryIndex, timeFrom, timeTo); } @@ -141,7 +144,7 @@ public class BatteryInfoActivity extends AbstractGBActivity { battery_status_time_span_seekbar.setProgress(0); battery_status_time_span_seekbar.setProgress(1); - batteryInfoChartFragment.setDateAndGetData(gbDevice, timeFrom, timeTo); + batteryInfoChartFragment.setDateAndGetData(gbDevice, batteryIndex, timeFrom, timeTo); } }, currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE)).show(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/BatteryInfoChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/BatteryInfoChartFragment.java index b01b9a515..e41a0f42d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/BatteryInfoChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/BatteryInfoChartFragment.java @@ -74,11 +74,13 @@ public class BatteryInfoChartFragment extends AbstractGBFragment { private int startTime; private int endTime; private GBDevice gbDevice; + private int batteryIndex; - public void setDateAndGetData(GBDevice gbDevice, long startTime, long endTime) { + public void setDateAndGetData(GBDevice gbDevice, int batteryIndex, long startTime, long endTime) { this.startTime = (int) startTime; this.endTime = (int) endTime; this.gbDevice = gbDevice; + this.batteryIndex = batteryIndex; try { createRefreshTask("Visualizing data", getActivity()).execute(); } catch (Exception e) { @@ -174,12 +176,13 @@ public class BatteryInfoChartFragment extends AbstractGBFragment { yAxisRight.setTextColor(CHART_TEXT_COLOR); } - private List getBatteryLevels(DBHandler db, GBDevice device, int tsFrom, int tsTo) { + private List getBatteryLevels(DBHandler db, GBDevice device, int batteryIndex, int tsFrom, int tsTo) { BatteryLevelDao batteryLevelDao = db.getDaoSession().getBatteryLevelDao(); Device dbDevice = DBHelper.findDevice(device, db.getDaoSession()); QueryBuilder qb = batteryLevelDao.queryBuilder(); qb.where(BatteryLevelDao.Properties.DeviceId.eq(dbDevice.getId())).orderAsc(BatteryLevelDao.Properties.Timestamp); + qb.where(BatteryLevelDao.Properties.BatteryIndex.eq(batteryIndex)); qb.where(BatteryLevelDao.Properties.Timestamp.gt(tsFrom)); qb.where(BatteryLevelDao.Properties.Timestamp.lt(tsTo)); @@ -215,7 +218,7 @@ public class BatteryInfoChartFragment extends AbstractGBFragment { @Override protected void doInBackground(DBHandler handler) { - List samples = getBatteryLevels(handler, gbDevice, startTime, endTime); + List samples = getBatteryLevels(handler, gbDevice, batteryIndex, startTime, endTime); DefaultBatteryChartsData dcd = null; try { dcd = fill_dcd(samples); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java index f61d2107e..395b8d704 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapterv2.java @@ -144,38 +144,51 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter 0 ? View.VISIBLE : View.GONE); + holder.batteryStatusBox1.setVisibility(coordinator.getBatteryCount() > 1 ? View.VISIBLE : View.GONE); + holder.batteryStatusBox2.setVisibility(coordinator.getBatteryCount() > 2 ? View.VISIBLE : View.GONE); + + LinearLayout[] batteryStatusBoxes = {holder.batteryStatusBox0, holder.batteryStatusBox1, holder.batteryStatusBox2}; + TextView[] batteryStatusLabels = {holder.batteryStatusLabel0, holder.batteryStatusLabel1, holder.batteryStatusLabel2}; + ImageView[] batteryIcons = {holder.batteryIcon0, holder.batteryIcon1, holder.batteryIcon2}; + + for (int battery = 0; battery < coordinator.getBatteryCount(); battery++) { + + int batteryLevel = device.getBatteryLevel(battery); + float batteryVoltage = device.getBatteryVoltage(battery); + BatteryState batteryState = device.getBatteryState(); + + if (batteryLevel != GBDevice.BATTERY_UNKNOWN) { + batteryStatusBoxes[battery].setVisibility(View.VISIBLE); + batteryStatusLabels[battery].setText(device.getBatteryLevel(battery) + "%"); + if (BatteryState.BATTERY_CHARGING.equals(batteryState) || + BatteryState.BATTERY_CHARGING_FULL.equals(batteryState)) { + batteryIcons[battery].setImageLevel(device.getBatteryLevel(battery) + 100); + } else { + batteryIcons[battery].setImageLevel(device.getBatteryLevel(battery)); + } + } else if (BatteryState.NO_BATTERY.equals(batteryState) && batteryVoltage != GBDevice.BATTERY_UNKNOWN) { + batteryStatusBoxes[battery].setVisibility(View.VISIBLE); + batteryStatusLabels[battery].setText(String.format(Locale.getDefault(), "%.2f", batteryVoltage)); + batteryIcons[battery].setImageLevel(200); } - } else if (BatteryState.NO_BATTERY.equals(batteryState) && batteryVoltage != GBDevice.BATTERY_UNKNOWN) { - holder.batteryStatusBox.setVisibility(View.VISIBLE); - holder.batteryStatusLabel.setText(String.format(Locale.getDefault(), "%.2f", batteryVoltage)); - holder.batteryIcon.setImageLevel(200); + final int finalBattery = battery; + batteryStatusBoxes[battery].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent startIntent; + startIntent = new Intent(context, BatteryInfoActivity.class); + startIntent.putExtra(GBDevice.EXTRA_DEVICE, device); + startIntent.putExtra("BATTERY_INDEX", finalBattery); + context.startActivity(startIntent); + } + } + ); + } - holder.batteryStatusBox.setOnClickListener(new View.OnClickListener() - - { - @Override - public void onClick(View v) { - Intent startIntent; - startIntent = new Intent(context, BatteryInfoActivity.class); - startIntent.putExtra(GBDevice.EXTRA_DEVICE, device); - context.startActivity(startIntent); - } - } - ); - holder.heartRateStatusBox.setVisibility((device.isInitialized() && coordinator.supportsRealtimeData() && coordinator.supportsHeartRateMeasurement(device)) ? View.VISIBLE : View.GONE); if (parent.getContext() instanceof ControlCenterv2) { ActivitySample sample = ((ControlCenterv2) parent.getContext()).getCurrentHRSample(); @@ -590,9 +603,15 @@ public class GBDeviceAdapterv2 extends RecyclerView.Adapter. */ +package nodomain.freeyourgadget.gadgetbridge.database.schema; + +import android.database.sqlite.SQLiteDatabase; + +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; +import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao; +import nodomain.freeyourgadget.gadgetbridge.entities.BatteryLevelDao; + +public class GadgetbridgeUpdate_35 implements DBUpdateScript { + @Override + public void upgradeSchema(SQLiteDatabase db) { + if (!DBHelper.existsColumn(BatteryLevelDao.TABLENAME, BatteryLevelDao.Properties.BatteryIndex.columnName, db)) { + String MOVE_DATA_TO_TEMP_TABLE = "ALTER TABLE battery_level RENAME TO battery_levels_temp;"; + db.execSQL(MOVE_DATA_TO_TEMP_TABLE); + + String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS \"BATTERY_LEVEL\" (\"TIMESTAMP\" INTEGER NOT NULL ," + + "\"DEVICE_ID\" INTEGER NOT NULL ,\"LEVEL\" INTEGER NOT NULL ,\"BATTERY_INDEX\" INTEGER NOT NULL ," + + "PRIMARY KEY (\"TIMESTAMP\" ,\"DEVICE_ID\" ,\"BATTERY_INDEX\" ) ON CONFLICT REPLACE) WITHOUT ROWID;"; + db.execSQL(CREATE_TABLE); + + String MIGATE_DATA = "insert into " + BatteryLevelDao.TABLENAME + + " (" + BatteryLevelDao.Properties.Timestamp.columnName + "," + + BatteryLevelDao.Properties.DeviceId.columnName + "," + + BatteryLevelDao.Properties.BatteryIndex.columnName + "," + + BatteryLevelDao.Properties.Level.columnName + ") " + + " select Timestamp, Device_ID, 0, Level from battery_levels_temp;"; + db.execSQL(MIGATE_DATA); + + String DROP_TEMP_TABLE = "drop table if exists battery_levels_temp"; + db.execSQL(DROP_TEMP_TABLE); + } + } + + @Override + public void downgradeSchema(SQLiteDatabase db) { + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventBatteryInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventBatteryInfo.java index 67af0c41d..a664d7032 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventBatteryInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventBatteryInfo.java @@ -24,7 +24,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; public class GBDeviceEventBatteryInfo extends GBDeviceEvent { public GregorianCalendar lastChargeTime = null; public BatteryState state = BatteryState.UNKNOWN; - public short level = 50; + public int batteryIndex = 0; + public int level = 50; public int numCharges = -1; public float voltage = -1f; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java index df3202a54..335a55d38 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/AbstractDeviceCoordinator.java @@ -246,4 +246,9 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator { public Class getCalibrationActivity() { return null; } + + @Override + public int getBatteryCount() { + return 1; + } //multiple battery support, default is 1, maximum is 3, 0 will disable the battery in UI } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java index ce7c246fa..a8c8ee0fa 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/DeviceCoordinator.java @@ -348,4 +348,12 @@ public interface DeviceCoordinator { */ String[] getSupportedLanguageSettings(GBDevice device); + /** + * + * Multiple battery support: Indicates how many batteries the device has. + * 1 is default, 3 is maximum at the moment (as per UI layout) + * 0 will disable the battery from the UI + */ + int getBatteryCount(); + } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java index 96426f4f5..d2f0827cb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java @@ -17,6 +17,8 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.impl; +import static nodomain.freeyourgadget.gadgetbridge.model.BatteryState.UNKNOWN; + import android.content.Context; import android.content.Intent; import android.os.Parcel; @@ -75,10 +77,13 @@ public class GBDevice implements Parcelable { private String mFirmwareVersion2; private String mModel; private State mState = State.NOT_CONNECTED; - private short mBatteryLevel = BATTERY_UNKNOWN; - private float mBatteryVoltage = BATTERY_UNKNOWN; + + // multiple battery support: at this point we support up to three batteries + private int[] mBatteryLevel = {BATTERY_UNKNOWN, BATTERY_UNKNOWN, BATTERY_UNKNOWN}; + private float[] mBatteryVoltage = {BATTERY_UNKNOWN, BATTERY_UNKNOWN, BATTERY_UNKNOWN}; private short mBatteryThresholdPercent = BATTERY_THRESHOLD_PERCENT; - private BatteryState mBatteryState; + private BatteryState[] mBatteryState = {UNKNOWN, UNKNOWN, UNKNOWN}; + private short mRssi = RSSI_UNKNOWN; private String mBusyTask; private List mDeviceInfos; @@ -111,9 +116,10 @@ public class GBDevice implements Parcelable { mFirmwareVersion2 = in.readString(); mModel = in.readString(); mState = State.values()[in.readInt()]; - mBatteryLevel = (short) in.readInt(); + mBatteryLevel = in.createIntArray(); + mBatteryVoltage = in.createFloatArray(); mBatteryThresholdPercent = (short) in.readInt(); - mBatteryState = (BatteryState) in.readSerializable(); + mBatteryState = ordinalsToEnums(in.createIntArray()); mRssi = (short) in.readInt(); mBusyTask = in.readString(); mDeviceInfos = in.readArrayList(getClass().getClassLoader()); @@ -136,9 +142,10 @@ public class GBDevice implements Parcelable { dest.writeString(mFirmwareVersion2); dest.writeString(mModel); dest.writeInt(mState.ordinal()); - dest.writeInt(mBatteryLevel); + dest.writeIntArray(mBatteryLevel); + dest.writeFloatArray(mBatteryVoltage); dest.writeInt(mBatteryThresholdPercent); - dest.writeSerializable(mBatteryState); + dest.writeIntArray(enumsToOrdinals(mBatteryState)); dest.writeInt(mRssi); dest.writeString(mBusyTask); dest.writeList(mDeviceInfos); @@ -154,6 +161,22 @@ public class GBDevice implements Parcelable { } } + private int[] enumsToOrdinals(BatteryState[] arrayEnum) { + int[] ordinals = new int[arrayEnum.length]; + for (int i = 0; i < arrayEnum.length; i++) { + ordinals[i] = arrayEnum[i].ordinal(); + } + return ordinals; + } + + private BatteryState[] ordinalsToEnums(int[] arrayInt){ + BatteryState[] enums = new BatteryState[arrayInt.length]; + for(int i = 0; i= 0 && batteryLevel <= 100) || batteryLevel == BATTERY_UNKNOWN) { - mBatteryLevel = batteryLevel; + mBatteryLevel[index] = batteryLevel; } else { LOG.error("Battery level musts be within range 0-100: " + batteryLevel); } } public void setBatteryVoltage(float batteryVoltage) { + setBatteryVoltage(batteryVoltage, 0); + } + + + public void setBatteryVoltage(float batteryVoltage, int index) { if (batteryVoltage >= 0 || batteryVoltage == BATTERY_UNKNOWN) { - mBatteryVoltage = batteryVoltage; + mBatteryVoltage[index] = batteryVoltage; } else { LOG.error("Battery voltage must be > 0: " + batteryVoltage); } @@ -497,15 +538,27 @@ public class GBDevice implements Parcelable { * @return the battery voltage, or -1 if unknown */ public float getBatteryVoltage() { - return mBatteryVoltage; + return getBatteryVoltage(0); + } + + public float getBatteryVoltage(int index) { + return mBatteryVoltage[index]; } public BatteryState getBatteryState() { - return mBatteryState; + return getBatteryState(0); + } + + public BatteryState getBatteryState(int index) { + return mBatteryState[index]; } public void setBatteryState(BatteryState mBatteryState) { - this.mBatteryState = mBatteryState; + setBatteryState(mBatteryState, 0); + } + + public void setBatteryState(BatteryState mBatteryState, int index) { + this.mBatteryState[index] = mBatteryState; } public short getBatteryThresholdPercent() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java index fbcf0202c..e5cc1b6ee 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java @@ -395,9 +395,9 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { protected void handleGBDeviceEvent(GBDeviceEventBatteryInfo deviceEvent) { Context context = getContext(); LOG.info("Got BATTERY_INFO device event"); - gbDevice.setBatteryLevel(deviceEvent.level); + gbDevice.setBatteryLevel(deviceEvent.level, deviceEvent.batteryIndex); gbDevice.setBatteryState(deviceEvent.state); - gbDevice.setBatteryVoltage(deviceEvent.voltage); + gbDevice.setBatteryVoltage(deviceEvent.voltage, deviceEvent.batteryIndex); if (deviceEvent.level == GBDevice.BATTERY_UNKNOWN) { // no level available, just "high" or "low" @@ -455,6 +455,7 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { int ts = (int) (System.currentTimeMillis() / 1000); BatteryLevel batteryLevel = new BatteryLevel(); batteryLevel.setTimestamp(ts); + batteryLevel.setBatteryIndex(deviceEvent.batteryIndex); batteryLevel.setDevice(device); batteryLevel.setLevel(deviceEvent.level); handler.getDaoSession().getBatteryLevelDao().insert(batteryLevel); diff --git a/app/src/main/res/layout/device_itemv2.xml b/app/src/main/res/layout/device_itemv2.xml index b0cf02db3..0081b9b64 100644 --- a/app/src/main/res/layout/device_itemv2.xml +++ b/app/src/main/res/layout/device_itemv2.xml @@ -161,6 +161,67 @@ + + + + + + + + + + + + + + + + +