From c3e395818fb87e4ecf05c80f60bfc9e740090026 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Tue, 18 Aug 2015 17:37:51 +0200 Subject: [PATCH] Adding support for battery events using GBDeviceEvent. - show notification on low battery (closes #40) - Miband specific: add date of last charge and number of charges --- .../deviceevents/GBDeviceEvent.java | 1 + .../GBDeviceEventBatteryInfo.java | 25 ++++++++++++++++++ .../gadgetbridge/impl/GBDevice.java | 17 ++++++------ .../service/AbstractDeviceSupport.java | 25 +++++++++++++++++- .../service/devices/miband/BatteryInfo.java | 26 +++++++++++++++++++ .../service/devices/miband/MiBandSupport.java | 17 +++++++----- .../freeyourgadget/gadgetbridge/util/GB.java | 26 +++++++++++++++++++ app/src/main/res/values/strings.xml | 4 +++ 8 files changed, 126 insertions(+), 15 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventBatteryInfo.java 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 0aa03f81e..5a8246a78 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 000000000..2bc311afb --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventBatteryInfo.java @@ -0,0 +1,25 @@ +package nodomain.freeyourgadget.gadgetbridge.deviceevents; + + +import java.util.GregorianCalendar; + +public class GBDeviceEventBatteryInfo extends GBDeviceEvent { + public GregorianCalendar lastChargeTime; + public BatteryState state = BatteryState.UNKNOWN; + //TODO: I think the string should be deprecated in favor of the Enum above + public String status; + public short level = 50; + public int numCharges = -1; + + public GBDeviceEventBatteryInfo() { + eventClass = EventClass.BATTERY_INFO; + } + + public enum BatteryState { + UNKNOWN, + CHARGE_FULL, + CHARGE_MEDIUM, + CHARGE_LOW, + CHARGING, + } +} 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 3bfdf9bf0..bf2e213e8 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java @@ -38,7 +38,8 @@ public class GBDevice implements Parcelable { private String mHardwareVersion = null; private State mState = State.NOT_CONNECTED; private short mBatteryLevel = BATTERY_UNKNOWN; - private String mBatteryState; + //TODO: get rid of String mBatteryStatus in favor of Enum mBatteryState + private String mBatteryStatus; private short mRssi = RSSI_UNKNOWN; private String mBusyTask; @@ -57,7 +58,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 +74,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 +178,7 @@ public class GBDevice implements Parcelable { private void unsetDynamicState() { setBatteryLevel(BATTERY_UNKNOWN); - setBatteryState(null); + setBatteryStatus(null); setFirmwareVersion(null); setRssi(RSSI_UNKNOWN); if (mBusyTask != null) { @@ -284,12 +285,12 @@ 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 String getBatteryStatus() { + return mBatteryStatus != null ? mBatteryStatus : GBApplication.getContext().getString(R.string._unknown_); } - public void setBatteryState(String batteryState) { - mBatteryState = batteryState; + public void setBatteryStatus(String batteryStatus) { + mBatteryStatus = batteryStatus; } @Override 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 64ea42e59..5783aec31 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,18 @@ 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.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 +112,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 +223,23 @@ 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.setBatteryStatus(deviceEvent.status); + + + //TODO: maybe switch to a device-dependent threshold + if (deviceEvent.level < 10) { + GB.updateBatteryNotification(deviceEvent.level, + 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 8509bc1ac..f21bef05e 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,5 +1,8 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband; +import java.util.Calendar; +import java.util.GregorianCalendar; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; @@ -31,4 +34,27 @@ public class BatteryInfo extends AbstractInfo { } return GBApplication.getContext().getString(R.string._unknown_); } + + public GregorianCalendar getLastChargeTime() { + GregorianCalendar lastCharge = new GregorianCalendar(); + + if (mData.length >= 10) { + lastCharge.set(Calendar.YEAR, (2000 + mData[1])); + lastCharge.set(Calendar.MONTH, mData[2]); + lastCharge.set(Calendar.DATE, mData[3]); + lastCharge.set(Calendar.HOUR_OF_DAY, mData[4]); + lastCharge.set(Calendar.MINUTE, mData[5]); + lastCharge.set(Calendar.SECOND, 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 8c8e3cea9..be9a5db93 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 @@ -18,6 +18,7 @@ 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; @@ -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 { @@ -637,6 +640,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) { @@ -651,13 +655,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) { @@ -732,9 +736,10 @@ 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.lastChargeTime = info.getLastChargeTime(); + batteryCmd.numCharges = info.getNumCharges(); + handleGBDeviceEvent(batteryCmd); } } 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 b7fa7c016..4d624121b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -44,6 +44,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; @@ -298,4 +299,29 @@ public class GB { NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); nm.notify(NOTIFICATION_ID_INSTALL, notification); } + + private static Notification createBatteryNotification(int level, String text, 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(context.getString(R.string.notif_battery_low_percent, level)) + .setContentIntent(pendingIntent) + .setSmallIcon(R.drawable.ic_notification) + .setStyle(new NotificationCompat.BigTextStyle().bigText(text)) + .setOngoing(false); + + return nb.build(); + } + + public static void updateBatteryNotification(int level, String text, Context context) { + Notification notification = createBatteryNotification(level, text, context); + + NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + nm.notify(NOTIFICATION_ID_LOW_BATTERY, notification); + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a60ab6c55..7132259be 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -166,4 +166,8 @@ 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! + Battery left: %s%% + Last charge: %s \n + Number of charges: %s