diff --git a/LICENSE.artwork b/LICENSE.artwork index 3d8766be..2d71011a 100644 --- a/LICENSE.artwork +++ b/LICENSE.artwork @@ -8,3 +8,6 @@ Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-N Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0): "GET IT ON F-Droid" button by Laura Kalbag. Source: https://ind.ie/about/blog/f-droid-button/ + +Creative Commons Attribution 3.0 Unported license (CC BY-3.0): + ic_notification_battery_low.png by Picol.org. Source: https://commons.wikimedia.org/wiki/File:Battery_1_Picol_icon.svg diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java index e671360f..8cee27dc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java @@ -13,6 +13,7 @@ import java.util.List; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; public class GBDeviceAdapter extends ArrayAdapter { @@ -59,6 +60,11 @@ public class GBDeviceAdapter extends ArrayAdapter { short batteryLevel = device.getBatteryLevel(); if (batteryLevel != GBDevice.BATTERY_UNKNOWN) { batteryStatusLabel.setText("BAT: " + device.getBatteryLevel() + "%"); + BatteryState batteryState = device.getBatteryState(); + if (BatteryState.BATTERY_CHARGING.equals(batteryState) || + BatteryState.BATTERY_CHARGING_FULL.equals(batteryState)) { + batteryStatusLabel.append(" CHG"); + } } else { batteryStatusLabel.setText(""); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEvent.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEvent.java index 0aa03f81..5a8246a7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEvent.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEvent.java @@ -15,6 +15,7 @@ public abstract class GBDeviceEvent { SLEEP_MONITOR_RES, SCREENSHOT, DISMISS_NOTIFICATION, + BATTERY_INFO } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventBatteryInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventBatteryInfo.java new file mode 100644 index 00000000..9371000d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventBatteryInfo.java @@ -0,0 +1,24 @@ +package nodomain.freeyourgadget.gadgetbridge.deviceevents; + + +import java.util.GregorianCalendar; + +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 numCharges = -1; + + public GBDeviceEventBatteryInfo() { + eventClass = EventClass.BATTERY_INFO; + } + + public boolean extendedInfoAvailable() { + if (numCharges != -1 && lastChargeTime != null) { + return true; + } + return false; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java index 3c33cb09..eea1d008 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java @@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Calendar; +import java.util.GregorianCalendar; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler; @@ -130,4 +131,5 @@ public class MiBandCoordinator implements DeviceCoordinator { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); return Integer.parseInt(prefs.getString(MiBandConst.PREF_MIBAND_FITNESS_GOAL, "10000")); } + } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java new file mode 100644 index 00000000..b356a207 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java @@ -0,0 +1,42 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.miband; + +import java.util.Calendar; +import java.util.GregorianCalendar; + +public class MiBandDateConverter { + /** + * uses the standard algorithm to convert bytes received from the MiBand to a Calendar object + * @param value + * @return + */ + public static GregorianCalendar rawBytesToCalendar(byte[] value) { + GregorianCalendar timestamp = new GregorianCalendar(); + + if (value.length == 6) { + timestamp.set(Calendar.YEAR, (2000 + value[0])); + timestamp.set(Calendar.MONTH, value[1]); + timestamp.set(Calendar.DATE, value[2]); + timestamp.set(Calendar.HOUR_OF_DAY, value[3]); + timestamp.set(Calendar.MINUTE, value[4]); + timestamp.set(Calendar.SECOND, value[5]); + } + + return timestamp; + } + + /** + * uses the standard algorithm to convert a Calendar object to a byte array to send to MiBand + * @param timestamp + * @return + */ + public static byte[] calendarToRawBytes(Calendar timestamp) { + return new byte[]{ + (byte) (timestamp.get(Calendar.YEAR) - 2000), + (byte) timestamp.get(Calendar.MONTH), + (byte) timestamp.get(Calendar.DATE), + (byte) timestamp.get(Calendar.HOUR_OF_DAY), + (byte) timestamp.get(Calendar.MINUTE), + (byte) timestamp.get(Calendar.SECOND) + }; + } +} 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 3bfdf9bf..91a566b9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java @@ -9,6 +9,7 @@ import android.support.v4.content.LocalBroadcastManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; @@ -30,6 +31,7 @@ public class GBDevice implements Parcelable { private static final Logger LOG = LoggerFactory.getLogger(GBDevice.class); public static final short RSSI_UNKNOWN = 0; public static final short BATTERY_UNKNOWN = -1; + private static final short BATTERY_THRESHOLD_PERCENT = 10; public static final String EXTRA_DEVICE = "device"; private final String mName; private final String mAddress; @@ -38,7 +40,10 @@ public class GBDevice implements Parcelable { private String mHardwareVersion = null; private State mState = State.NOT_CONNECTED; private short mBatteryLevel = BATTERY_UNKNOWN; - private String mBatteryState; + private short mBatteryThresholdPercent = BATTERY_THRESHOLD_PERCENT; + //TODO: get rid of String mBatteryStatus in favor of Enum mBatteryState + private String mBatteryStatus; + private BatteryState mBatteryState; private short mRssi = RSSI_UNKNOWN; private String mBusyTask; @@ -57,7 +62,7 @@ public class GBDevice implements Parcelable { mHardwareVersion = in.readString(); mState = State.values()[in.readInt()]; mBatteryLevel = (short) in.readInt(); - mBatteryState = in.readString(); + mBatteryStatus = in.readString(); mRssi = (short) in.readInt(); mBusyTask = in.readString(); @@ -73,7 +78,7 @@ public class GBDevice implements Parcelable { dest.writeString(mHardwareVersion); dest.writeInt(mState.ordinal()); dest.writeInt(mBatteryLevel); - dest.writeString(mBatteryState); + dest.writeString(mBatteryStatus); dest.writeInt(mRssi); dest.writeString(mBusyTask); } @@ -177,7 +182,7 @@ public class GBDevice implements Parcelable { private void unsetDynamicState() { setBatteryLevel(BATTERY_UNKNOWN); - setBatteryState(null); + setBatteryState(BatteryState.UNKNOWN); setFirmwareVersion(null); setRssi(RSSI_UNKNOWN); if (mBusyTask != null) { @@ -281,15 +286,20 @@ public class GBDevice implements Parcelable { } } - /** - * Returns a string representation of the battery state. - */ - public String getBatteryState() { - return mBatteryState != null ? mBatteryState : GBApplication.getContext().getString(R.string._unknown_); + public BatteryState getBatteryState() { + return mBatteryState; } - public void setBatteryState(String batteryState) { - mBatteryState = batteryState; + public void setBatteryState(BatteryState mBatteryState) { + this.mBatteryState = mBatteryState; + } + + public short getBatteryThresholdPercent() { + return mBatteryThresholdPercent; + } + + public void setBatteryThresholdPercent(short batteryThresholdPercent) { + this.mBatteryThresholdPercent = batteryThresholdPercent; } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/BatteryState.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/BatteryState.java new file mode 100644 index 00000000..fb82100d --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/BatteryState.java @@ -0,0 +1,10 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +public enum BatteryState { + UNKNOWN, + BATTERY_NORMAL, + BATTERY_LOW, + BATTERY_CHARGING, + BATTERY_CHARGING_FULL, + BATTERY_NOT_CHARGING_FULL +} 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 64ea42e5..bc4b40a0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java @@ -15,17 +15,19 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; +import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import nodomain.freeyourgadget.gadgetbridge.activities.AppManagerActivity; import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsHost; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; +import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBCallControlReceiver; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBMusicControlReceiver; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.activities.charts.AbstractChartFragment; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; @@ -111,6 +113,9 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { case DISMISS_NOTIFICATION: handleGBDeviceEvent((GBDeviceEventDismissNotification) deviceEvent); break; + case BATTERY_INFO: + handleGBDeviceEvent((GBDeviceEventBatteryInfo) deviceEvent); + break; default: break; } @@ -219,4 +224,28 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { notificationListenerIntent.putExtra("id", deviceEvent.notificationID); LocalBroadcastManager.getInstance(context).sendBroadcast(notificationListenerIntent); } + + public void handleGBDeviceEvent(GBDeviceEventBatteryInfo deviceEvent) { + Context context = getContext(); + LOG.info("Got BATTERY_INFO device event"); + gbDevice.setBatteryLevel(deviceEvent.level); + gbDevice.setBatteryState(deviceEvent.state); + + //show the notification if the battery level is below threshold and only if not connected to charger + if (deviceEvent.level <= gbDevice.getBatteryThresholdPercent() && + (BatteryState.BATTERY_LOW.equals(deviceEvent.state) || + BatteryState.BATTERY_NORMAL.equals(deviceEvent.state)) + ) { + GB.updateBatteryNotification(context.getString(R.string.notif_battery_low_percent, gbDevice.getName(), deviceEvent.level), + deviceEvent.extendedInfoAvailable() ? + context.getString(R.string.notif_battery_low_percent, gbDevice.getName(), deviceEvent.level) + "\n" + + context.getString(R.string.notif_battery_low_bigtext_last_charge_time, DateFormat.getDateTimeInstance().format(deviceEvent.lastChargeTime.getTime()).toString()) + + context.getString(R.string.notif_battery_low_bigtext_number_of_charges, deviceEvent.numCharges) + : "" + , context); + } + + gbDevice.sendDeviceUpdateIntent(context); + } + } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java index 8509bc1a..fa7d6e48 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java @@ -1,9 +1,17 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband; -import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.R; +import java.util.GregorianCalendar; + +import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandDateConverter; +import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; public class BatteryInfo extends AbstractInfo { + public static final byte DEVICE_BATTERY_NORMAL = 0; + public static final byte DEVICE_BATTERY_LOW = 1; + public static final byte DEVICE_BATTERY_CHARGING = 2; + public static final byte DEVICE_BATTERY_CHARGING_FULL = 3; + public static final byte DEVICE_BATTERY_CHARGE_OFF = 4; + public BatteryInfo(byte[] data) { super(data); } @@ -15,20 +23,42 @@ public class BatteryInfo extends AbstractInfo { return 50; // actually unknown } - public String getStatus() { + public BatteryState getState() { if (mData.length >= 10) { int value = mData[9]; switch (value) { - case 1: - return GBApplication.getContext().getString(R.string.battery_low); - case 2: - return GBApplication.getContext().getString(R.string.battery_medium); - case 3: - return GBApplication.getContext().getString(R.string.battery_full); - case 4: - return GBApplication.getContext().getString(R.string.battery_not_charging); + case DEVICE_BATTERY_NORMAL: + return BatteryState.BATTERY_NORMAL; + case DEVICE_BATTERY_LOW: + return BatteryState.BATTERY_LOW; + case DEVICE_BATTERY_CHARGING: + return BatteryState.BATTERY_CHARGING; + case DEVICE_BATTERY_CHARGING_FULL: + return BatteryState.BATTERY_CHARGING_FULL; + case DEVICE_BATTERY_CHARGE_OFF: + return BatteryState.BATTERY_NOT_CHARGING_FULL; } } - return GBApplication.getContext().getString(R.string._unknown_); + return BatteryState.UNKNOWN; + } + + public GregorianCalendar getLastChargeTime() { + GregorianCalendar lastCharge = new GregorianCalendar(); + + if (mData.length >= 10) { + lastCharge = MiBandDateConverter.rawBytesToCalendar(new byte[]{ + mData[1], mData[2], mData[3], mData[4], mData[5], mData[6] + }); + } + + return lastCharge; + } + + public int getNumCharges() { + if (mData.length >= 10) { + return ((0xff & mData[7]) | ((0xff & mData[8]) << 8)); + + } + return -1; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java index b191b450..9af6ec42 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/MiBandSupport.java @@ -13,14 +13,15 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Calendar; import java.util.GregorianCalendar; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator; +import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandDateConverter; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService; import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State; @@ -66,6 +67,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { private DeviceInfo mDeviceInfo; GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo(); + GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo(); public MiBandSupport() { addSupportedService(MiBandService.UUID_SERVICE_MIBAND_SERVICE); @@ -261,6 +263,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } return this; } + /** * Part of device initialization process. Do not call manually. * @@ -276,7 +279,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { transaction.write(characteristic, new byte[]{ MiBandService.COMMAND_SET_FITNESS_GOAL, 0, - (byte) (fitnessGoal & 0xff), + (byte) (fitnessGoal & 0xff), (byte) ((fitnessGoal >>> 8) & 0xff) }); } else { @@ -426,14 +429,14 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { * @param builder */ private MiBandSupport setCurrentTime(TransactionBuilder builder) { - Calendar now = GregorianCalendar.getInstance(); + byte[] nowBytes = MiBandDateConverter.calendarToRawBytes(GregorianCalendar.getInstance()); byte[] time = new byte[]{ - (byte) (now.get(Calendar.YEAR) - 2000), - (byte) now.get(Calendar.MONTH), - (byte) now.get(Calendar.DATE), - (byte) now.get(Calendar.HOUR_OF_DAY), - (byte) now.get(Calendar.MINUTE), - (byte) now.get(Calendar.SECOND), + nowBytes[0], + nowBytes[1], + nowBytes[2], + nowBytes[3], + nowBytes[4], + nowBytes[5], (byte) 0x0f, (byte) 0x0f, (byte) 0x0f, @@ -621,6 +624,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { /** * Utility method that may be used to log incoming messages when we don't know how to deal with them yet. + * * @param value */ private void logMessageContent(byte[] value) { @@ -635,13 +639,13 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { * characteristic, * These messages appear to be always 1 byte long, with values that are listed in MiBandService. * It is not excluded that there are further values which are still unknown. - * + *

