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
live-activity-data
Daniele Gobbetti 2015-08-18 17:37:51 +02:00
parent 121baa19ec
commit c3e395818f
8 changed files with 126 additions and 15 deletions

View File

@ -15,6 +15,7 @@ public abstract class GBDeviceEvent {
SLEEP_MONITOR_RES, SLEEP_MONITOR_RES,
SCREENSHOT, SCREENSHOT,
DISMISS_NOTIFICATION, DISMISS_NOTIFICATION,
BATTERY_INFO
} }
} }

View File

@ -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,
}
}

View File

@ -38,7 +38,8 @@ public class GBDevice implements Parcelable {
private String mHardwareVersion = null; private String mHardwareVersion = null;
private State mState = State.NOT_CONNECTED; private State mState = State.NOT_CONNECTED;
private short mBatteryLevel = BATTERY_UNKNOWN; 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 short mRssi = RSSI_UNKNOWN;
private String mBusyTask; private String mBusyTask;
@ -57,7 +58,7 @@ public class GBDevice implements Parcelable {
mHardwareVersion = in.readString(); mHardwareVersion = in.readString();
mState = State.values()[in.readInt()]; mState = State.values()[in.readInt()];
mBatteryLevel = (short) in.readInt(); mBatteryLevel = (short) in.readInt();
mBatteryState = in.readString(); mBatteryStatus = in.readString();
mRssi = (short) in.readInt(); mRssi = (short) in.readInt();
mBusyTask = in.readString(); mBusyTask = in.readString();
@ -73,7 +74,7 @@ public class GBDevice implements Parcelable {
dest.writeString(mHardwareVersion); dest.writeString(mHardwareVersion);
dest.writeInt(mState.ordinal()); dest.writeInt(mState.ordinal());
dest.writeInt(mBatteryLevel); dest.writeInt(mBatteryLevel);
dest.writeString(mBatteryState); dest.writeString(mBatteryStatus);
dest.writeInt(mRssi); dest.writeInt(mRssi);
dest.writeString(mBusyTask); dest.writeString(mBusyTask);
} }
@ -177,7 +178,7 @@ public class GBDevice implements Parcelable {
private void unsetDynamicState() { private void unsetDynamicState() {
setBatteryLevel(BATTERY_UNKNOWN); setBatteryLevel(BATTERY_UNKNOWN);
setBatteryState(null); setBatteryStatus(null);
setFirmwareVersion(null); setFirmwareVersion(null);
setRssi(RSSI_UNKNOWN); setRssi(RSSI_UNKNOWN);
if (mBusyTask != null) { if (mBusyTask != null) {
@ -284,12 +285,12 @@ public class GBDevice implements Parcelable {
/** /**
* Returns a string representation of the battery state. * Returns a string representation of the battery state.
*/ */
public String getBatteryState() { public String getBatteryStatus() {
return mBatteryState != null ? mBatteryState : GBApplication.getContext().getString(R.string._unknown_); return mBatteryStatus != null ? mBatteryStatus : GBApplication.getContext().getString(R.string._unknown_);
} }
public void setBatteryState(String batteryState) { public void setBatteryStatus(String batteryStatus) {
mBatteryState = batteryState; mBatteryStatus = batteryStatus;
} }
@Override @Override

View File

@ -15,17 +15,18 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import nodomain.freeyourgadget.gadgetbridge.activities.AppManagerActivity; import nodomain.freeyourgadget.gadgetbridge.activities.AppManagerActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsHost; import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsHost;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.util.GB; import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBCallControlReceiver; import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBCallControlReceiver;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBMusicControlReceiver; import nodomain.freeyourgadget.gadgetbridge.service.receivers.GBMusicControlReceiver;
import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.AbstractChartFragment;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
@ -111,6 +112,9 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
case DISMISS_NOTIFICATION: case DISMISS_NOTIFICATION:
handleGBDeviceEvent((GBDeviceEventDismissNotification) deviceEvent); handleGBDeviceEvent((GBDeviceEventDismissNotification) deviceEvent);
break; break;
case BATTERY_INFO:
handleGBDeviceEvent((GBDeviceEventBatteryInfo) deviceEvent);
break;
default: default:
break; break;
} }
@ -219,4 +223,23 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
notificationListenerIntent.putExtra("id", deviceEvent.notificationID); notificationListenerIntent.putExtra("id", deviceEvent.notificationID);
LocalBroadcastManager.getInstance(context).sendBroadcast(notificationListenerIntent); 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);
}
} }

View File

@ -1,5 +1,8 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband; package nodomain.freeyourgadget.gadgetbridge.service.devices.miband;
import java.util.Calendar;
import java.util.GregorianCalendar;
import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.R;
@ -31,4 +34,27 @@ public class BatteryInfo extends AbstractInfo {
} }
return GBApplication.getContext().getString(R.string._unknown_); 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;
}
} }

