Make firmware and app installation a bit more user friendly #30

live-activity-data
cpfeiffer 2015-08-30 00:21:51 +02:00
parent 87a5b09e43
commit 41d8bcf634
14 changed files with 274 additions and 33 deletions

View File

@ -12,17 +12,25 @@ import android.support.v4.content.LocalBroadcastManager;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
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.adapter.ItemWithDetailsAdapter;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -47,13 +55,14 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
} else if (action.equals(GBDevice.ACTION_DEVICE_CHANGED)) {
device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
if (device != null) {
refreshBusyState(device);
if (!device.isInitialized()) {
setInstallEnabled(false);
if (mayConnect) {
GB.toast(FwAppInstallerActivity.this, getString(R.string.connecting), Toast.LENGTH_SHORT, GB.INFO);
connect();
} else {
setInfoText(device.getStateString());
setInfoText(getString(R.string.fwappinstaller_connection_state, device.getStateString()));
}
} else {
validateInstallation();
@ -62,6 +71,22 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
}
}
};
private ProgressBar mProgressBar;
private ListView itemListView;
private List<ItemWithDetails> mItems = new ArrayList<>();
private ItemWithDetailsAdapter mItemAdapter;
private void refreshBusyState(GBDevice dev) {
if (dev.isConnecting() || dev.isBusy()) {
mProgressBar.setVisibility(View.VISIBLE);
} else {
boolean wasBusy = mProgressBar.getVisibility() != View.GONE;
if (wasBusy) {
mProgressBar.setVisibility(View.GONE);
// done!
}
}
}
private void connect() {
mayConnect = false; // only do that once per #onCreate
@ -84,8 +109,12 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
device = dev;
}
mayConnect = true;
fwAppInstallTextView = (TextView) findViewById(R.id.debugTextView);
itemListView = (ListView) findViewById(R.id.itemListView);
mItemAdapter = new ItemWithDetailsAdapter(this, mItems);
itemListView.setAdapter(mItemAdapter);
fwAppInstallTextView = (TextView) findViewById(R.id.infoTextView);
installButton = (Button) findViewById(R.id.installButton);
mProgressBar = (ProgressBar) findViewById(R.id.installProgressBar);
setInstallEnabled(false);
IntentFilter filter = new IntentFilter();
filter.addAction(ControlCenter.ACTION_QUIT);
@ -152,4 +181,17 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
public void setInstallEnabled(boolean enable) {
installButton.setEnabled(device != null && device.isConnected() && enable);
}
@Override
public void clearInstallItems() {
mItems.clear();
mItemAdapter.notifyDataSetChanged();
}
@Override
public void setInstallItem(ItemWithDetails item) {
mItems.clear();
mItems.add(item);
mItemAdapter.notifyDataSetChanged();
}
}

View File

@ -1,6 +1,12 @@
package nodomain.freeyourgadget.gadgetbridge.activities;
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
public interface InstallActivity {
void setInfoText(String text);
void setInstallEnabled(boolean enable);
void clearInstallItems();
void setInstallItem(ItemWithDetails item);
}

View File

@ -33,11 +33,11 @@ public class DeviceCandidateAdapter extends ArrayAdapter<GBDeviceCandidate> {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.device_candidate_item, parent, false);
view = inflater.inflate(R.layout.item_with_details, parent, false);
}
ImageView deviceImageView = (ImageView) view.findViewById(R.id.device_candidate_image);
TextView deviceNameLabel = (TextView) view.findViewById(R.id.device_candidate_name);
TextView deviceAddressLabel = (TextView) view.findViewById(R.id.device_candidate_address);
ImageView deviceImageView = (ImageView) view.findViewById(R.id.item_image);
TextView deviceNameLabel = (TextView) view.findViewById(R.id.item_name);
TextView deviceAddressLabel = (TextView) view.findViewById(R.id.item_details);
String name = formatDeviceCandidate(device);
deviceNameLabel.setText(name);

View File

@ -31,11 +31,11 @@ public class GBDeviceAppAdapter extends ArrayAdapter<GBDeviceApp> {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.device_candidate_item, parent, false);
view = inflater.inflate(R.layout.item_with_details, parent, false);
}
TextView deviceAppVersionAuthorLabel = (TextView) view.findViewById(R.id.device_candidate_address);
TextView deviceAppNameLabel = (TextView) view.findViewById(R.id.device_candidate_name);
ImageView deviceImageView = (ImageView) view.findViewById(R.id.device_candidate_image);
TextView deviceAppVersionAuthorLabel = (TextView) view.findViewById(R.id.item_details);
TextView deviceAppNameLabel = (TextView) view.findViewById(R.id.item_name);
ImageView deviceImageView = (ImageView) view.findViewById(R.id.item_image);
deviceAppVersionAuthorLabel.setText(getContext().getString(R.string.appversion_by_creator, deviceApp.getVersion(), deviceApp.getCreator()));
deviceAppNameLabel.setText(deviceApp.getName());

