From 595ee45f755446633bf57d957984eb2586c9a68b Mon Sep 17 00:00:00 2001 From: Jamorham Date: Tue, 8 Nov 2016 13:05:04 +0000 Subject: [PATCH] Initial Support for Pebble2 and Pebble Health --- app/src/main/AndroidManifest.xml | 2 +- .../java/com/eveningoutpost/dexdrip/Home.java | 54 +++++++- .../dexdrip/Models/HeartRate.java | 81 +++++++++++ .../dexdrip/Models/PebbleMovement.java | 128 ++++++++++++++++++ .../dexdrip/UtilityModels/BgGraphBuilder.java | 74 +++++++++- .../dexdrip/UtilityModels/ColorCache.java | 5 +- .../UtilityModels/pebble/PebbleWatchSync.java | 97 +++++++++++++ .../ic_heart_pulse_grey600_24dp.png | Bin 0 -> 1237 bytes .../drawable-xhdpi/ic_walk_grey600_24dp.png | Bin 0 -> 1065 bytes app/src/main/res/layout/activity_home.xml | 38 ++++++ .../res/raw/xdrip_pebble_classic_trend.bin | Bin 54981 -> 62027 bytes app/src/main/res/xml/xdrip_plus_prefs.xml | 33 +++++ 12 files changed, 502 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/com/eveningoutpost/dexdrip/Models/HeartRate.java create mode 100644 app/src/main/java/com/eveningoutpost/dexdrip/Models/PebbleMovement.java create mode 100644 app/src/main/res/drawable-xhdpi/ic_heart_pulse_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_walk_grey600_24dp.png diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4f9639212a..210d732c7c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -50,7 +50,7 @@ android:value="41" /> + android:value="com.eveningoutpost.dexdrip.Models.ActiveBgAlert,com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice,com.eveningoutpost.dexdrip.Models.AlertType,com.eveningoutpost.dexdrip.Models.BgReading,com.eveningoutpost.dexdrip.Models.BgReading,com.eveningoutpost.dexdrip.Models.Calibration,com.eveningoutpost.dexdrip.Models.Calibration,com.eveningoutpost.dexdrip.Models.CalibrationRequest,com.eveningoutpost.dexdrip.Models.Sensor,com.eveningoutpost.dexdrip.Models.TransmitterData,com.eveningoutpost.dexdrip.Models.Treatments,com.eveningoutpost.dexdrip.Models.UserError,com.eveningoutpost.dexdrip.Models.UserNotification,com.eveningoutpost.dexdrip.ShareModels.Models,com.eveningoutpost.dexdrip.UtilityModels.BgSendQueue,com.eveningoutpost.dexdrip.UtilityModels.CalibrationSendQueue,com.eveningoutpost.dexdrip.UtilityModels.SensorSendQueue,com.eveningoutpost.dexdrip.Models.HeartRate,com.eveningoutpost.dexdrip.Models.PebbleMovement"/> BgGraphBuilder.NOISE_TRIGGER) && (BgGraphBuilder.best_bg_estimate > 0) @@ -2119,7 +2163,7 @@ private void displayCurrentInfoFromReading(BgReading lastBgReading, boolean pred // TODO this should be made more efficient probably if (Home.getPreferencesBooleanDefaultFalse("display_glucose_from_plugin") && (PluggableCalibration.getCalibrationPluginFromPreferences() != null)) { - currentBgValueText.setText("\u24C5" + currentBgValueText.getText()); // adds warning P in circle icon + currentBgValueText.setText(getString(R.string.p_in_circle) + currentBgValueText.getText()); // adds warning P in circle icon } } @@ -2556,8 +2600,10 @@ public static String getPreferencesStringWithDefault(final String pref, final St } if (prefs != null) { return prefs.getString(pref, def); + } else { + UserError.Log.wtf(TAG, "Could not initialize preferences in getPreferencesStringWithDefault: "+pref); + return ""; } - return ""; } public static long getPreferencesLong(final String pref, final long def) { diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/Models/HeartRate.java b/app/src/main/java/com/eveningoutpost/dexdrip/Models/HeartRate.java new file mode 100644 index 0000000000..15f066e991 --- /dev/null +++ b/app/src/main/java/com/eveningoutpost/dexdrip/Models/HeartRate.java @@ -0,0 +1,81 @@ +package com.eveningoutpost.dexdrip.Models; + +import android.provider.BaseColumns; + +import com.activeandroid.Model; +import com.activeandroid.annotation.Column; +import com.activeandroid.annotation.Table; +import com.activeandroid.query.Select; +import com.activeandroid.util.SQLiteUtils; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + +/** + * Created by jamorham on 01/11/2016. + */ + + +@Table(name = "HeartRate", id = BaseColumns._ID) +public class HeartRate extends Model { + + private static boolean patched = false; + private final static String TAG = "HeartRate"; + + @Expose + @Column(name = "timestamp", unique = true, onUniqueConflicts = Column.ConflictAction.IGNORE) + public long timestamp; + + @Expose + @Column(name = "bpm") + public int bpm; + + + // patches and saves + public Long saveit() { + fixUpTable(); + return save(); + } + + public String toS() { + final Gson gson = new GsonBuilder() + .excludeFieldsWithoutExposeAnnotation() + .create(); + return gson.toJson(this); + } + + public static HeartRate last() { + try { + return new Select() + .from(HeartRate.class) + .orderBy("timestamp desc") + .executeSingle(); + } catch (android.database.sqlite.SQLiteException e) { + fixUpTable(); + return null; + } + } + + // create the table ourselves without worrying about model versioning and downgrading + private static void fixUpTable() { + if (patched) return; + String[] patchup = { + "CREATE TABLE HeartRate (_id INTEGER PRIMARY KEY AUTOINCREMENT);", + "ALTER TABLE HeartRate ADD COLUMN timestamp INTEGER;", + "ALTER TABLE HeartRate ADD COLUMN bpm INTEGER;", + "CREATE UNIQUE INDEX index_HeartRate_timestamp on HeartRate(timestamp);"}; + + for (String patch : patchup) { + try { + SQLiteUtils.execSql(patch); + // UserError.Log.e(TAG, "Processed patch should not have succeeded!!: " + patch); + } catch (Exception e) { + // UserError.Log.d(TAG, "Patch: " + patch + " generated exception as it should: " + e.toString()); + } + } + patched = true; + } +} + + + diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/Models/PebbleMovement.java b/app/src/main/java/com/eveningoutpost/dexdrip/Models/PebbleMovement.java new file mode 100644 index 0000000000..5247c3efe2 --- /dev/null +++ b/app/src/main/java/com/eveningoutpost/dexdrip/Models/PebbleMovement.java @@ -0,0 +1,128 @@ +package com.eveningoutpost.dexdrip.Models; + +import android.provider.BaseColumns; + +import com.activeandroid.Model; +import com.activeandroid.annotation.Column; +import com.activeandroid.annotation.Table; +import com.activeandroid.query.Select; +import com.activeandroid.util.SQLiteUtils; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + +import java.util.List; + +/** + * Created by jamorham on 01/11/2016. + */ + + +@Table(name = "PebbleMovement", id = BaseColumns._ID) +public class PebbleMovement extends Model { + + private static boolean patched = false; + private final static String TAG = "PebbleMovement"; + + @Expose + @Column(name = "timestamp", unique = true, onUniqueConflicts = Column.ConflictAction.IGNORE) + public long timestamp; + + @Expose + @Column(name = "metric") + public int metric; + + + // patches and saves + public Long saveit() { + fixUpTable(); + return save(); + } + + public String toS() { + final Gson gson = new GsonBuilder() + .excludeFieldsWithoutExposeAnnotation() + .create(); + return gson.toJson(this); + } + + + // static methods + + public static PebbleMovement last() { + try { + return new Select() + .from(PebbleMovement.class) + .orderBy("timestamp desc") + .executeSingle(); + } catch (android.database.sqlite.SQLiteException e) { + fixUpTable(); + return null; + } + } + + public static List latestForGraph(int number, double startTime) { + return latestForGraph(number, (long) startTime, Long.MAX_VALUE); + } + + public static List latestForGraph(int number, long startTime) { + return latestForGraph(number, startTime, Long.MAX_VALUE); + } + + public static List latestForGraph(int number, long startTime, long endTime) { + return new Select() + .from(PebbleMovement.class) + .where("timestamp >= " + Math.max(startTime, 0)) + .where("timestamp <= " + endTime) + .orderBy("timestamp asc") // warn asc! + .limit(number) + .execute(); + } + + // expects pre-sorted in asc order? + public static List deltaListFromMovementList(List mList) { + int last_metric = -1; + int temp_metric = -1; + for (PebbleMovement pm : mList) { + // first item in list + if (last_metric == -1) { + last_metric = pm.metric; + pm.metric = 0; + } else { + // normal incrementing calculate delta + if (pm.metric >= last_metric) { + temp_metric = pm.metric - last_metric; + last_metric = pm.metric; + pm.metric = temp_metric; + } else { + last_metric = pm.metric; + } + } + } + return mList; + } + + + // create the table ourselves without worrying about model versioning and downgrading + private static void fixUpTable() { + if (patched) return; + String[] patchup = { + "CREATE TABLE PebbleMovement (_id INTEGER PRIMARY KEY AUTOINCREMENT);", + "ALTER TABLE PebbleMovement ADD COLUMN timestamp INTEGER;", + "ALTER TABLE PebbleMovement ADD COLUMN metric INTEGER;", + "CREATE UNIQUE INDEX index_PebbleMovement_timestamp on PebbleMovement(timestamp);"}; + + for (String patch : patchup) { + try { + SQLiteUtils.execSql(patch); + // UserError.Log.e(TAG, "Processed patch should not have succeeded!!: " + patch); + } catch (Exception e) { + // UserError.Log.d(TAG, "Patch: " + patch + " generated exception as it should: " + e.toString()); + } + } + patched = true; + } +} + + + diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgGraphBuilder.java b/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgGraphBuilder.java index 001a6179d1..3b1bb5c197 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgGraphBuilder.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/BgGraphBuilder.java @@ -22,6 +22,7 @@ import com.eveningoutpost.dexdrip.Models.Forecast.TrendLine; import com.eveningoutpost.dexdrip.Models.Iob; import com.eveningoutpost.dexdrip.Models.JoH; +import com.eveningoutpost.dexdrip.Models.PebbleMovement; import com.eveningoutpost.dexdrip.Models.Profile; import com.eveningoutpost.dexdrip.Models.Treatments; import com.eveningoutpost.dexdrip.Models.UserError; @@ -100,7 +101,7 @@ public class BgGraphBuilder { private static double low_occurs_at_processed_till_timestamp = -1; private final static String TAG = "jamorham graph"; //private final static int pluginColor = Color.parseColor("#AA00FFFF"); // temporary - private final static int pluginColor = Color.parseColor("#77ff7700"); // temporary + private final static int pluginSize = 2; final int pointSize; final int axisTextSize; @@ -276,6 +277,68 @@ private void extend_line(List points, float x, float y) { Log.d(TAG,"Extend line size: "+points.size()); } + // line illustrating result from step counter + private List stepsLines() { + final List stepsLines = new ArrayList<>(); + if (prefs.getBoolean("show_pebble_movement_line", true)) { + final List pmlist = PebbleMovement.deltaListFromMovementList(PebbleMovement.latestForGraph(2000, loaded_start, loaded_end)); + PointValue last_point = null; + final boolean d = false; + if (d) Log.d(TAG, "Delta: pmlist size: " + pmlist.size()); + final float yscale = doMgdl ? (float) Constants.MMOLL_TO_MGDL : 1f; + final float ypos = 6 * yscale; // TODO Configurable + //final long last_timestamp = pmlist.get(pmlist.size() - 1).timestamp; + final float MAX_SIZE = 40; + int flipper = 0; + int accumulator = 0; + + for (PebbleMovement pm : pmlist) { + if (last_point == null) { + last_point = new PointValue((float) pm.timestamp / FUZZER, ypos); + } else { + final PointValue this_point = new PointValue((float) pm.timestamp / FUZZER, ypos); + final float time_delta = this_point.getX() - last_point.getX(); + if (time_delta > 1) { + + final List new_points = new ArrayList<>(); + new_points.add(last_point); + new_points.add(this_point); + + last_point = this_point; // update pointer + final Line this_line = new Line(new_points); + flipper ^= 1; + this_line.setColor((flipper == 0) ? getCol(X.color_step_counter1) : getCol(X.color_step_counter2)); + + float stroke_size = Math.min(MAX_SIZE, (float) Math.log1p(((double) (pm.metric + accumulator)) / time_delta) * 5); + if (d) Log.d(TAG, "Delta stroke: " + stroke_size); + this_line.setStrokeWidth((int) stroke_size); + + if (d) + Log.d(TAG, "Delta-Line: " + JoH.dateTimeText(pm.timestamp) + " time delta: " + time_delta + " total: " + (pm.metric + accumulator) + " lsize: " + stroke_size + " / " + (int) stroke_size); + accumulator = 0; + + if (this_line.getStrokeWidth() > 0) { + stepsLines.add(this_line); + this_line.setHasPoints(false); + this_line.setHasLines(true); + } else { + if (d) Log.d(TAG, "Delta skip: " + JoH.dateTimeText(pm.timestamp)); + } + if (d) + Log.d(TAG, "Delta-List: " + JoH.dateTimeText(pm.timestamp) + " time delta: " + time_delta + " val: " + pm.metric); + } else { + accumulator += pm.metric; + if (d) + Log.d(TAG, "Delta: added: " + JoH.dateTimeText(pm.timestamp) + " metric: " + pm.metric + " to accumulator: " + accumulator); + } + } + } + if (d) + Log.d(TAG, "Delta returning stepsLines: " + stepsLines.size() + " final accumulator remaining: " + accumulator); + } + return stepsLines; + } + private List motionLine() { final ArrayList motion_datas = ActivityRecognizedService.getForGraph((long) start_time * FUZZER, (long) end_time * FUZZER); @@ -373,9 +436,11 @@ public LineChartData previewLineData(LineChartData hint) { unlabledLinesSize = 2; } for (Line lline : previewLineData.getLines()) { - if ((lline.getPointRadius() == pluginSize) && (lline.getPointColor() == pluginColor)) { - removeItems.add(lline); // remove plugin plot from preview graph + if (((lline.getPointRadius() == pluginSize) && (lline.getPointColor() == getCol(X.color_secondary_glucose_value))) + || ((lline.getColor() == getCol(X.color_step_counter1) || (lline.getColor() == getCol(X.color_step_counter2))))) { + removeItems.add(lline); // remove plugin or step counter plot from preview graph } + if ((lline.hasLabels() && (lline.getPointRadius() > 0))) { lline.setPointRadius(3); // preserve size for treatments @@ -405,6 +470,7 @@ public synchronized List defaultLines(boolean simple) { if (Home.getPreferencesBoolean("motion_tracking_enabled", false) && Home.getPreferencesBoolean("plot_motion", false)) { lines.addAll(motionLine()); } + lines.addAll(stepsLines()); } Line[] calib = calibrationValuesLine(); @@ -605,7 +671,7 @@ public List extraLines() line.setHasLines(false); line.setPointRadius(pluginSize); line.setHasPoints(true); - line.setColor(pluginColor); + line.setColor(getCol(X.color_secondary_glucose_value)); lines.add(line); return lines; } diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/ColorCache.java b/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/ColorCache.java index ec0ae1dac2..fff164d2e1 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/ColorCache.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/ColorCache.java @@ -51,7 +51,10 @@ public enum X { color_treatment_dot_foreground("color_treatment_dot_foreground"), color_home_chart_background("color_home_chart_background"), color_notification_chart_background("color_notification_chart_background"), - color_widget_chart_background("color_widget_chart_background"); + color_widget_chart_background("color_widget_chart_background"), + color_secondary_glucose_value("color_secondary_glucose_value"), + color_step_counter1("color_step_counter1"), + color_step_counter2("color_step_counter2"); String internalName; diff --git a/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/pebble/PebbleWatchSync.java b/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/pebble/PebbleWatchSync.java index 561cec5aab..ee99212502 100644 --- a/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/pebble/PebbleWatchSync.java +++ b/app/src/main/java/com/eveningoutpost/dexdrip/UtilityModels/pebble/PebbleWatchSync.java @@ -6,7 +6,9 @@ import android.os.IBinder; import android.preference.PreferenceManager; +import com.eveningoutpost.dexdrip.Models.HeartRate; import com.eveningoutpost.dexdrip.Models.JoH; +import com.eveningoutpost.dexdrip.Models.PebbleMovement; import com.eveningoutpost.dexdrip.Models.UserError.Log; import com.eveningoutpost.dexdrip.UtilityModels.AlertPlayer; import com.eveningoutpost.dexdrip.UtilityModels.BgGraphBuilder; @@ -35,9 +37,17 @@ public class PebbleWatchSync extends Service { private final static String TAG = PebbleWatchSync.class.getSimpleName(); + private final static long sanity_timestamp = 1478197375; + private final static boolean d = false; + + // these must match in watchface + private final static int HEARTRATE_LOG = 101; + private final static int MOVEMENT_LOG = 103; public static int lastTransactionId; + private long last_heartrate_timestamp = 0; + private long last_movement_timestamp = 0; private static Context context; private static BgGraphBuilder bgGraphBuilder; @@ -146,6 +156,93 @@ public void receiveNack(Context context, int transactionId) { } }); + PebbleKit.registerDataLogReceiver(context, new PebbleKit.PebbleDataLogReceiver(currentWatchFaceUUID) { + @Override + public void receiveData(Context context, UUID logUuid, Long timestamp, + Long tag, int data) { + if (d) + Log.d(TAG, "receiveLogData: uuid:" + logUuid + " " + JoH.dateTimeText(timestamp * 1000) + " tag:" + tag + " data: " + data); + } + + @Override + public void receiveData(Context context, UUID logUuid, Long timestamp, + Long tag, Long data) { + Log.d(TAG, "receiveLogData: uuid:" + logUuid + " started: " + JoH.dateTimeText(timestamp * 1000) + " tag:" + tag + " data: " + data); + + if ((tag != null) && (data != null)) { + final int s = (int) (long) tag; + + + switch (s) { + case HEARTRATE_LOG: + if (data > sanity_timestamp) { + if (last_heartrate_timestamp > 0) { + Log.e(TAG, "Out of sequence heartrate timestamp received!"); + } + last_heartrate_timestamp = data; + } else { + if (data > 0) { + if (last_heartrate_timestamp > 0) { + final HeartRate hr = new HeartRate(); + hr.timestamp = last_heartrate_timestamp * 1000; + hr.bpm = (int) (long) data; + Log.d(TAG, "Saving HeartRate: " + hr.toS()); + hr.saveit(); + last_heartrate_timestamp = 0; // reset state + } else { + Log.e(TAG, "Out of sequence heartrate value received!"); + } + } + } + break; + + case MOVEMENT_LOG: + if (data > sanity_timestamp) { + if (last_movement_timestamp > 0) { + Log.e(TAG, "Out of sequence movement timestamp received!"); + } + last_movement_timestamp = data; + } else { + if (data > 0) { + if (last_movement_timestamp > 0) { + final PebbleMovement pm = new PebbleMovement(); + pm.timestamp = last_movement_timestamp * 1000; + pm.metric = (int) (long) data; + Log.d(TAG, "Saving Movement: " + pm.toS()); + pm.saveit(); + last_movement_timestamp = 0; // reset state + } else { + Log.e(TAG, "Out of sequence movement value received!"); + } + } + } + break; + + default: + Log.e(TAG, "Unknown pebble data log type received: " + s); + break; + + } + } else { + Log.e(TAG, "Got null Long in receive data"); + } + } + + + @Override + public void receiveData(Context context, UUID logUuid, Long timestamp, + Long tag, byte[] data) { + if (d) Log.d(TAG,"receiveLogData: uuid:"+logUuid+" "+JoH.dateTimeText(timestamp*1000)+" tag:"+tag+" hexdata: "+JoH.bytesToHex(data)); + } + + @Override + public void onFinishSession(Context context, UUID logUuid, Long timestamp, + Long tag) { + if (d) Log.i(TAG, "Session " + tag + " finished!"); + } + + }); + // control app PebbleKit.registerReceivedDataHandler(context, new PebbleKit.PebbleDataReceiver(PEBBLE_CONTROL_APP_UUID) { @Override diff --git a/app/src/main/res/drawable-xhdpi/ic_heart_pulse_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_heart_pulse_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..53d9bd1b6667060fc6cc74491f0ed7bf8dfd1cad GIT binary patch literal 1237 zcmV;`1SVYX9M(RH>j8!GjjuDm#NcCu z=@vnzf^0Tl_775VTeK>8=&h|{aj6zPY@k-q9s~~_thHJ!(t_=_ZfEj&Xj0Z>x|t*s zJecQ_neThQ=Y4)NUy>QgxY2iCQ=^GO{8Fg3Z8Y;342XAOTzg&Wgxq^YimZ zrlzK@Eao#jJiL6#k|kTU*3SWt0QUd^a31&(IG#u(j_33F%dr4>p11VcwQCu`1(r7` z|4T$BdU|^Dp6A`D^_iQS8_`;4fV&#_Tme)%ot~)mX$rt`oHeFt9s?eWay1s{`*OLw zWqf@696&akU27P|G2qcAeZKX5f6L_L~7 zkq2Ax0nUp^f1yzLH8OzXI4RRKzXtkRY+BXn%ID*4`ke87f8*rjah#P60Zh}}1T2f-Id7Wg zpi=5$p-}kEG|iWRzdOjVtdebU0AN!DGql#9jE;_8s-BOIj$RUx;~fMD%~l5>A`eG2 z`!Hnf;ZCLx%T@=VwO$>;==a{<-kI9*R4R26_@z?-VcEjAP@<7hxm^C(^E@9Qo6YuR zGMV)Np68Vbxic}UE?XGDg@!JP#7EU*5!q!J#`Xns9{}YJ0n}v++d^j>n0zxfHueMD zdcYHrts?S*=Xpy3^7;JFz^P8856foO4it;UfvAQ-5NrcdKd%5LkbTz3V$bw$TrXO41kG=iSNe8$IskuWEg{Ogr}0}VBJ+~ z)3jFi&&|y}RXdo=xJjsSz)x?Qbmd+mVMy4|Z!B~zVGGhbqHUH1_1N`tx^ zTI;pNV(|}vef##U@_qjtkdD~rJ*CtRKu0NV_E$(;*PRA-ELNnoo-qt#dk_TkB63hf zo{#8%NGY{5YWP+Fsu1t6;6ETHy{nXZt(ou;;lV9TrBdlce}Dff5!nz&a;^1&VzD^X zZ1|P|DiELBw!MNj-+4vkZKc%iR>HRh05Cf{J7e4SGT@08!%r0o1*g^UZ39#xEX(Qz z`kP!@R7z#r?cX*4K&ezZX<1eeU`1R~P)gy_KvX%mNgVMZGY9y|{u>n*d zzO-#S2|O7#FCuR#rCyJ-XRH7Kv$M0OEXy*0jWttmDy80tyI<@80HsptE8DjJ1fBu3 zi0oEM6*|$YqsnA5>oS?ly8k*yS6y}0Rp;~%zkF#cI|>mf00000NkvXXu0mjfpshbw literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_walk_grey600_24dp.png b/app/src/main/res/drawable-xhdpi/ic_walk_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ceffae66b090a8ec012cfcde7d54ff3e276ac449 GIT binary patch literal 1065 zcmV+^1lIeBP)+M?tg5&5KUJRzdbT-S9H4`AE& z01^EWGM0$QzEY|5XD9Jh+yF|cBMARc1mJMT@#6+~09?l_Aa(#|J`X@bOj5ITB&oOo z=I7^c4h;_ zb;fZVHa%Y2M36$E@G>)J0c5My>Hz?0qK0pyec#^+VAM1~nr?*n6e3=x0ORnpF<9Xignx1LLiHJU^ z{TDhGBgZHJIF9p#@B90jn5zJ;19)wNfti2E<#HFA#nW21wO5P*EG;eVRZ2b8#C(;R zb4sZ>)J{Gk+67=&i;!&r7%S$KQkfR!InVQc18~;Vc*X$$9Bg5`2mtHr>v<9R*Cc?E zB{ViR_9TF2o3bJzzXQPZ^z6YFq?>6DV0jT$)xM$p=UsAy{Y_A zN*xrD(Edc!J2EnoGFd(}jBO$aGY_{g@9FF7I}u0nfPwpfZQB+R-2t$zMYn$}%X-yu zoMqDh9nSy}?SDY>0PvFU`{SmQHv#})xXpe!+qR!iB0wgjZ7rnj833Oq3Se|}v=>0| zHdZB~qqu(;ZV)0mIX*tVJ23$1bb3EFKh0clUH2k@Qz0(flu}+b=4 z8#EHpdxb(_FcAREd??Vgva+)B(}rSM*2e%ALj2zEIzX{l+(AUI*SCqt&*gIY-iGct z&N4HPVDo-3R|Q9PtW+xRhWO6}`+1(XKt!iaC2S0Uh=R-K?&|95FJXOM*ZnSW00^A_ zM0BoPF0aOws8N8)$;lT0?5S^K=9wt5x&pAawl<8$Lhx2kPtV*V13*NXdR;_j;&^$E z6JR)?cV+oR0?6m{J4K|vo>|aZ|MkcKFmt9}7m==g{YU_TftN>_y|G7Lh jHFcw#0FULd{NLq2D*-EL`L8rt00000NkvXXu0mjfq2J-w literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml index 66baac2c0e..2174136099 100644 --- a/app/src/main/res/layout/activity_home.xml +++ b/app/src/main/res/layout/activity_home.xml @@ -363,6 +363,44 @@ android:paddingRight="4dp" android:paddingBottom="2dp" /> +