View File

@ -18,6 +18,7 @@ import java.util.GregorianCalendar;
import java.util.UUID; import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator;
@ -66,6 +67,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
private DeviceInfo mDeviceInfo; private DeviceInfo mDeviceInfo;
GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo(); GBDeviceEventVersionInfo versionCmd = new GBDeviceEventVersionInfo();
GBDeviceEventBatteryInfo batteryCmd = new GBDeviceEventBatteryInfo();
public MiBandSupport() { public MiBandSupport() {
addSupportedService(MiBandService.UUID_SERVICE_MIBAND_SERVICE); addSupportedService(MiBandService.UUID_SERVICE_MIBAND_SERVICE);
@ -261,6 +263,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
} }
return this; return this;
} }
/** /**
* Part of device initialization process. Do not call manually. * Part of device initialization process. Do not call manually.
* *
@ -276,7 +279,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
transaction.write(characteristic, new byte[]{ transaction.write(characteristic, new byte[]{
MiBandService.COMMAND_SET_FITNESS_GOAL, MiBandService.COMMAND_SET_FITNESS_GOAL,
0, 0,
(byte) (fitnessGoal & 0xff), (byte) (fitnessGoal & 0xff),
(byte) ((fitnessGoal >>> 8) & 0xff) (byte) ((fitnessGoal >>> 8) & 0xff)
}); });
} else { } 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. * Utility method that may be used to log incoming messages when we don't know how to deal with them yet.
*
* @param value * @param value
*/ */
private void logMessageContent(byte[] value) { private void logMessageContent(byte[] value) {
@ -651,13 +655,13 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
* characteristic, * characteristic,
* These messages appear to be always 1 byte long, with values that are listed in MiBandService. * 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. * It is not excluded that there are further values which are still unknown.
* * <p/>
* Upon receiving known values that request further action by GB, the appropriate method is called. * Upon receiving known values that request further action by GB, the appropriate method is called.
* *
* @param value * @param value
*/ */
private void handleNotificationNotif(byte[] value) { private void handleNotificationNotif(byte[] value) {
if(value.length != 1) { if (value.length != 1) {
LOG.error("Notifications should be 1 byte long."); LOG.error("Notifications should be 1 byte long.");
LOG.info("RECEIVED DATA WITH LENGTH: " + value.length); LOG.info("RECEIVED DATA WITH LENGTH: " + value.length);
for (byte b : value) { for (byte b : value) {
@ -732,9 +736,10 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
private void handleBatteryInfo(byte[] value, int status) { private void handleBatteryInfo(byte[] value, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) { if (status == BluetoothGatt.GATT_SUCCESS) {
BatteryInfo info = new BatteryInfo(value); BatteryInfo info = new BatteryInfo(value);
getDevice().setBatteryLevel((short) info.getLevelInPercent()); batteryCmd.level = ((short) info.getLevelInPercent());
getDevice().setBatteryState(info.getStatus()); batteryCmd.lastChargeTime = info.getLastChargeTime();
getDevice().sendDeviceUpdateIntent(getContext()); batteryCmd.numCharges = info.getNumCharges();
handleGBDeviceEvent(batteryCmd);
} }
} }

View File

@ -44,6 +44,7 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.TimeChangeReceiver;
public class GB { public class GB {
public static final int NOTIFICATION_ID = 1; public static final int NOTIFICATION_ID = 1;
public static final int NOTIFICATION_ID_INSTALL = 2; 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); private static final Logger LOG = LoggerFactory.getLogger(GB.class);
public static final int INFO = 1; public static final int INFO = 1;
@ -298,4 +299,29 @@ public class GB {
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(NOTIFICATION_ID_INSTALL, notification); 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);
}
} }

View File

@ -166,4 +166,8 @@
<string name="pbw_install_handler_unable_to_install">Unable to install the given file: $1%s</string> <string name="pbw_install_handler_unable_to_install">Unable to install the given file: $1%s</string>
<string name="pbw_install_handler_hw_revision_mismatch">Unable to install the given firmware: it doesn\'t match your Pebble\'s hardware revision.</string> <string name="pbw_install_handler_hw_revision_mismatch">Unable to install the given firmware: it doesn\'t match your Pebble\'s hardware revision.</string>
<string name="installer_activity_wait_while_determining_status">Please wait while determining the installation status...</string> <string name="installer_activity_wait_while_determining_status">Please wait while determining the installation status...</string>
<string name="notif_battery_low_title">Gadget battery Low!</string>
<string name="notif_battery_low_percent">Battery left: %s%%</string>
<string name="notif_battery_low_bigtext_last_charge_time">Last charge: %s \n</string>
<string name="notif_battery_low_bigtext_number_of_charges">Number of charges: %s</string>
</resources> </resources>