View File

@ -0,0 +1,46 @@
package nodomain.freeyourgadget.gadgetbridge.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
public class ItemWithDetailsAdapter extends ArrayAdapter<ItemWithDetails> {
private final Context context;
public ItemWithDetailsAdapter(Context context, List<ItemWithDetails> items) {
super(context, 0, items);
this.context = context;
}
@Override
public View getView(int position, View view, ViewGroup parent) {
ItemWithDetails item = getItem(position);
if (view == null) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
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);
TextView detailsView = (TextView) view.findViewById(R.id.item_details);
nameView.setText(item.getName());
detailsView.setText(item.getDetails());
iconView.setImageResource(item.getIcon());
return view;
}
}

View File

@ -30,7 +30,8 @@ public class MiBandFWHelper {
private final int[] whitelistedFirmwareVersion = {
16779534, // 1.0.9.14 tested by developer
16779547, //1.0.9.27 tested by developer
16779568 //1.0.9.48 tested by developer
16779568, //1.0.9.48 tested by developer
16779585, //1.0.9.65 tested by developer
};
public MiBandFWHelper(Uri uri, Context context) throws IOException {

View File

@ -13,6 +13,7 @@ import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
public class MiBandFWInstallHandler implements InstallHandler {
private static final Logger LOG = LoggerFactory.getLogger(MiBandFWInstallHandler.class);
@ -34,21 +35,35 @@ public class MiBandFWInstallHandler implements InstallHandler {
@Override
public void validateInstallation(InstallActivity installActivity, GBDevice device) {
if (device.isBusy() || device.getType() != DeviceType.MIBAND || !device.isInitialized()) {
installActivity.setInfoText("Element cannot be installed");
if (device.isBusy()) {
installActivity.setInfoText(device.getBusyTask());
installActivity.setInstallEnabled(false);
return;
}
if (device.getType() != DeviceType.MIBAND || !device.isInitialized()) {
installActivity.setInfoText(mContext.getString(R.string.fwapp_install_device_not_ready));
installActivity.setInstallEnabled(false);
return;
}
GenericItem fwItem = new GenericItem(mContext.getString(R.string.miband_installhandler_miband_firmware, helper.getHumanFirmwareVersion()));
fwItem.setIcon(R.drawable.ic_device_miband);
StringBuilder builder = new StringBuilder(mContext.getString(R.string.fw_upgrade_notice, helper.getHumanFirmwareVersion()));
if (helper.isFirmwareWhitelisted()) {
builder.append(" ").append(mContext.getString(R.string.miband_firmware_known));
fwItem.setDetails(mContext.getString(R.string.miband_fwinstaller_compatible_version));
// TODO: set a CHECK (OKAY) button
} else {
builder.append(" ").append(mContext.getString(R.string.miband_firmware_unknown_warning)).append(" ")
builder.append(" ").append(mContext.getString(R.string.miband_firmware_unknown_warning)).append(" \n\n")
.append(mContext.getString(R.string.miband_firmware_suggest_whitelist, helper.getFirmwareVersion()));
fwItem.setDetails(mContext.getString(R.string.miband_fwinstaller_untested_version));
// TODO: set a UNKNOWN (question mark) button
}
installActivity.setInfoText(builder.toString());
installActivity.setInstallItem(fwItem);
installActivity.setInstallEnabled(true);
}

View File

@ -12,6 +12,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
public class PBWInstallHandler implements InstallHandler {
@ -27,7 +28,12 @@ public class PBWInstallHandler implements InstallHandler {
@Override
public void validateInstallation(InstallActivity installActivity, GBDevice device) {
if (device.isBusy() || device.getType() != DeviceType.PEBBLE || !device.isConnected()) {
if (device.isBusy()) {
installActivity.setInfoText(device.getBusyTask());
installActivity.setInstallEnabled(false);
return;
}
if (device.getType() != DeviceType.PEBBLE || !device.isConnected()) {
installActivity.setInfoText("Element cannot be installed");
installActivity.setInstallEnabled(false);
return;
@ -40,18 +46,30 @@ public class PBWInstallHandler implements InstallHandler {
return;
}
GenericItem installItem = new GenericItem();
installItem.setIcon(R.drawable.ic_device_pebble);
if (mPBWReader.isFirmware()) {
String hwRevision = mPBWReader.getHWRevision();
if (hwRevision != null && hwRevision.equals(device.getHardwareVersion())) {
installItem.setName(mContext.getString(R.string.pbw_installhandler_pebble_firmware, ""));
installItem.setDetails(mContext.getString(R.string.pbwinstallhandler_correct_hw_revision));
installActivity.setInfoText(mContext.getString(R.string.firmware_install_warning, hwRevision));
installActivity.setInstallEnabled(true);
} else {
if (hwRevision != null) {
installItem.setName(mContext.getString(R.string.pbw_installhandler_pebble_firmware, hwRevision));
installItem.setDetails(mContext.getString(R.string.pbwinstallhandler_incorrect_hw_revision));
}
installActivity.setInfoText(mContext.getString(R.string.pbw_install_handler_hw_revision_mismatch));
installActivity.setInstallEnabled(false);
}
} else {
GBDeviceApp app = mPBWReader.getGBDeviceApp();
if (app != null) {
installItem.setName(app.getName());
installItem.setDetails(mContext.getString(R.string.pbwinstallhandler_app_item, app.getCreator(), app.getVersion()));
installActivity.setInfoText(mContext.getString(R.string.app_install_info, app.getName(), app.getVersion(), app.getCreator()));
installActivity.setInstallEnabled(true);
} else {
@ -59,6 +77,10 @@ public class PBWInstallHandler implements InstallHandler {
installActivity.setInstallEnabled(false);
}
}
if (installItem.getName() != null) {
installActivity.setInstallItem(installItem);
}
}
@Override

View File

@ -0,0 +1,46 @@
package nodomain.freeyourgadget.gadgetbridge.model;
public class GenericItem implements ItemWithDetails {
private String name;
private String details;
private int icon;
public GenericItem(String name, String details) {
this.name = name;
this.details = details;
}
public GenericItem(String name) {
this.name = name;
}
public GenericItem() {
}
public void setName(String name) {
this.name = name;
}
public void setDetails(String details) {
this.details = details;
}
public void setIcon(int icon) {
this.icon = icon;
}
@Override
public String getName() {
return name;
}
@Override
public String getDetails() {
return details;
}
@Override
public int getIcon() {
return icon;
}
}

View File

@ -0,0 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.model;
public interface ItemWithDetails {
String getName();
String getDetails();
int getIcon();
}

View File

@ -12,10 +12,12 @@ import java.io.IOException;
import java.util.Arrays;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEOperation;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceBusyAction;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetProgressAction;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport;
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
@ -50,6 +52,10 @@ public class UpdateFirmwareOperation extends AbstractBTLEOperation<MiBandSupport
//the firmware will be sent by the notification listener if the band confirms that the metadata are ok.
}
private void done() {
getDevice().unsetBusyTask();
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
@ -88,6 +94,7 @@ public class UpdateFirmwareOperation extends AbstractBTLEOperation<MiBandSupport
} else {
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
GB.toast("Problem with the firmware transfer. DO NOT REBOOT YOUR MIBAND!!!", Toast.LENGTH_LONG, GB.ERROR);
done();
}
firmwareInfoSent = false;
newFirmware = null;
@ -97,6 +104,7 @@ public class UpdateFirmwareOperation extends AbstractBTLEOperation<MiBandSupport
GB.toast("Problem with the firmware metadata transfer", Toast.LENGTH_LONG, GB.ERROR);
firmwareInfoSent = false;
newFirmware = null;
done();
break;
case MiBandService.NOTIFY_FIRMWARE_UPDATE_SUCCESS:
if (rebootWhenBandReady) {
@ -104,12 +112,14 @@ public class UpdateFirmwareOperation extends AbstractBTLEOperation<MiBandSupport
getSupport().onReboot();
}
rebootWhenBandReady = false;
done();
break;
case MiBandService.NOTIFY_FIRMWARE_UPDATE_FAILED:
//TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do?
GB.toast("Problem with the firmware transfer. DO NOT REBOOT YOUR MIBAND!!!", Toast.LENGTH_LONG, GB.ERROR);
GB.updateInstallNotification("Firmware write failed", false, 0, getContext());
rebootWhenBandReady = false;
done();
break;
default:
@ -149,6 +159,7 @@ public class UpdateFirmwareOperation extends AbstractBTLEOperation<MiBandSupport
(byte) (checksum >> 8)
};
TransactionBuilder builder = performInitialized("send firmware info");
builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.updating_firmware), getContext()));
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), fwInfo);
builder.queue(getQueue());
}

View File

@ -1,4 +1,4 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -6,20 +6,52 @@
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.FwAppInstallerActivity">
<ListView
android:id="@+id/itemListView"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1"
>
</ListView>
<TextView
android:id="@+id/debugTextView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:id="@+id/infoTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
/>
<ImageView
android:id="@+id/fwappStatusIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="Status Icon"
android:layout_weight="0"
/>
<ProgressBar
android:id="@+id/installProgressBar"
android:layout_width="40dp"
android:layout_height="40dp"
android:indeterminate="true"
android:layout_gravity="center_horizontal"
android:visibility="gone"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/appinstaller_install"
android:id="@+id/installButton"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:enabled="false" />
</RelativeLayout>
<android.widget.Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="3"/>
</LinearLayout>

View File

@ -6,7 +6,7 @@
android:padding="8dp" >
<ImageView
android:id="@+id/device_candidate_image"
android:id="@+id/item_image"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentStart="true"
@ -16,24 +16,27 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/device_candidate_image"
android:layout_toEndOf="@+id/item_image"
android:orientation="vertical"
android:paddingStart="8dp"
android:paddingEnd="8dp">
<TextView
android:id="@+id/device_candidate_name"
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollHorizontally="false"
android:textStyle="bold"
style="@style/Base.TextAppearance.AppCompat.SearchResult.Title"
android:text="Item Name"
android:singleLine="true" />
<TextView
android:id="@+id/device_candidate_address"
android:id="@+id/item_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="normal" />
style="@style/Base.TextAppearance.AppCompat.SearchResult"
android:text="Item Description"
/>
</LinearLayout>
</RelativeLayout>

View File

@ -20,10 +20,10 @@
<!-- Strings related to FwAppInstaller -->
<string name="title_activity_fw_app_insaller">FW/App installer</string>
<string name="fw_upgrade_notice">You are about to install firmware %s instead of the one currently on your MiBand.</string>
<string name="miband_firmware_known">This firmware has been tested and is known to be compatible with GadgetBridge.</string>
<string name="miband_firmware_unknown_warning">"This firmware is untested and may not be compatible with GadgetBridge. You are not encouraged to flash it to your MiBand. "</string>
<string name="miband_firmware_suggest_whitelist">If you still want to proceed and things continue to work properly afterwards, please tell the GadgetBridge developers to whitelist firmware version: %s</string>
<string name="fw_upgrade_notice">You are about to install firmware %s instead of the one currently on your Mi Band.</string>
<string name="miband_firmware_known">This firmware has been tested and is known to be compatible with Gadgetbridge.</string>
<string name="miband_firmware_unknown_warning">"This firmware is untested and may not be compatible with Gadgetbridge.\n\nYou are NOT encouraged to flash it to your Mi Band!"</string>
<string name="miband_firmware_suggest_whitelist">If you still want to proceed and things continue to work properly afterwards, please tell the Gadgetbridge developers to whitelist firmware version: %s</string>
<!-- Strings related to Settings -->
<string name="title_activity_settings">Settings</string>
@ -161,7 +161,7 @@
<string name="installer_activity_unable_to_find_handler">Unable to find a handler to install this file.</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="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">%1$s battery left: %2$s%%</string>
<string name="notif_battery_low_bigtext_last_charge_time">Last charge: %s \n</string>
@ -169,4 +169,14 @@
<string name="sleepchart_your_sleep">Your Sleep</string>
<string name="weekstepschart_steps_a_week">Steps a week</string>
<string name="activity_sleepchart_activity_and_sleep">Your Activity and Sleep</string>
<string name="updating_firmware">Updating Firmware…</string>
<string name="fwapp_install_device_not_ready">File cannot be installed, device not ready.</string>
<string name="miband_installhandler_miband_firmware">Mi Band Firmware %1$s</string>
<string name="miband_fwinstaller_compatible_version">Compatible version</string>
<string name="miband_fwinstaller_untested_version">Untested version!</string>
<string name="fwappinstaller_connection_state">Connection to device: %1$s</string>
<string name="pbw_installhandler_pebble_firmware">Pebble Firmware %1$s</string>
<string name="pbwinstallhandler_correct_hw_revision">Correct hardware revision</string>
<string name="pbwinstallhandler_incorrect_hw_revision">Hardware revision mismatch!</string>
<string name="pbwinstallhandler_app_item">%1$s (%2$s)</string>
</resources>