Add some progress to firmware updating #271 #234

Also: remove the low latency mode for firmware update,
because my Mi1S simply disconnects then.

Still missing in the view: device disconnects
here
cpfeiffer 2016-04-03 00:50:45 +02:00
parent 7a224243a3
commit a4919789ca
8 changed files with 164 additions and 18 deletions

View File

@ -29,6 +29,7 @@ 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.GenericItem;
import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -37,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class FwAppInstallerActivity extends Activity implements InstallActivity {
private static final Logger LOG = LoggerFactory.getLogger(FwAppInstallerActivity.class);
private static final String ITEM_DETAILS = "details";
private TextView fwAppInstallTextView;
private Button installButton;
@ -45,13 +47,22 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
private InstallHandler installHandler;
private boolean mayConnect;
private ProgressBar mProgressBar;
private ListView itemListView;
private final List<ItemWithDetails> mItems = new ArrayList<>();
private ItemWithDetailsAdapter mItemAdapter;
private ListView detailsListView;
private ItemWithDetailsAdapter mDetailsItemAdapter;
private ArrayList<ItemWithDetails> mDetails = new ArrayList<>();
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(GBApplication.ACTION_QUIT)) {
if (GBApplication.ACTION_QUIT.equals(action)) {
finish();
} else if (action.equals(GBDevice.ACTION_DEVICE_CHANGED)) {
} else if (GBDevice.ACTION_DEVICE_CHANGED.equals(action)) {
device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
if (device != null) {
refreshBusyState(device);
@ -67,13 +78,13 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
validateInstallation();
}
}
} else if (GB.ACTION_DISPLAY_MESSAGE.equals(action)) {
String message = intent.getStringExtra(GB.DISPLAY_MESSAGE_MESSAGE);
int severity = intent.getIntExtra(GB.DISPLAY_MESSAGE_SEVERITY, GB.INFO);
addMessage(message, severity);
}
}
};
private ProgressBar mProgressBar;
private ListView itemListView;
private final List<ItemWithDetails> mItems = new ArrayList<>();
private ItemWithDetailsAdapter mItemAdapter;
private void refreshBusyState(GBDevice dev) {
if (dev.isConnecting() || dev.isBusy()) {
@ -107,6 +118,13 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
if (dev != null) {
device = dev;
}
if (savedInstanceState != null) {
mDetails = savedInstanceState.getParcelableArrayList(ITEM_DETAILS);
if (mDetails == null) {
mDetails = new ArrayList<>();
}
}
mayConnect = true;
itemListView = (ListView) findViewById(R.id.itemListView);
mItemAdapter = new ItemWithDetailsAdapter(this, mItems);
@ -114,10 +132,15 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
fwAppInstallTextView = (TextView) findViewById(R.id.infoTextView);
installButton = (Button) findViewById(R.id.installButton);
mProgressBar = (ProgressBar) findViewById(R.id.installProgressBar);
detailsListView = (ListView) findViewById(R.id.detailsListView);
mDetailsItemAdapter = new ItemWithDetailsAdapter(this, mDetails);
mDetailsItemAdapter.setSize(ItemWithDetailsAdapter.SIZE_SMALL);
detailsListView.setAdapter(mDetailsItemAdapter);
setInstallEnabled(false);
IntentFilter filter = new IntentFilter();
filter.addAction(GBApplication.ACTION_QUIT);
filter.addAction(GBDevice.ACTION_DEVICE_CHANGED);
filter.addAction(GB.ACTION_DISPLAY_MESSAGE);
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter);
installButton.setOnClickListener(new View.OnClickListener() {
@ -145,6 +168,12 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(ITEM_DETAILS, mDetails);
}
private InstallHandler findInstallHandlerFor(Uri uri) {
for (DeviceCoordinator coordinator : DeviceHelper.getInstance().getAllCoordinators()) {
InstallHandler handler = coordinator.findInstallHandler(uri, this);
@ -195,4 +224,9 @@ public class FwAppInstallerActivity extends Activity implements InstallActivity
mItems.add(item);
mItemAdapter.notifyDataSetChanged();
}
private void addMessage(String message, int severity) {
mDetails.add(new GenericItem(message));
mDetailsItemAdapter.notifyDataSetChanged();
}
}

View File

@ -18,8 +18,12 @@ import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
*/
public class ItemWithDetailsAdapter extends ArrayAdapter<ItemWithDetails> {
public static final int SIZE_SMALL = 1;
public static final int SIZE_MEDIUM = 2;
public static final int SIZE_LARGE = 3;
private final Context context;
private boolean horizontalAlignment;
private int size = SIZE_MEDIUM;
public ItemWithDetailsAdapter(Context context, List<ItemWithDetails> items) {
super(context, 0, items);
@ -42,7 +46,14 @@ public class ItemWithDetailsAdapter extends ArrayAdapter<ItemWithDetails> {
if (horizontalAlignment) {
view = inflater.inflate(R.layout.item_with_details_horizontal, parent, false);
} else {
view = inflater.inflate(R.layout.item_with_details, parent, false);
switch (size) {
case SIZE_SMALL:
view = inflater.inflate(R.layout.item_with_details_small, parent, false);
break;
default:
view = inflater.inflate(R.layout.item_with_details, parent, false);
break;
}
}
}
ImageView iconView = (ImageView) view.findViewById(R.id.item_image);
@ -55,4 +66,12 @@ public class ItemWithDetailsAdapter extends ArrayAdapter<ItemWithDetails> {
return view;
}
public void setSize(int size) {
this.size = size;
}
public int getSize() {
return size;
}
}

View File

@ -0,0 +1,21 @@
package nodomain.freeyourgadget.gadgetbridge.deviceevents;
public class GBDeviceEventDisplayMessage {
public String message;
public int duration;
public int severity;
/**
* An event for displaying a message to the user. How the message is displayed
* is a detail of the current activity, which needs to listen to the Intent
* GB.ACTION_DISPLAY_MESSAGE.
* @param message
* @param duration
* @param severity
*/
public GBDeviceEventDisplayMessage(String message, int duration, int severity) {
this.message = message;
this.duration = duration;
this.severity = severity;
}
}

View File

@ -1,5 +1,6 @@
package nodomain.freeyourgadget.gadgetbridge.service;
import android.app.Application;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@ -32,6 +33,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventScreenshot;
@ -280,4 +282,14 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
gbDevice.sendDeviceUpdateIntent(context);
}
public void handleGBDeviceEvent(GBDeviceEventDisplayMessage message) {
GB.log(message.message, message.severity, null);
Intent messageIntent = new Intent(GB.ACTION_DISPLAY_MESSAGE);
messageIntent.putExtra(GB.DISPLAY_MESSAGE_MESSAGE, message.message);
messageIntent.putExtra(GB.DISPLAY_MESSAGE_DURATION, message.duration);
messageIntent.putExtra(GB.DISPLAY_MESSAGE_SEVERITY, message.severity);
LocalBroadcastManager.getInstance(context).sendBroadcast(messageIntent);
}
}

View File

@ -2,6 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.Context;
import android.net.Uri;
import android.widget.Toast;
@ -13,6 +14,7 @@ import java.util.Arrays;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventDisplayMessage;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandFWHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
@ -53,7 +55,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
updateCoordinator.initNextOperation();
if (!updateCoordinator.sendFwInfo()) {
GB.toast(getContext(), "Error sending firmware info, aborting.", Toast.LENGTH_LONG, GB.ERROR);
displayMessage(getContext(), "Error sending firmware info, aborting.", Toast.LENGTH_LONG, GB.ERROR);
done();
}
//the firmware will be sent by the notification listener if the band confirms that the metadata are ok.
@ -102,9 +104,9 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
switch (value[0]) {
case MiBandService.NOTIFY_FW_CHECK_SUCCESS:
if (firmwareInfoSent) {
GB.toast(getContext(), "Firmware metadata successfully sent.", Toast.LENGTH_LONG, GB.INFO);
displayMessage(getContext(), "Firmware metadata successfully sent.", Toast.LENGTH_LONG, GB.INFO);
if (!updateCoordinator.sendFwData()) {
GB.toast(getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR);
displayMessage(getContext(), getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR);
done();
}
firmwareInfoSent = false;
@ -113,20 +115,20 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
}
break;
case MiBandService.NOTIFY_FW_CHECK_FAILED:
GB.toast(getContext().getString(R.string.updatefirmwareoperation_metadata_updateproblem), Toast.LENGTH_LONG, GB.ERROR);
displayMessage(getContext(), getContext().getString(R.string.updatefirmwareoperation_metadata_updateproblem), Toast.LENGTH_LONG, GB.ERROR);
firmwareInfoSent = false;
done();
break;
case MiBandService.NOTIFY_FIRMWARE_UPDATE_SUCCESS:
if (updateCoordinator.initNextOperation()) {
GB.toast(getContext(), "Heart Rate Firmware successfully updated, now updating Mi Band Firmware", Toast.LENGTH_LONG, GB.INFO);
displayMessage(getContext(), "Heart Rate Firmware successfully updated, now updating Mi Band Firmware", Toast.LENGTH_LONG, GB.INFO);
if (!updateCoordinator.sendFwInfo()) {
GB.toast(getContext(), "Error sending firmware info, aborting.", Toast.LENGTH_LONG, GB.ERROR);
displayMessage(getContext(), "Error sending firmware info, aborting.", Toast.LENGTH_LONG, GB.ERROR);
done();
}
break;
} else if (updateCoordinator.needsReboot()) {
GB.toast(getContext(), getContext().getString(R.string.updatefirmwareoperation_update_complete_rebooting), Toast.LENGTH_LONG, GB.INFO);
displayMessage(getContext(), getContext().getString(R.string.updatefirmwareoperation_update_complete_rebooting), Toast.LENGTH_LONG, GB.INFO);
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_update_complete), false, 100, getContext());
getSupport().onReboot();
} else {
@ -136,7 +138,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
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(getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR);
displayMessage(getContext(), getContext().getString(R.string.updatefirmwareoperation_updateproblem_do_not_reboot), Toast.LENGTH_LONG, GB.ERROR);
GB.updateInstallNotification(getContext().getString(R.string.updatefirmwareoperation_write_failed), false, 0, getContext());
done();
break;
@ -147,6 +149,10 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
}
}
private void displayMessage(Context context, String message, int duration, int severity) {
getSupport().handleGBDeviceEvent(new GBDeviceEventDisplayMessage(message, duration, severity));
}
/**
* Prepare the MiBand to receive the new firmware data.
* Some information about the new firmware version have to be pushed to the MiBand before sending
@ -278,7 +284,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
int firmwareProgress = 0;
TransactionBuilder builder = performInitialized("send firmware packet");
getSupport().setLowLatency(builder);
// getSupport().setLowLatency(builder);
for (int i = 0; i < packets; i++) {
byte[] fwChunk = Arrays.copyOfRange(fwbytes, i * packetLength, i * packetLength + packetLength);
@ -325,7 +331,7 @@ public class UpdateFirmwareOperation extends AbstractMiBandOperation {
public boolean sendFwInfo() {
try {
TransactionBuilder builder = performInitialized("send firmware info");
getSupport().setLowLatency(builder);
// getSupport().setLowLatency(builder);
builder.add(new SetDeviceBusyAction(getDevice(), getContext().getString(R.string.updating_firmware), getContext()));
builder.add(new FirmwareInfoSentAction()); // Note: *before* actually sending the info, otherwise it's too late!
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), getFirmwareInfo());

View File

@ -39,6 +39,10 @@ public class GB {
public static final int INFO = 1;
public static final int WARN = 2;
public static final int ERROR = 3;
public static final String ACTION_DISPLAY_MESSAGE = "GB_Display_Message";
public static final String DISPLAY_MESSAGE_MESSAGE = "message";
public static final String DISPLAY_MESSAGE_DURATION = "duration";
public static final String DISPLAY_MESSAGE_SEVERITY = "severity";
public static GBEnvironment environment;
public static Notification createNotification(String text, Context context) {
@ -225,7 +229,7 @@ public class GB {
}
}
private static void log(String message, int severity, Throwable ex) {
public static void log(String message, int severity, Throwable ex) {
switch (severity) {
case INFO:
LOG.info(message, ex);

View File

@ -62,6 +62,14 @@
android:layout_below="@+id/installProgressBar"
android:layout_marginTop="10dp" />
<ListView
android:id="@+id/detailsListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/installButton"
android:layout_alignParentEnd="false">
</ListView>
<android.widget.Space
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/activatedBackgroundIndicator"
android:padding="4dp" >
<ImageView
android:id="@+id/item_image"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentStart="true"
android:contentDescription="@string/candidate_item_device_image" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_toEndOf="@+id/item_image"
android:orientation="vertical"
android:paddingStart="4dp"
android:paddingEnd="4dp">
<TextView
android:id="@+id/item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scrollHorizontally="false"
style="@style/Base.TextAppearance.AppCompat.Body1"
android:text="Item Name"
android:singleLine="true" />
<TextView
android:id="@+id/item_details"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Base.TextAppearance.AppCompat.Body2"
android:text="Item Description"
/>
</LinearLayout>
</RelativeLayout>