From 23d91ac79e2da6aeb63009e23585500cd386f170 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sun, 21 Jun 2015 00:34:05 +0200 Subject: [PATCH] Support for finding a lost device (closes #42) --- .../gadgetbridge/AbstractBTDeviceSupport.java | 6 ++++ .../BluetoothCommunicationService.java | 6 ++++ .../gadgetbridge/ControlCenter.java | 24 +++++++++++++ .../gadgetbridge/EventHandler.java | 2 ++ .../gadgetbridge/ServiceDeviceSupport.java | 8 +++++ .../gadgetbridge/miband/MiBandSupport.java | 35 +++++++++++++++---- .../gadgetbridge/miband/VibrationProfile.java | 6 ++-- .../protocol/GBDeviceProtocol.java | 4 +++ .../main/res/menu/controlcenter_context.xml | 3 ++ app/src/main/res/values/strings.xml | 3 ++ 10 files changed, 87 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractBTDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractBTDeviceSupport.java index dd7ecbc6..047f1677 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractBTDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AbstractBTDeviceSupport.java @@ -161,4 +161,10 @@ public abstract class AbstractBTDeviceSupport extends AbstractDeviceSupport { byte[] bytes = gbDeviceProtocol.encodeReboot(); sendToDevice(bytes); } + + @Override + public void onFindDevice(boolean start) { + byte[] bytes = gbDeviceProtocol.encodeLocateDevice(start); + sendToDevice(bytes); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java index 5ed8980f..52da0a43 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java @@ -59,6 +59,7 @@ public class BluetoothCommunicationService extends Service { public static final String ACTION_REBOOT = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.reboot"; public static final String ACTION_FETCH_ACTIVITY_DATA = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.fetch_activity_data"; public static final String ACTION_DISCONNECT = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.disconnect"; + public static final String ACTION_FIND_DEVICE = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.find_device"; public static final String EXTRA_PERFORM_PAIR = "perform_pair"; @@ -208,6 +209,11 @@ public class BluetoothCommunicationService extends Service { mDeviceSupport = null; break; } + case ACTION_FIND_DEVICE: { + boolean start = intent.getBooleanExtra("find_start", false); + mDeviceSupport.onFindDevice(start); + break; + } case ACTION_CALLSTATE: GBCommand command = GBCommand.values()[intent.getIntExtra("call_command", 0)]; // UGLY diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java index ff977aed..64a6b6f7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java @@ -1,10 +1,13 @@ package nodomain.freeyourgadget.gadgetbridge; import android.app.Activity; +import android.app.AlertDialog; +import android.app.ProgressDialog; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.content.BroadcastReceiver; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; @@ -198,11 +201,32 @@ public class ControlCenter extends Activity { startService(startIntent); } return true; + case R.id.controlcenter_find_device: + if (selectedDevice != null) { + findDevice(true); + ProgressDialog dialog = ProgressDialog.show( + this, + getString(R.string.control_center_find_lost_device), + getString(R.string.control_center_cancel_to_stop_vibration), + true, true, + new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + findDevice(false); + } + }); + } default: return super.onContextItemSelected(item); } } + private void findDevice(boolean start) { + Intent startIntent = new Intent(this, BluetoothCommunicationService.class); + startIntent.putExtra("find_start", start); + startIntent.setAction(BluetoothCommunicationService.ACTION_FIND_DEVICE); + startService(startIntent); + } @Override public boolean onCreateOptionsMenu(Menu menu) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java index 4ce49b15..8dbcf63c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/EventHandler.java @@ -34,4 +34,6 @@ public interface EventHandler { void onFetchActivityData(); void onReboot(); + + void onFindDevice(boolean start); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java index f929274d..1574a5d7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ServiceDeviceSupport.java @@ -210,4 +210,12 @@ public class ServiceDeviceSupport implements DeviceSupport { } delegate.onReboot(); } + + @Override + public void onFindDevice(boolean start) { + if (checkBusy("find device")) { + return; + } + delegate.onFindDevice(start); + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java index b0dd21a6..9054b086 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/MiBandSupport.java @@ -69,6 +69,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { //same as above, but remains untouched for the ack message private GregorianCalendar activityDataTimestampToAck = null; private volatile boolean telephoneRinging; + private volatile boolean isLocatingDevice; public MiBandSupport() { @@ -135,10 +136,15 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { return getNotification(vibrateDuration, vibrateTimes, flashTimes, flashColour, originalColour, flashDuration); } - private void sendDefaultNotification(TransactionBuilder builder) { + private void sendDefaultNotification(TransactionBuilder builder, short repeat, BtLEAction extraAction) { BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT); - LOG.info("Sending notification to MiBand: " + characteristic); - builder.write(characteristic, getDefaultNotification()).queue(getQueue()); + LOG.info("Sending notification to MiBand: " + characteristic + " (" + repeat + " times)"); + byte[] defaultNotification = getDefaultNotification(); + for (short i = 0; i < repeat; i++) { + builder.write(characteristic, defaultNotification); + builder.add(extraAction); + } + builder.queue(getQueue()); } /** @@ -153,7 +159,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { */ private void sendCustomNotification(VibrationProfile vibrationProfile, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) { BluetoothGattCharacteristic controlPoint = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT); - for (byte i = 0; i < vibrationProfile.getRepeat(); i++) { + for (short i = 0; i < vibrationProfile.getRepeat(); i++) { int[] onOffSequence = vibrationProfile.getOnOffSequence(); for (int j = 0; j < onOffSequence.length; j++) { int on = onOffSequence[j]; @@ -245,10 +251,10 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { return this; } - private void performDefaultNotification(String task) { + private void performDefaultNotification(String task, short repeat, BtLEAction extraAction) { try { TransactionBuilder builder = performInitialized(task); - sendDefaultNotification(builder); + sendDefaultNotification(builder, repeat, extraAction); } catch (IOException ex) { LOG.error("Unable to send notification to MI device", ex); } @@ -314,7 +320,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { private VibrationProfile getPreferredVibrateProfile(String notificationOrigin, SharedPreferences prefs, int repeat) { String profileId = getNotificationPrefStringValue(VIBRATION_PROFILE, notificationOrigin, prefs, DEFAULT_VALUE_VIBRATION_PROFILE); - return VibrationProfile.getProfile(profileId, (byte) repeat); + return VibrationProfile.getProfile(profileId, (byte) (repeat & 0xfff)); } @Override @@ -432,6 +438,21 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } } + @Override + public void onFindDevice(boolean start) { + isLocatingDevice = start; + + if (start) { + AbortTransactionAction abortAction = new AbortTransactionAction() { + @Override + protected boolean shouldAbort() { + return !isLocatingDevice; + } + }; + performDefaultNotification("locating device", (short) 255, abortAction); + } + } + @Override public void onFetchActivityData() { try { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/VibrationProfile.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/VibrationProfile.java index 7144f80c..5596a0a1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/VibrationProfile.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/miband/VibrationProfile.java @@ -41,7 +41,7 @@ public class VibrationProfile { private final String id; private int[] onOffSequence; - private byte repeat; // 1-10 + private short repeat; /** * Creates a new profile instance. @@ -49,7 +49,7 @@ public class VibrationProfile { * @param onOffSequence a sequence of alternating on and off durations, in milliseconds * @param repeat how ofoften the sequence shall be repeated */ - public VibrationProfile(String id, int[] onOffSequence, byte repeat) { + public VibrationProfile(String id, int[] onOffSequence, short repeat) { this.id = id; this.repeat = repeat; this.onOffSequence = onOffSequence; @@ -63,7 +63,7 @@ public class VibrationProfile { return onOffSequence; } - public byte getRepeat() { + public short getRepeat() { return repeat; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceProtocol.java index f91e777c..c1fe6a21 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceProtocol.java @@ -62,6 +62,10 @@ public abstract class GBDeviceProtocol { return null; } + public byte[] encodeLocateDevice(boolean start) { + return null; + } + public GBDeviceCommand decodeResponse(byte[] responseData) { return null; } diff --git a/app/src/main/res/menu/controlcenter_context.xml b/app/src/main/res/menu/controlcenter_context.xml index 9322d26b..cbfd6010 100644 --- a/app/src/main/res/menu/controlcenter_context.xml +++ b/app/src/main/res/menu/controlcenter_context.xml @@ -6,6 +6,9 @@ + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 23b6a6d9..5f5ab314 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -133,5 +133,8 @@ Pebble Notification K9 Mail Notification Incoming Call Notification + Find Deviceā€¦ + Find lost Device + Cancel to stop vibration.