* Upon receiving known values that request further action by GB, the appropriate method is called. * * @param value */ private void handleNotificationNotif(byte[] value) { - if(value.length != 1) { + if (value.length != 1) { LOG.error("Notifications should be 1 byte long."); LOG.info("RECEIVED DATA WITH LENGTH: " + value.length); for (byte b : value) { @@ -681,17 +685,18 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { * @param characteristic */ private void queueAlarm(Alarm alarm, TransactionBuilder builder, BluetoothGattCharacteristic characteristic) { - Calendar alarmCal = alarm.getAlarmCal(); + byte[] alarmCalBytes = MiBandDateConverter.calendarToRawBytes(alarm.getAlarmCal()); + byte[] alarmMessage = new byte[]{ (byte) MiBandService.COMMAND_SET_TIMER, (byte) alarm.getIndex(), (byte) (alarm.isEnabled() ? 1 : 0), - (byte) (alarmCal.get(Calendar.YEAR) - 2000), - (byte) alarmCal.get(Calendar.MONTH), - (byte) alarmCal.get(Calendar.DATE), - (byte) alarmCal.get(Calendar.HOUR_OF_DAY), - (byte) alarmCal.get(Calendar.MINUTE), - (byte) alarmCal.get(Calendar.SECOND), + alarmCalBytes[0], + alarmCalBytes[1], + alarmCalBytes[2], + alarmCalBytes[3], + alarmCalBytes[4], + alarmCalBytes[5], (byte) (alarm.isSmartWakeup() ? 30 : 0), (byte) alarm.getRepetitionMask() }; @@ -716,9 +721,11 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { private void handleBatteryInfo(byte[] value, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { BatteryInfo info = new BatteryInfo(value); - getDevice().setBatteryLevel((short) info.getLevelInPercent()); - getDevice().setBatteryState(info.getStatus()); - getDevice().sendDeviceUpdateIntent(getContext()); + batteryCmd.level = ((short) info.getLevelInPercent()); + batteryCmd.state = info.getState(); + batteryCmd.lastChargeTime = info.getLastChargeTime(); + batteryCmd.numCharges = info.getNumCharges(); + handleGBDeviceEvent(batteryCmd); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/FetchActivityOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/FetchActivityOperation.java index cf05b1b3..e6f3959f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/FetchActivityOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/FetchActivityOperation.java @@ -19,6 +19,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; +import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandDateConverter; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; @@ -224,14 +225,15 @@ public class FetchActivityOperation extends AbstractBTLEOperation * @param bytesTransferred */ private void sendAckDataTransfer(Calendar time, int bytesTransferred) { + byte[] ackTime = MiBandDateConverter.calendarToRawBytes(time); byte[] ack = new byte[]{ MiBandService.COMMAND_CONFIRM_ACTIVITY_DATA_TRANSFER_COMPLETE, - (byte) (time.get(Calendar.YEAR) - 2000), - (byte) time.get(Calendar.MONTH), - (byte) time.get(Calendar.DATE), - (byte) time.get(Calendar.HOUR_OF_DAY), - (byte) time.get(Calendar.MINUTE), - (byte) time.get(Calendar.SECOND), + ackTime[0], + ackTime[1], + ackTime[2], + ackTime[3], + ackTime[4], + ackTime[5], (byte) (bytesTransferred & 0xff), (byte) (0xff & (bytesTransferred >> 8)) }; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index ab3f0fdd..fb73f9b0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -38,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.TimeChangeReceiver; public class GB { public static final int NOTIFICATION_ID = 1; public static final int NOTIFICATION_ID_INSTALL = 2; + public static final int NOTIFICATION_ID_LOW_BATTERY = 3; private static final Logger LOG = LoggerFactory.getLogger(GB.class); public static final int INFO = 1; @@ -297,6 +298,35 @@ public class GB { nm.notify(NOTIFICATION_ID_INSTALL, notification); } + private static Notification createBatteryNotification(String text, String bigText, Context context) { + Intent notificationIntent = new Intent(context, ControlCenter.class); + notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, + notificationIntent, 0); + + NotificationCompat.Builder nb = new NotificationCompat.Builder(context) + .setContentTitle( context.getString(R.string.notif_battery_low_title)) + .setContentText(text) + .setContentIntent(pendingIntent) + .setSmallIcon(R.drawable.ic_notification_low_battery) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setOngoing(false); + + if (bigText != null) { + nb.setStyle(new NotificationCompat.BigTextStyle().bigText(bigText)); + } + + return nb.build(); + } + + public static void updateBatteryNotification(String text, String bigText, Context context) { + Notification notification = createBatteryNotification(text, bigText, context); + + NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID_LOW_BATTERY, notification); + } + public static GBEnvironment env() { return environment; } diff --git a/app/src/main/res/drawable-hdpi/ic_notification_low_battery.png b/app/src/main/res/drawable-hdpi/ic_notification_low_battery.png new file mode 100644 index 00000000..dad13ba6 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_notification_low_battery.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_notification_low_battery.png b/app/src/main/res/drawable-mdpi/ic_notification_low_battery.png new file mode 100644 index 00000000..32c4393f Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_notification_low_battery.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_notification_low_battery.png b/app/src/main/res/drawable-xhdpi/ic_notification_low_battery.png new file mode 100644 index 00000000..f1aff36a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_notification_low_battery.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_notification_low_battery.png b/app/src/main/res/drawable-xxhdpi/ic_notification_low_battery.png new file mode 100644 index 00000000..60dacdf7 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_notification_low_battery.png differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ceae0a9e..4849e6b0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -74,10 +74,6 @@ tap a device to connect Cannot connect. BT address invalid? Gadgetbridge running - low - medium - full - not charging installing binary %1$d/%2$d installation failed! installation successful @@ -166,6 +162,10 @@ Unable to install the given file: $1%s Unable to install the given firmware: it doesn\'t match your Pebble\'s hardware revision. Please wait while determining the installation status... + Gadget battery Low! + %1$s battery left: %2$s%% + Last charge: %s \n + Number of charges: %s Your Sleep Steps a week Your Activity and Sleep