From e26e6d7b24b946bae0d751253a5dcc4b25d53ea3 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 16 Mar 2016 00:14:38 +0100 Subject: [PATCH] Display HR firmware version Hide fw,hw,hr versions by default and show them on demand with an info button. --- .../gadgetbridge/adapter/GBDeviceAdapter.java | 78 +++++++++-- .../adapter/ItemWithDetailsAdapter.java | 10 +- .../gadgetbridge/impl/GBDevice.java | 65 +++++++-- .../gadgetbridge/model/GenericItem.java | 62 +++++++++ .../gadgetbridge/model/ItemWithDetails.java | 10 +- .../service/devices/miband/DeviceInfo.java | 15 +-- .../service/devices/miband/MiBandSupport.java | 9 +- .../operations/FetchActivityOperation.java | 2 +- .../ic_information_outline_grey600_24dp.png | Bin 0 -> 1138 bytes .../ic_information_outline_grey600_24dp.png | Bin 0 -> 619 bytes .../ic_information_outline_grey600_24dp.png | Bin 0 -> 1269 bytes .../ic_information_outline_grey600_24dp.png | Bin 0 -> 1814 bytes .../main/res/drawable/information_outline.xml | 8 ++ app/src/main/res/layout/device_item.xml | 126 ++++++++++-------- .../layout/item_with_details_horizontal.xml | 44 ++++++ app/src/main/res/values/strings.xml | 2 + 16 files changed, 336 insertions(+), 95 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_information_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_information_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_information_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_information_outline_grey600_24dp.png create mode 100644 app/src/main/res/drawable/information_outline.xml create mode 100644 app/src/main/res/layout/item_with_details_horizontal.xml 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 6b48ad64..b655a601 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java @@ -8,14 +8,19 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.ImageView; +import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; +import java.text.Collator; +import java.util.Collections; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; +import nodomain.freeyourgadget.gadgetbridge.model.GenericItem; +import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails; /** * Adapter for displaying GBDevice instances. @@ -32,7 +37,7 @@ public class GBDeviceAdapter extends ArrayAdapter { @Override public View getView(int position, View view, ViewGroup parent) { - GBDevice device = getItem(position); + final GBDevice device = getItem(position); if (view == null) { LayoutInflater inflater = (LayoutInflater) context @@ -42,37 +47,59 @@ public class GBDeviceAdapter extends ArrayAdapter { } TextView deviceStatusLabel = (TextView) view.findViewById(R.id.device_status); TextView deviceNameLabel = (TextView) view.findViewById(R.id.device_name); - TextView deviceInfo1Label = (TextView) view.findViewById(R.id.device_info1); - TextView deviceInfo2Label = (TextView) view.findViewById(R.id.device_info2); + final ListView deviceInfoList = (ListView) view.findViewById(R.id.device_item_infos); + ItemWithDetailsAdapter infoAdapter = new ItemWithDetailsAdapter(context, device.getDeviceInfos()); + infoAdapter.setHorizontalAlignment(true); + deviceInfoList.setAdapter(infoAdapter); + TextView batteryLabel = (TextView) view.findViewById(R.id.battery_label); TextView batteryStatusLabel = (TextView) view.findViewById(R.id.battery_status); - ImageView deviceImageView = (ImageView) view.findViewById(R.id.device_image); + final ImageView deviceImageView = (ImageView) view.findViewById(R.id.device_image); + ImageView deviceInfoView = (ImageView) view.findViewById(R.id.device_info_image); ProgressBar busyIndicator = (ProgressBar) view.findViewById(R.id.device_busy_indicator); deviceNameLabel.setText(getUniqueDeviceName(device)); - deviceInfo1Label.setText(device.getHWInfoString()); - deviceInfo2Label.setText(device.getInfoString()); if (device.isBusy()) { deviceStatusLabel.setText(device.getBusyTask()); busyIndicator.setVisibility(View.VISIBLE); + batteryLabel.setVisibility(View.GONE); batteryStatusLabel.setVisibility(View.GONE); - deviceInfo1Label.setVisibility(View.GONE); - deviceInfo2Label.setVisibility(View.GONE); } else { deviceStatusLabel.setText(device.getStateString()); busyIndicator.setVisibility(View.GONE); + batteryLabel.setVisibility(View.VISIBLE); batteryStatusLabel.setVisibility(View.VISIBLE); - deviceInfo1Label.setVisibility(View.VISIBLE); - deviceInfo2Label.setVisibility(View.VISIBLE); } + boolean showInfoIcon = device.hasDeviceInfos() && !device.isBusy(); + deviceInfoView.setVisibility(showInfoIcon ? View.VISIBLE : View.GONE); + deviceInfoView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (deviceInfoList.getVisibility() == View.VISIBLE) { + deviceInfoList.setVisibility(View.GONE); + } else { + ArrayAdapter adapter = (ArrayAdapter) deviceInfoList.getAdapter(); + adapter.clear(); + List infos = device.getDeviceInfos(); + Collections.sort(infos); + adapter.addAll(infos); + justifyListViewHeightBasedOnChildren(deviceInfoList); + deviceInfoList.setVisibility(View.VISIBLE); + } + } + }); + short batteryLevel = device.getBatteryLevel(); if (batteryLevel != GBDevice.BATTERY_UNKNOWN) { - batteryStatusLabel.setText("BAT: " + device.getBatteryLevel() + "%"); + batteryLabel.setText("BAT:"); + batteryStatusLabel.setText(device.getBatteryLevel() + "%"); BatteryState batteryState = device.getBatteryState(); if (BatteryState.BATTERY_LOW.equals(batteryState)) { + batteryLabel.setTextColor(Color.RED); batteryStatusLabel.setTextColor(Color.RED); } else { + batteryLabel.setTextColor(ContextCompat.getColor(getContext(), R.color.secondarytext)); batteryStatusLabel.setTextColor(ContextCompat.getColor(getContext(), R.color.secondarytext)); if (BatteryState.BATTERY_CHARGING.equals(batteryState) || @@ -81,6 +108,7 @@ public class GBDeviceAdapter extends ArrayAdapter { } } } else { + batteryLabel.setText(""); batteryStatusLabel.setText(""); } @@ -98,11 +126,35 @@ public class GBDeviceAdapter extends ArrayAdapter { return view; } + public void justifyListViewHeightBasedOnChildren (ListView listView) { + ArrayAdapter adapter = (ArrayAdapter) listView.getAdapter(); + + if (adapter == null) { + return; + } + ViewGroup vg = listView; + int totalHeight = 0; + for (int i = 0; i < adapter.getCount(); i++) { + View listItem = adapter.getView(i, null, vg); + listItem.measure(0, 0); + totalHeight += listItem.getMeasuredHeight(); + } + + ViewGroup.LayoutParams par = listView.getLayoutParams(); + par.height = totalHeight + (listView.getDividerHeight() * (adapter.getCount() - 1)); + listView.setLayoutParams(par); + listView.requestLayout(); + } + private String getUniqueDeviceName(GBDevice device) { String deviceName = device.getName(); if (!isUniqueDeviceName(device, deviceName)) { - deviceName = deviceName + " " + device.getHardwareVersion(); - if (!isUniqueDeviceName(device, deviceName)) { + if (device.getHardwareVersion() != null) { + deviceName = deviceName + " " + device.getHardwareVersion(); + if (!isUniqueDeviceName(device, deviceName)) { + deviceName = deviceName + " " + device.getShortAddress(); + } + } else { deviceName = deviceName + " " + device.getShortAddress(); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ItemWithDetailsAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ItemWithDetailsAdapter.java index dd1ab2da..fed094ac 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ItemWithDetailsAdapter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/ItemWithDetailsAdapter.java @@ -19,6 +19,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails; public class ItemWithDetailsAdapter extends ArrayAdapter { private final Context context; + private boolean horizontalAlignment; public ItemWithDetailsAdapter(Context context, List items) { super(context, 0, items); @@ -26,6 +27,9 @@ public class ItemWithDetailsAdapter extends ArrayAdapter { this.context = context; } + public void setHorizontalAlignment(boolean horizontalAlignment) { + this.horizontalAlignment = horizontalAlignment; + } @Override public View getView(int position, View view, ViewGroup parent) { ItemWithDetails item = getItem(position); @@ -34,7 +38,11 @@ public class ItemWithDetailsAdapter extends ArrayAdapter { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = inflater.inflate(R.layout.item_with_details, parent, false); + if (horizontalAlignment) { + view = inflater.inflate(R.layout.item_with_details_horizontal, parent, false); + } else { + view = inflater.inflate(R.layout.item_with_details, parent, false); + } } ImageView iconView = (ImageView) view.findViewById(R.id.item_image); TextView nameView = (TextView) view.findViewById(R.id.item_name); 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 9e832494..e296ad98 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java @@ -10,10 +10,15 @@ import android.support.v4.content.LocalBroadcastManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.List; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.model.BatteryState; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; +import nodomain.freeyourgadget.gadgetbridge.model.GenericItem; +import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails; public class GBDevice implements Parcelable { public static final String ACTION_DEVICE_CHANGED @@ -34,6 +39,8 @@ public class GBDevice implements Parcelable { public static final short BATTERY_UNKNOWN = -1; private static final short BATTERY_THRESHOLD_PERCENT = 10; public static final String EXTRA_DEVICE = "device"; + private static final String DEVINFO_HW_VER = "HW: "; + private static final String DEVINFO_FW_VER = "FW: "; private final String mName; private final String mAddress; private final DeviceType mDeviceType; @@ -45,6 +52,8 @@ public class GBDevice implements Parcelable { private BatteryState mBatteryState; private short mRssi = RSSI_UNKNOWN; private String mBusyTask; + private String infoString; + private List mDeviceInfos; public GBDevice(String address, String name, DeviceType deviceType) { mAddress = address; @@ -65,6 +74,7 @@ public class GBDevice implements Parcelable { mBatteryState = (BatteryState) in.readSerializable(); mRssi = (short) in.readInt(); mBusyTask = in.readString(); + mDeviceInfos = in.readArrayList(getClass().getClassLoader()); validate(); } @@ -82,6 +92,7 @@ public class GBDevice implements Parcelable { dest.writeSerializable(mBatteryState); dest.writeInt(mRssi); dest.writeString(mBusyTask); + dest.writeList(mDeviceInfos); } private void validate() { @@ -213,18 +224,6 @@ public class GBDevice implements Parcelable { return GBApplication.getContext().getString(R.string.unknown_state); } - - public String getInfoString() { - if (mFirmwareVersion != null) { - if (mHardwareVersion != null) { - return GBApplication.getContext().getString(R.string.connectionstate_hw_fw, mHardwareVersion, mFirmwareVersion); - } - return GBApplication.getContext().getString(R.string.connectionstate_fw, mFirmwareVersion); - } else { - return ""; - } - } - public DeviceType getType() { return mDeviceType; } @@ -330,6 +329,48 @@ public class GBDevice implements Parcelable { return ""; } + public boolean hasDeviceInfos() { + return getDeviceInfos().size() > 0; + } + + public List getDeviceInfos() { + List result = new ArrayList<>(); + if (mDeviceInfos != null) { + result.addAll(mDeviceInfos); + } + if (mHardwareVersion != null) { + result.add(new GenericItem(DEVINFO_HW_VER, mHardwareVersion)); + } + if (mFirmwareVersion != null) { + result.add(new GenericItem(DEVINFO_FW_VER, mFirmwareVersion)); + } + return result; + } + + public void setDeviceInfos(List deviceInfos) { + this.mDeviceInfos = deviceInfos; + } + + public void addDeviceInfo(ItemWithDetails info) { + if (mDeviceInfos == null) { + mDeviceInfos = new ArrayList<>(); + } else { + int index = mDeviceInfos.indexOf(info); + if (index >= 0) { + mDeviceInfos.set(index, info); // replace item with new one + return; + } + } + mDeviceInfos.add(info); + } + + public boolean removeDeviceInfo(ItemWithDetails info) { + if (mDeviceInfos == null) { + return false; + } + return mDeviceInfos.remove(info); + } + public enum State { // Note: the order is important! NOT_CONNECTED, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/GenericItem.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/GenericItem.java index f2350768..1e28c869 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/GenericItem.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/GenericItem.java @@ -1,10 +1,31 @@ package nodomain.freeyourgadget.gadgetbridge.model; +import android.os.Parcel; +import android.os.Parcelable; + +import java.text.Collator; + public class GenericItem implements ItemWithDetails { private String name; private String details; private int icon; + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public GenericItem createFromParcel(Parcel source) { + GenericItem item = new GenericItem(); + item.setName(source.readString()); + item.setDetails(source.readString()); + item.setIcon(source.readInt()); + return item; + } + + @Override + public GenericItem[] newArray(int size) { + return new GenericItem[size]; + } + }; + public GenericItem(String name, String details) { this.name = name; this.details = details; @@ -17,6 +38,13 @@ public class GenericItem implements ItemWithDetails { public GenericItem() { } + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(getName()); + dest.writeString(getDetails()); + dest.writeInt(getIcon()); + } + public void setName(String name) { this.name = name; } @@ -43,4 +71,38 @@ public class GenericItem implements ItemWithDetails { public int getIcon() { return icon; } + + @Override + public int describeContents() { + return 0; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + GenericItem that = (GenericItem) o; + + return !(getName() != null ? !getName().equals(that.getName()) : that.getName() != null); + + } + + @Override + public int hashCode() { + return getName() != null ? getName().hashCode() : 0; + } + + @Override + public int compareTo(ItemWithDetails another) { + if (getName() == another.getName()) { + return 0; + } + if (getName() == null) { + return +1; + } else if (another.getName() == null) { + return -1; + } + return Collator.getInstance().compare(getName(), another.getName()); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ItemWithDetails.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ItemWithDetails.java index dcb76883..0c5dc497 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ItemWithDetails.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ItemWithDetails.java @@ -1,9 +1,17 @@ package nodomain.freeyourgadget.gadgetbridge.model; -public interface ItemWithDetails { +import android.os.Parcelable; + +public interface ItemWithDetails extends Parcelable, Comparable { String getName(); String getDetails(); int getIcon(); + + /** + * Equality is based on #getName() only. + * @param other + */ + boolean equals(Object other); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java index 5a704497..74450139 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/DeviceInfo.java @@ -67,14 +67,6 @@ public class DeviceInfo extends AbstractInfo { return getInt(data, from, 4); } - public String getHumanFirmwareVersion() { - return MiBandFWHelper.formatFirmwareVersion(fwVersion); - } - - public String getHumanFirmware2Version() { - return MiBandFWHelper.formatFirmwareVersion(fw2Version); - } - public int getFirmwareVersion() { return fwVersion; } @@ -83,6 +75,10 @@ public class DeviceInfo extends AbstractInfo { return fw2Version; } + public boolean supportsHeartrate() { + return isMilli1S(); + } + @Override public String toString() { return "DeviceInfo{" + @@ -117,8 +113,7 @@ public class DeviceInfo extends AbstractInfo { return MiBandConst.MI_1A; } if (isMilli1S()) { - return getHumanFirmware2Version(); -// return MiBandConst.MI_1S; + return MiBandConst.MI_1S; } return "?"; } 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 53272f32..be8b6182 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 @@ -36,6 +36,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.CalendarEvents; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; +import nodomain.freeyourgadget.gadgetbridge.model.GenericItem; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; @@ -551,7 +552,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } public boolean supportsHeartRate() { - return getDeviceInfo() != null && getDeviceInfo().isMilli1S(); + return getDeviceInfo() != null && getDeviceInfo().supportsHeartrate(); } @Override @@ -815,9 +816,12 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { private void handleDeviceInfo(byte[] value, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { mDeviceInfo = new DeviceInfo(value); + if (getDeviceInfo().supportsHeartrate()) { + getDevice().addDeviceInfo(new GenericItem("HR:", MiBandFWHelper.formatFirmwareVersion(mDeviceInfo.getHeartrateFirmwareVersion()))); + } LOG.warn("Device info: " + mDeviceInfo); versionCmd.hwVersion = mDeviceInfo.getHwVersion(); - versionCmd.fwVersion = mDeviceInfo.getHumanFirmwareVersion(); + versionCmd.fwVersion = MiBandFWHelper.formatFirmwareVersion(mDeviceInfo.getFirmwareVersion()); handleGBDeviceEvent(versionCmd); } } @@ -936,7 +940,6 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { List mEvents = upcomingEvents.getCalendarEventList(getContext()); int iteration = 0; - ArrayList alarmList = new ArrayList<>(); for (CalendarEvents.CalendarEvent mEvt : mEvents) { if (iteration >= availableSlots || iteration > 2) { break; 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 e5e14441..42faa337 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 @@ -137,7 +137,7 @@ public class FetchActivityOperation extends AbstractMiBandOperation { public FetchActivityOperation(MiBandSupport support) { super(support); - hasExtendedActivityData = support.getDeviceInfo().isMilli1S(); + hasExtendedActivityData = support.getDeviceInfo().supportsHeartrate(); activityDataHolderSize = getBytesPerMinuteOfActivityData() * 60 * 4; // 4h activityStruct = new ActivityStruct(activityDataHolderSize); } diff --git a/app/src/main/res/drawable-hdpi/ic_information_outline_grey600_24dp.png b/app/src/main/res/drawable-hdpi/ic_information_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..28ac3bdda4777e8c1e28ba359692b5276abdf8b9 GIT binary patch literal 1138 zcmV-&1daQNP)7%Q6#m|dY&Kin z6G0Ob6Lx+SVmFxi8)iNW;5Q<=3INPJ2;e>JFk!rPNd;5;-lUtTY+(i~ju}rF^|uEFKj?Ofz%8p3w19sdNCq^IBl= z3MCSW_W&F>TxYkpw_jXZTKcn_XBCgf_x1MnehlES;eOwB-M5>?TP?&q17Oh*yky(< z%b84OyBje8kk99DjE;_eRxX$C1~8)CkHliJpL4m~rH&PnQucbD_bY%w?fQ0oef{ZH z%Qu-!J`CV70AS_|uIrv}7UwvQH8eEz6@VwT>#A+r4@xN;CMo;_JUuTY*h#`PDGp9HK@57&>+Zh91Fm)nyr+YN~hCX-9DyPNT<_V zN~tNsbxd8EwuYz5yp6E3AX2UP2 zzQik)O8;Jw`f@jXR{SsZ<=VAnSqJt?keS=$+#!gFRt@usy%J>R_Hi}}5<+}!m}64P z5Ox_l=U5BQMnQ!_VHLnNZ4MNR#iP3|Naw6IZr3ztb3u9&J!z<)PNh#hry6%_$*rqej<#Lx|vDh5|9@Vaqa=AP_JUskeKA*qQjhJ{m zzK@x+0LBgXjO)6mn#H#}bx<;y{FIryY4XjggnUhYEyw4XOr~X%-)>oRI2?Y#^Sm|a zV-Pd<6VXSW=e;vIIob9Yck&%%P zEz8;h@DKnyppffCG+n7wUYehu|0&3T|J|Prw{gqiZ@=c#YoLbajsO4v07*qoM6N<$ Eg7w-6a{vGU literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_information_outline_grey600_24dp.png b/app/src/main/res/drawable-mdpi/ic_information_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..213286b7faa55326b87cf11a73d69c411095f5ff GIT binary patch literal 619 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjY)RhkE(}6TtKSPDj(q#+`jNd$6978;gU!A%!U)WIM=za0adXh%MoPEJF zU$h(%am~4@bTMqx5B5`@qRB<=H}afs9KW)VId+DBR`-!r}8e+xHbFy^Zd>i4@^S)JpIr&UE zgMgEb!LgE#7px8L*F5~yCST8-B{jW#dCr3a>pNCVPrVr!$&$d5pt98FOYQ%LnfC<) zUsTF5xN!epaR2>#p^KfZo>bC-pHK5eL&;%rp2jY@1|YtVaSOLyU1{$@9vt% zU1t~>qOvbVh0oh#;>&9+zk5v+qo6G#gW{2(o#CPD&PK8_r|rwWecH9bwfcd9UTm1< zqODV;FZ$oUw_j7|`m;4fF3%YfdS2eSq5$TkU#pGx(hO_$)?^iY3pDFsiIpvL0b|1L z?|+*^dDo;#A81Ye+j(~GmcG@C1dbM1{JE92^_9yPkprL0cK=;{GpA0j|M*n*U@y&G zci(xZ{Y!Xg82_Jw!+^21>Cxtl1aHX7hdzzT)g;_GPoX z*=w4C4YbzYO370G$9#FT??`4&Vva_{Ha2#Gh$e~X9RSVM zOag#BGk?y^6Vubvj}KiyEEc;8;1d8RswA%BF@O)#>GT(eA|Mip1jFI*rvTp7wKH>$ zh~}C3djP)#gTV(aEiG99*xud_@9gZH2Jj*gy~fN#L=-BKYSuK(Q6WU3W&(r|ZI0u7 z3E&M)^8)}$(==}jA#!Do7jhiu3V?9{r!^tpn5Oxb5Mrxp0p84i1>mC6v<*O*ra2>o z$d^N0Bc$1JoG1VRphaoElg(x?XEK=`zcHHjOX9sYD)~o-VZ1ptHMLj?aY;ZPz{iP1 z;s@7tzXtHU)O^v){hr?#zE8litSdyME~?*mcXwZ(nVI>s8uBWl(P&p75cn3rS=rCb zS8dzAeP99O><=%;gyO#DaVk#$Gk<{M9d<37%}yUS`6uvltx2wCkJJ7Fgb)UR5!pvXsr^1@ zwL~V9*&(8o;vVt16=BaB*xK591=7KcnRCoMcTf`Lyz_o=U3U(^w6tS)dfa}J9dIHw4>S8wt@xzDLFIsx6X;kxdxjS`^A-L1yx z_JLEf!OUx@0F~?mDwuhVsHod1HAeRY+KY_#_P;9;Pzz{sx2rKmnPWY*&1nWgU5{U$vIj*>G=}M8>eSnBQ10Yu#&V<9^v3d#ca>-wyyvJz|v;w?; z-W!U0(z2}n!zSzX>2jM7@=ap&-x9v&?+iw(X^Zc0QVyd@34w f&3cSu9CiEyReujo$LVw-00000NkvXXu0mjf&pu4; literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_information_outline_grey600_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_information_outline_grey600_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..fb2acbc6a12a7f7540163e6df80d5da0fa04a192 GIT binary patch literal 1814 zcmV+x2kH2UP)bx13{R3cc$I# zba8%~Hh=_=Yh^SR)q(3Nx7*{A1+K8xynP&l*4WJ3YBmlbGtN@@F zKo5W`M0AyzFX*~{RtRzDi4({$j3y%5Kt!vUc@cmyLv(eQh|V$dF=jrH$z*zJTA)-a z^$HQCn0YyX`U<-rAfl7ZY}>Z|V@(NU7{(GJ+6Lg|Y6boXKQZ&xOeS->(vB-C(B{pX zpNhp|Spe%sNSH@CR4SE{J9qBEh`KdR>xswX1pp`(i@M`DP0T!#nP+R7_7XEM!M)MW zFP|5S#bifEM}KGnB@&4V@p$|gfTcc~_X0TRjy~rAaL`x{!&pQ_8vv}wy|SPjr;5em zs*aA1zeil4EnBus85kJ&0l=IxO>Y3m>bkyL2+=px?>&qVqM=YId7whZm zU){ca`^^y(D4kAEbR6e&8F2;xbm+RiwNk=JgxUrm0d*O1QPZ>~?d|Qit1gfbVoae> z_#VJAMYC=qT4Pz(`DzIBD5h!7XXYaSW-6L>>bm}#5aMnS-&)XM`uh4lEhEl}VzD@9 zq{IOL%d*ZFi^VwrPAHl!b7K!gU696xVXPq{OVQ-Zd_Moy{{8!lBPGs#y1Kghr%#`L zq_MH_X#jJ*+7Qu#*4EbFa=F|kzkYrH#M~nAGJr;zIJRxShv1`Ar6I#G_7TxL68o)E zsr0~PQ`5A0 zLm46NlS-vLg|%&a$YqE-(*6qI8PCLtmRXi{s+=ERJ;-sKZ4%P}5v?7LIMt%Pz5O;3 zt;M}^BS=oc1WG28i;1Ys%SJ@IMsl$D)z#IR64MO;B5V7% z+*o@(O!aP#Qk2V}nx?(Z{P+OF%!evDzZ%YHi0C7)90BZ5{HhAwo+_Ws~m#`BKiW{@nlE)Y~*I)t>QH#XXiP2Fp z2Zi0(gXAg~$Z?$KJio$xF6>N)iY#_nu7J7+&60fN_plQkDzeyRxdQ4@Y?{}@SSRE;&_VKcJ0x!A# z-%ttUsdj&V|9I3WirA&U3Y9>fQwe7Fvtc(XQN%8tHmL-m(!JH<537sJjrC~nMCJWO}pT!RTDgt$XQvdP`sVJ93ES@Y6Kxf0}**13zX&POCSIT;k~ak$vvM_6S%Q@)j$Joj#88YWipu_B04EC zCr#5F^;NYSW75k;L?_FgwJtjs8yp;zo#vQ|+SwQLJcXvn?Ez&4%4V}?nA!8MJTq@H zO>=(O3dnE|R&A2Rem0xUo*A}40HA5wR*9*enGdJa>9CLfK1Mp7p2*CHAz2huHy@MY{&EY{2ND)9v$@SubQl0y}GWsx%nFaD?Kyh@yen(N%xg25 z%n`pn1D#RK<#Lx=TU(omXn~~3yvD}Hxh*X%-*t6$4eNw^P!fs6gvpa99|7>DLYyx$ znT#F8Z{Q`@hK7buAlZO(SrL!NFOKBsW}4>wcsza)zzRjPPB->IL + + + \ No newline at end of file diff --git a/app/src/main/res/layout/device_item.xml b/app/src/main/res/layout/device_item.xml index 246dca8d..d7b4b1bb 100644 --- a/app/src/main/res/layout/device_item.xml +++ b/app/src/main/res/layout/device_item.xml @@ -1,75 +1,93 @@ - + - + android:singleLine="true" + android:typeface="sans" /> - + - + - + - + - - - + - - \ No newline at end of file + + + + + diff --git a/app/src/main/res/layout/item_with_details_horizontal.xml b/app/src/main/res/layout/item_with_details_horizontal.xml new file mode 100644 index 00000000..8c318025 --- /dev/null +++ b/app/src/main/res/layout/item_with_details_horizontal.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 22fafcfd..3d60e89a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -231,5 +231,7 @@ Add widget Preferred sleep duration in hours An alarm was set for %1$02d:%2$02d + HW: %1$s + FW: %1$s