From 7f331a1bb1337806ba755bb7fa20420c1c4b9410 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 8 Sep 2015 14:15:46 +0200 Subject: [PATCH 01/73] Pebble: play around with timeline pins --- .../devices/pebble/PebbleProtocol.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 84a57cee..783d7b68 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -371,6 +371,7 @@ public class PebbleProtocol extends GBDeviceProtocol { if (isFw3x) { // 3.x notification + //return encodeTimelinePin(id, (int) (ts + 600 & 0xffffffff), (short) 90, 21, title); // really, this is just for testing return encodeBlobdbNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle); } else if (mForceProtocol || type != NOTIFICATION_EMAIL) { // 2.x notification @@ -556,6 +557,45 @@ public class PebbleProtocol extends GBDeviceProtocol { return buf.array(); } + private byte[] encodeTimelinePin(int id, int timestamp, short duration, int icon_id, String title) { + final short TIMELINE_PIN_LENGTH = 46; + + icon_id |= 0x80000000; + UUID uuid = new UUID(mRandom.nextLong(), ((long) mRandom.nextInt() << 32) | id); + byte attributes_count = 2; + byte actions_count = 0; + + int attributes_length = 10 + title.length(); + int pin_length = TIMELINE_PIN_LENGTH + attributes_length; + ByteBuffer buf = ByteBuffer.allocate(pin_length); + + // pin - 46 bytes + buf.order(ByteOrder.BIG_ENDIAN); + buf.putLong(uuid.getMostSignificantBits()); + buf.putLong(uuid.getLeastSignificantBits()); + buf.putLong(0); // parent + buf.putLong(0); + buf.order(ByteOrder.LITTLE_ENDIAN); + buf.putInt(timestamp); // 32-bit timestamp + buf.putShort(duration); + buf.put((byte) 0x02); // type (0x02 = pin) + buf.putShort((short) 0x0001); // flags 0x0001 = ? + buf.put((byte) 0x02); // layout (0x02 = pin?) + + buf.putShort((short) attributes_length); // total length of all attributes and actions in bytes + buf.put(attributes_count); + buf.put(actions_count); + + buf.put((byte) 4); // icon + buf.putShort((short) 4); // length of int + buf.putInt(icon_id); + buf.put((byte) 1); // title + buf.putShort((short) title.getBytes().length); + buf.put(title.getBytes()); + + return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array()); + } + private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, byte type, boolean hasHandle) { final short NOTIFICATION_PIN_LENGTH = 46; final short ACTION_LENGTH_MIN = 10; From e34c5614d74ec1f0362ab7fa0f8d2951a6281ccf Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 9 Sep 2015 20:46:50 +0200 Subject: [PATCH 02/73] Bail out hard if we get negative steps from the database #91 We don't add them to the db for sure. --- .../gadgetbridge/impl/GBActivitySample.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBActivitySample.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBActivitySample.java index 861dc8a1..1cb7416d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBActivitySample.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBActivitySample.java @@ -16,6 +16,19 @@ public class GBActivitySample implements ActivitySample { this.intensity = intensity; this.steps = steps; this.type = type; + validate(); + } + + private void validate() { + if (steps < 0) { + throw new IllegalArgumentException("steps must be > 0"); + } + if (intensity < 0) { + throw new IllegalArgumentException("intensity must be > 0"); + } + if (timestamp < 0) { + throw new IllegalArgumentException("timestamp must be > 0"); + } } @Override From 2dec5574ccb8693367fa5b6c22ef2e232c77ca85 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 9 Sep 2015 20:49:17 +0200 Subject: [PATCH 03/73] Log the where condition of the samples query #91 --- .../gadgetbridge/database/ActivityDatabaseHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java index 59ee6d07..ea46e9bc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java @@ -179,6 +179,7 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl } ArrayList samples = new ArrayList(); final String where = "(provider=" + provider.getID() + " and timestamp>=" + timestamp_from + " and timestamp<=" + timestamp_to + getWhereClauseFor(activityTypes, provider) + ")"; + LOG.info("Activity query where: "+ where); final String order = "timestamp"; try (SQLiteDatabase db = this.getReadableDatabase()) { try (Cursor cursor = db.query(TABLE_GBACTIVITYSAMPLES, null, where, null, null, null, order)) { From bddf6c890987c9d6eef5e472adf798395162487c Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 9 Sep 2015 20:52:04 +0200 Subject: [PATCH 04/73] Also log the number of rows (samples) returned by the query #91 --- .../gadgetbridge/database/ActivityDatabaseHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java index ea46e9bc..fd642d49 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java @@ -183,6 +183,7 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl final String order = "timestamp"; try (SQLiteDatabase db = this.getReadableDatabase()) { try (Cursor cursor = db.query(TABLE_GBACTIVITYSAMPLES, null, where, null, null, null, order)) { + LOG.info("Activity query result: " + cursor.getCount() + " samples"); if (cursor.moveToFirst()) { do { GBActivitySample sample = new GBActivitySample( From d9d222ca9b133cf0462fa3bce003820fb527f0e6 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 9 Sep 2015 21:15:29 +0200 Subject: [PATCH 05/73] Tiny logging improvement --- .../gadgetbridge/activities/charts/AbstractChartFragment.java | 2 +- .../gadgetbridge/activities/charts/WeekStepsChartFragment.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java index 7be2afcb..668708c4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java @@ -360,7 +360,7 @@ public abstract class AbstractChartFragment extends AbstractGBFragment { String dateStringFrom = ""; String dateStringTo = ""; - LOG.info("number of samples:" + samples.size()); + LOG.info("" + getTitle() + ": number of samples:" + samples.size()); if (samples.size() > 1) { float movement_divisor; boolean annotate = true; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java index 71382dfa..39068828 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java @@ -130,6 +130,7 @@ public class WeekStepsChartFragment extends AbstractChartFragment { GBDevice device = ((ChartsHost) getHost()).getDevice(); if (device != null) { + // TODO: eek, this is device specific! mTargetSteps = MiBandCoordinator.getFitnessGoal(device.getAddress()); } From e0ccb6bf8442013ee9246dfc339522688b73ef59 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 9 Sep 2015 21:53:28 +0200 Subject: [PATCH 06/73] Log the date/time that we sync to the Mi Band #91 --- .../service/devices/miband/MiBandSupport.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) 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 aeeb8c5e..08ec86f9 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 @@ -13,6 +13,8 @@ import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; import java.util.GregorianCalendar; import java.util.UUID; @@ -34,6 +36,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.AbortTransactio import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.FetchActivityOperation; import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.UpdateFirmwareOperation; +import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.DEFAULT_VALUE_FLASH_COLOUR; @@ -429,7 +432,10 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { * @param builder */ private MiBandSupport setCurrentTime(TransactionBuilder builder) { - byte[] nowBytes = MiBandDateConverter.calendarToRawBytes(GregorianCalendar.getInstance()); + Calendar now = GregorianCalendar.getInstance(); + Date date = now.getTime(); + LOG.info("Sending current time to Mi Band: " + DateTimeUtils.formatDate(date) + " (" + date.toGMTString() + ")"); + byte[] nowBytes = MiBandDateConverter.calendarToRawBytes(now); byte[] time = new byte[]{ nowBytes[0], nowBytes[1], From e80a3cc591113b7a9b6ddc699702a94aafbe2e8f Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 9 Sep 2015 22:33:06 +0200 Subject: [PATCH 07/73] Log the number of samples being flushed #91 --- .../devices/miband/operations/FetchActivityOperation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 cdf19128..8f57d02e 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 @@ -184,7 +184,7 @@ public class FetchActivityOperation extends AbstractBTLEOperation LOG.debug("nothing to flush, struct is already null"); return; } - LOG.debug("flushing activity data holder"); + LOG.debug("flushing activity data samples: " + activityStruct.activityDataHolderProgress / 3); byte category, intensity, steps; DBHandler dbHandler = null; From 22a9ff1819be383e3bf75873530b58ef876b0a26 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 9 Sep 2015 23:23:38 +0200 Subject: [PATCH 08/73] Log when no listener is registered for a characteristic change --- .../freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index a7f6d6a3..dd8fdb53 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -403,6 +403,8 @@ public final class BtLEQueue { } if (getCallbackToUse() != null) { getCallbackToUse().onCharacteristicChanged(gatt, characteristic); + } else { + LOG.info("No gattcallback registered, ignoring characteristic change"); } } From c23905070cf5def3448bfb515bb39074f1813dde Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 9 Sep 2015 23:39:57 +0200 Subject: [PATCH 09/73] Some more logging improvelets --- .../nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java | 2 +- .../freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java | 4 ++++ .../gadgetbridge/service/devices/miband/MiBandSupport.java | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) 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 72458e62..429414c3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java @@ -153,7 +153,7 @@ public class GBDevice implements Parcelable { if (mBusyTask != null) { LOG.warn("Attempt to mark device as busy with: " + task + ", but is already busy with: " + mBusyTask); } - LOG.info("Mark device as busy: " + mBusyTask); + LOG.info("Mark device as busy: " + task); mBusyTask = task; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index dd8fdb53..0c5a195f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -20,6 +20,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State; import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport; @@ -444,6 +445,9 @@ public final class BtLEQueue { } public void reset() { + if (LOG.isDebugEnabled()) { + LOG.debug("internal gatt callback set to null"); + } mTransactionGattCallback = null; } }; 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 08ec86f9..f2a2a479 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 @@ -597,6 +597,8 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { handleBatteryInfo(characteristic.getValue(), BluetoothGatt.GATT_SUCCESS); } else if (MiBandService.UUID_CHARACTERISTIC_NOTIFICATION.equals(characteristicUUID)) { handleNotificationNotif(characteristic.getValue()); + } else{ + LOG.info("Unhandled characteristic changed: " + characteristicUUID); } } From 80d15573aff52b411b9b0aa8e567453df994c5da Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 10 Sep 2015 00:00:52 +0200 Subject: [PATCH 10/73] Avoid tiny window where a gatt callback of an operation could be unset --- .../freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index 0c5a195f..f8d2a5dd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -20,7 +20,6 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; -import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State; import nodomain.freeyourgadget.gadgetbridge.service.DeviceSupport; @@ -62,10 +61,10 @@ public final class BtLEQueue { while (!mDisposed && !mCrashed) { try { Transaction transaction = mTransactions.take(); - internalGattCallback.reset(); if (!isConnected()) { // TODO: request connection and initialization from the outside and wait until finished + internalGattCallback.reset(); // wait until the connection succeeds before running the actions // Note that no automatic connection is performed. This has to be triggered From 0ad758fbca5e7754ae3ce0a29c00f6ca40ce90b1 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 10 Sep 2015 13:48:54 +0200 Subject: [PATCH 11/73] WIP blacklist activity (currently does nothing except listing apps) --- app/src/main/AndroidManifest.xml | 7 ++ .../activities/AppBlacklistActivity.java | 106 ++++++++++++++++++ .../activities/AppManagerActivity.java | 2 - .../activities/SettingsActivity.java | 9 ++ .../main/res/layout/activity_appblacklist.xml | 16 +++ app/src/main/res/values/strings.xml | 5 + app/src/main/res/xml/preferences.xml | 3 + 7 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java create mode 100644 app/src/main/res/layout/activity_appblacklist.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e49194d1..9dfd1d54 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -66,6 +66,13 @@ android:name="android.support.PARENT_ACTIVITY" android:value=".activities.ControlCenter" /> + + + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java new file mode 100644 index 00000000..f4a505ed --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java @@ -0,0 +1,106 @@ +package nodomain.freeyourgadget.gadgetbridge.activities; + +import android.app.Activity; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Bundle; +import android.support.v4.app.NavUtils; +import android.support.v4.content.LocalBroadcastManager; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.R; + + +public class AppBlacklistActivity extends Activity { + private static final Logger LOG = LoggerFactory.getLogger(AppBlacklistActivity.class); + + private BroadcastReceiver mReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(ControlCenter.ACTION_QUIT)) { + finish(); + } + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_appblacklist); + getActionBar().setDisplayHomeAsUpEnabled(true); + + final PackageManager pm = getPackageManager(); + + final List packageList = pm.getInstalledApplications(PackageManager.GET_META_DATA); + ListView appListView = (ListView) findViewById(R.id.appListView); + + final ArrayAdapter adapter = new ArrayAdapter(this, R.layout.item_with_details, packageList) { + + @Override + public View getView(int position, View view, ViewGroup parent) { + if (view == null) { + LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + view = inflater.inflate(R.layout.item_with_details, parent, false); + } + + ApplicationInfo appInfo = packageList.get(position); + //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(appInfo.loadDescription(pm)); + deviceAppNameLabel.setText(appInfo.loadLabel(pm)); + deviceImageView.setImageDrawable(appInfo.loadIcon(pm)); + + return view; + } + }; + appListView.setAdapter(adapter); + /* + appListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View v, int position, long id) { + // do something + } + }); + */ + + IntentFilter filter = new IntentFilter(); + filter.addAction(ControlCenter.ACTION_QUIT); + + LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filter); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + NavUtils.navigateUpFromSameTask(this); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + protected void onDestroy() { + LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver); + super.onDestroy(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index 94c8837f..6e3b2802 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -27,8 +27,6 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAppAdapter; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; -import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; -import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; import nodomain.freeyourgadget.gadgetbridge.util.FileUtils; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index 735b68af..6f3761e2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -36,6 +36,15 @@ public class SettingsActivity extends AbstractSettingsActivity { } }); + pref = findPreference("pref_key_blacklist"); + pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent enableIntent = new Intent(SettingsActivity.this, AppBlacklistActivity.class); + startActivity(enableIntent); + return true; + } + }); + final Preference pebbleEmuAddr = findPreference("pebble_emu_addr"); pebbleEmuAddr.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override diff --git a/app/src/main/res/layout/activity_appblacklist.xml b/app/src/main/res/layout/activity_appblacklist.xml new file mode 100644 index 00000000..831675a3 --- /dev/null +++ b/app/src/main/res/layout/activity_appblacklist.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 781c6a4f..b175c584 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -18,6 +18,9 @@ App Manager Delete + + Notification Blacklist + FW/App installer You are about to install firmware %s instead of the one currently on your Mi Band. @@ -49,6 +52,8 @@ when screen is off never + Blacklist Apps + Developer Options Mi Band address diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 6dfe88c3..41a36bed 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -51,6 +51,9 @@ android:defaultValue="false" android:key="notifications_generic_whenscreenon" android:title="@string/pref_title_whenscreenon" /> + Date: Thu, 10 Sep 2015 23:07:42 +0200 Subject: [PATCH 12/73] Pebble: allow launching internal Golf and Sports App if untested features are enabled This is completely useless for now, but since it is there on every Pebble, I want to be able to launch it. --- .../activities/AppManagerActivity.java | 30 ++++++++++++++++--- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index 6e3b2802..7fe4db25 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -5,7 +5,9 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; import android.view.ContextMenu; @@ -52,14 +54,30 @@ public class AppManagerActivity extends Activity { appList.add(new GBDeviceApp(uuid, appName, appCreator, "", appType)); } + + if (sharedPrefs.getBoolean("pebble_force_untested", false)) { + appList.addAll(getSystemApps()); + } + mGBDeviceAppAdapter.notifyDataSetChanged(); } } }; - final List appList = new ArrayList<>(); + + SharedPreferences sharedPrefs; + + private final List appList = new ArrayList<>(); private GBDeviceAppAdapter mGBDeviceAppAdapter; private GBDeviceApp selectedApp = null; + private List getSystemApps() { + List systemApps = new ArrayList<>(); + systemApps.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.UNKNOWN)); + systemApps.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.UNKNOWN)); + + return systemApps; + } + private List getCachedApps() { List cachedAppList = new ArrayList<>(); try { @@ -82,6 +100,9 @@ public class AppManagerActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + setContentView(R.layout.activity_appmanager); getActionBar().setDisplayHomeAsUpEnabled(true); @@ -99,9 +120,10 @@ public class AppManagerActivity extends Activity { registerForContextMenu(appListView); - List cachedApps = getCachedApps(); - for (GBDeviceApp app : cachedApps) { - appList.add(app); + appList.addAll(getCachedApps()); + + if (sharedPrefs.getBoolean("pebble_force_untested", false)) { + appList.addAll(getSystemApps()); } IntentFilter filter = new IntentFilter(); From 914d1b9625b35ced449513dfdbee47bfcfa85bed Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 12 Sep 2015 00:19:36 +0200 Subject: [PATCH 13/73] Make notification blacklist actually working --- .../activities/AppBlacklistActivity.java | 67 ++++++++++++++++--- .../activities/AppManagerActivity.java | 2 +- .../externalevents/NotificationListener.java | 7 ++ 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java index f4a505ed..aec7cd9a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java @@ -5,16 +5,20 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v4.content.LocalBroadcastManager; import android.view.LayoutInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.CheckBox; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; @@ -22,6 +26,7 @@ import android.widget.TextView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashSet; import java.util.List; import nodomain.freeyourgadget.gadgetbridge.R; @@ -40,6 +45,39 @@ public class AppBlacklistActivity extends Activity { } }; + private SharedPreferences sharedPrefs; + + private HashSet blacklist = null; + + private void loadBlackList() { + blacklist = (HashSet) sharedPrefs.getStringSet("package_blacklist", null); + if (blacklist == null) { + blacklist = new HashSet<>(); + } + } + + private void saveBlackList() { + SharedPreferences.Editor editor = sharedPrefs.edit(); + if (blacklist.isEmpty()) { + editor.putStringSet("package_blacklist", null); + } else { + editor.putStringSet("package_blacklist", blacklist); + } + editor.apply(); + } + + private synchronized void addToBlacklist(String packageName) { + if (!blacklist.contains(packageName)) { + blacklist.add(packageName); + saveBlackList(); + } + } + + private synchronized void removeFromBlacklist(String packageName) { + blacklist.remove(packageName); + saveBlackList(); + } + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -47,40 +85,53 @@ public class AppBlacklistActivity extends Activity { getActionBar().setDisplayHomeAsUpEnabled(true); final PackageManager pm = getPackageManager(); + sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + + loadBlackList(); final List packageList = pm.getInstalledApplications(PackageManager.GET_META_DATA); ListView appListView = (ListView) findViewById(R.id.appListView); - final ArrayAdapter adapter = new ArrayAdapter(this, R.layout.item_with_details, packageList) { - + final ArrayAdapter adapter = new ArrayAdapter(this, R.layout.item_with_checkbox, packageList) { @Override public View getView(int position, View view, ViewGroup parent) { if (view == null) { LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - view = inflater.inflate(R.layout.item_with_details, parent, false); + view = inflater.inflate(R.layout.item_with_checkbox, parent, false); } ApplicationInfo appInfo = packageList.get(position); - //TextView deviceAppVersionAuthorLabel = (TextView) view.findViewById(R.id.item_details); + 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); + CheckBox checkbox = (CheckBox) view.findViewById(R.id.item_checkbox); - //deviceAppVersionAuthorLabel.setText(appInfo.loadDescription(pm)); + deviceAppVersionAuthorLabel.setText(appInfo.packageName); deviceAppNameLabel.setText(appInfo.loadLabel(pm)); deviceImageView.setImageDrawable(appInfo.loadIcon(pm)); + if (blacklist.contains(appInfo.packageName)) { + checkbox.setChecked(true); + } + return view; } }; appListView.setAdapter(adapter); - /* + appListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View v, int position, long id) { - // do something + String packageName = packageList.get(position).packageName; + CheckBox checkBox = ((CheckBox) v.findViewById(R.id.item_checkbox)); + checkBox.toggle(); + if (checkBox.isChecked()) { + addToBlacklist(packageName); + } else { + removeFromBlacklist(packageName); + } } }); - */ IntentFilter filter = new IntentFilter(); filter.addAction(ControlCenter.ACTION_QUIT); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index 7fe4db25..983da45e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -64,7 +64,7 @@ public class AppManagerActivity extends Activity { } }; - SharedPreferences sharedPrefs; + private SharedPreferences sharedPrefs; private final List appList = new ArrayList<>(); private GBDeviceAppAdapter mGBDeviceAppAdapter; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index 016f93d2..ce3c8332 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -19,6 +19,8 @@ import android.support.v4.content.LocalBroadcastManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.HashSet; + import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; @@ -146,6 +148,11 @@ public class NotificationListener extends NotificationListenerService { } } + HashSet blacklist = (HashSet) sharedPrefs.getStringSet("package_blacklist", null); + if (blacklist != null && blacklist.contains(source)) { + return; + } + LOG.info("Processing notification from source " + source); Bundle extras = notification.extras; From 70fcbbbe1723b13adf67f9ed107f30fc3519a578 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 12 Sep 2015 19:20:28 +0200 Subject: [PATCH 14/73] Add missing file, fixes build and #114 --- .../main/res/layout/item_with_checkbox.xml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 app/src/main/res/layout/item_with_checkbox.xml diff --git a/app/src/main/res/layout/item_with_checkbox.xml b/app/src/main/res/layout/item_with_checkbox.xml new file mode 100644 index 00000000..c166b0aa --- /dev/null +++ b/app/src/main/res/layout/item_with_checkbox.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + \ No newline at end of file From 986e7e0450b86851a96fb92b73fde1014f90406c Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Sat, 12 Sep 2015 16:55:47 +0200 Subject: [PATCH 15/73] Improve Pebble Time notifications icons * Add a list of icons in the source code * Generic notification now use the correct icon instead of the SMS icon --- .../devices/pebble/PebbleProtocol.java | 115 +++++++++++++++++- 1 file changed, 110 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 783d7b68..bbb9fd21 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -70,11 +70,105 @@ public class PebbleProtocol extends GBDeviceProtocol { static final byte BLOBDB_REMINDER = 3; static final byte BLOBDB_NOTIFICATION = 4; + // This is not in the Pebble protocol + static final byte NOTIFICATION_UNDEFINED = -1; + static final byte NOTIFICATION_EMAIL = 0; static final byte NOTIFICATION_SMS = 1; static final byte NOTIFICATION_TWITTER = 2; static final byte NOTIFICATION_FACEBOOK = 3; + static final byte ICON_NOTIFICATION_GENERIC = 1; + static final byte ICON_TIMELINE_MISSED_CALL = 2; + static final byte ICON_NOTIFICATION_REMINDER = 3; + static final byte ICON_NOTIFICATION_FLAG = 4; + static final byte ICON_NOTIFICATION_WHATSAPP = 5; + static final byte ICON_NOTIFICATION_TWITTER = 6; + static final byte ICON_NOTIFICATION_TELEGRAM = 7; + static final byte ICON_NOTIFICATION_GOOGLE_HANGOUTS = 8; + static final byte ICON_NOTIFICATION_GMAIL = 9; + static final byte ICON_NOTIFICATION_FACEBOOK_MESSENGER = 10; + static final byte ICON_NOTIFICATION_FACEBOOK = 11; + static final byte ICON_AUDIO_CASSETTE = 12; + static final byte ICON_ALARM_CLOCK = 13; + static final byte ICON_TIMELINE_WEATHER = 14; + static final byte ICON_TIMELINE_SUN = 16; + static final byte ICON_TIMELINE_SPORTS = 17; + static final byte ICON_GENERIC_EMAIL = 19; + static final byte ICON_AMERICAN_FOOTBALL = 20; + static final byte ICON_TIMELINE_CALENDAR = 21; + static final byte ICON_TIMELINE_BASEBALL = 22; + static final byte ICON_BIRTHDAY_EVENT = 23; + static final byte ICON_CAR_RENTAL = 24; + static final byte ICON_CLOUDY_DAY = 25; + static final byte ICON_CRICKET_GAME = 26; + static final byte ICON_DINNER_RESERVATION = 27; + static final byte ICON_GENERIC_WARNING = 28; + static final byte ICON_GLUCOSE_MONITOR = 29; + static final byte ICON_HOCKEY_GAME = 30; + static final byte ICON_HOTEL_RESERVATION = 31; + static final byte ICON_LIGHT_RAIN = 32; + static final byte ICON_LIGHT_SNOW = 33; + static final byte ICON_MOVIE_EVENT = 34; + static final byte ICON_MUSIC_EVENT = 35; + static final byte ICON_NEWS_EVENT = 36; + static final byte ICON_PARTLY_CLOUDY = 37; + static final byte ICON_PAY_BILL = 38; + static final byte ICON_RADIO_SHOW = 39; + static final byte ICON_SCHEDULED_EVENT = 40; + static final byte ICON_SOCCER_GAME = 41; + static final byte ICON_STOCKS_EVENT = 42; + static final byte ICON_RESULT_DELETED = 43; + static final byte ICON_CHECK_INTERNET_CONNECTION = 44; + static final byte ICON_GENERIC_SMS = 45; + static final byte ICON_RESULT_MUTE = 46; + static final byte ICON_RESULT_SENT = 47; + static final byte ICON_WATCH_DISCONNECTED = 48; + static final byte ICON_DURING_PHONE_CALL = 49; + static final byte ICON_TIDE_IS_HIGH = 50; + static final byte ICON_RESULT_DISMISSED = 51; + static final byte ICON_HEAVY_RAIN = 52; + static final byte ICON_HEAVY_SNOW = 53; + static final byte ICON_SCHEDULED_FLIGHT = 54; + static final byte ICON_GENERIC_CONFIRMATION = 55; + static final byte ICON_DAY_SEPARATOR = 56; + static final byte ICON_NO_EVENTS = 57; + static final byte ICON_NOTIFICATION_BLACKBERRY_MESSENGER = 58; + static final byte ICON_NOTIFICATION_INSTAGRAM = 59; + static final byte ICON_NOTIFICATION_MAILBOX = 60; + static final byte ICON_NOTIFICATION_GOOGLE_INBOX = 61; + static final byte ICON_RESULT_FAILED = 62; + static final byte ICON_GENERIC_QUESTION = 63; + static final byte ICON_NOTIFICATION_OUTLOOK = 64; + static final byte ICON_RAINING_AND_SNOWING = 65; + static final byte ICON_REACHED_FITNESS_GOAL = 66; + static final byte ICON_NOTIFICATION_LINE = 67; + static final byte ICON_NOTIFICATION_SKYPE = 68; + static final byte ICON_NOTIFICATION_SNAPCHAT = 69; + static final byte ICON_NOTIFICATION_VIBER = 70; + static final byte ICON_NOTIFICATION_WECHAT = 71; + static final byte ICON_NOTIFICATION_YAHOO_MAIL = 72; + static final byte ICON_TV_SHOW = 73; + static final byte ICON_BASKETBALL = 74; + static final byte ICON_DISMISSED_PHONE_CALL = 75; + static final byte ICON_NOTIFICATION_GOOGLE_MESSENGER = 76; + static final byte ICON_NOTIFICATION_HIPCHAT = 77; + static final byte ICON_INCOMING_PHONE_CALL = 78; + static final byte ICON_NOTIFICATION_KAKAOTALK = 79; + static final byte ICON_NOTIFICATION_KIK = 80; + static final byte ICON_NOTIFICATION_LIGHTHOUSE = 81; + static final byte ICON_LOCATION = 82; + static final byte ICON_SETTINGS = 83; + static final byte ICON_SUNRISE = 84; + static final byte ICON_SUNSET = 85; + static final byte ICON_FACETIME_DISMISSED = 86; + static final byte ICON_FACETIME_INCOMING = 87; + static final byte ICON_FACETIME_OUTGOING = 88; + static final byte ICON_FACETIME_MISSED = 89; + static final byte ICON_FACETIME_DURING = 90; + static final byte ICON_BLUESCREEN_OF_DEATH = 91; + static final byte ICON_START_MUSIC_PHONE = 92; + static final byte PHONECONTROL_ANSWER = 1; static final byte PHONECONTROL_HANGUP = 2; static final byte PHONECONTROL_GETSTATE = 3; @@ -379,6 +473,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } else { // 1.x notification on FW 2.X String[] parts = {title, body, ts.toString(), subtitle}; + // be aware that type is at this point always NOTIFICATION_EMAIL return encodeMessage(ENDPOINT_NOTIFICATION, type, 0, parts); } } @@ -395,7 +490,7 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeGenericNotification(String title, String details, int handle) { - return encodeNotification(handle, title, null, details, NOTIFICATION_SMS, true); + return encodeNotification(handle, title, null, details, NOTIFICATION_UNDEFINED, true); } @Override @@ -602,13 +697,23 @@ public class PebbleProtocol extends GBDeviceProtocol { String[] parts = {title, subtitle, body}; - int icon_id = 0x80000000 | 1; + int icon_id; switch (type) { case NOTIFICATION_EMAIL: - icon_id = 0x80000000 | 19; + icon_id = ICON_GENERIC_EMAIL; break; case NOTIFICATION_SMS: - icon_id = 0x80000000 | 45; + icon_id = ICON_GENERIC_SMS; + break; + case NOTIFICATION_FACEBOOK: + icon_id = ICON_NOTIFICATION_FACEBOOK; + break; + case NOTIFICATION_TWITTER: + icon_id = ICON_NOTIFICATION_TWITTER; + break; + default: + icon_id = ICON_NOTIFICATION_GENERIC; + break; } // Calculate length first byte actions_count; @@ -682,7 +787,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.put((byte) 4); // icon buf.putShort((short) 4); // length of int - buf.putInt(icon_id); + buf.putInt(0x80000000 | icon_id); // dismiss action buf.put(dismiss_action_id); From b886ba4ac72e1ebcdd0f7591ec99e16cd2e2e136 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 12 Sep 2015 23:22:29 +0200 Subject: [PATCH 16/73] update CHANGELOG, bump version --- CHANGELOG.md | 4 +++- app/build.gradle | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e12b00c..b36bef66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ ###Changelog -####Version next +####Version 0.5.4 * Miband: allow the transfer of activity data without clearing MiBand's memory +* Pebble: for generic notificataions use generic icon insted of SMS icons on FW 3.x (thanks @roidelapluie) +* In settings, support blacklisting apps for generic notifications ####Version 0.5.3 * Pebble: For generic notifications, support dismissing individual notficications and "Open on Phone" feature (OG & PT) diff --git a/app/build.gradle b/app/build.gradle index 2a53d1da..f69753a2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "nodomain.freeyourgadget.gadgetbridge" minSdkVersion 19 targetSdkVersion 23 - versionCode 24 - versionName "0.5.3" + versionCode 25 + versionName "0.5.4" } buildTypes { release { From 7ba255080b5919bb02624d4fe0e7eeb2e3d4a6b6 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 12 Sep 2015 23:30:02 +0200 Subject: [PATCH 17/73] updaten translations from transifex (thanks!) --- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-es/strings.xml | 7 +++- app/src/main/res/values-fr/strings.xml | 4 ++- app/src/main/res/values-it/strings.xml | 50 +++++++++++++++++++++++++- app/src/main/res/values-ko/strings.xml | 1 + app/src/main/res/values-ru/strings.xml | 1 + 6 files changed, 61 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 77d54c80..3d28dbe5 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -14,6 +14,7 @@ App Manager Löschen + FW/App Installer Es soll die Firmware %s anstelle der aktuell installierten Version aufs Mi Band gespielt werden. @@ -144,7 +145,6 @@ Deine Aktivität (ALPHA) Kann keine Verbindung herstellen: %1$s Kann keinen Handler für die Installation dieser Datei finden. - Kann die gegebene Datei %1$s nicht installieren Kann die gegebene Firmware nicht installieren. Sie passt nicht zur Hardware Revision der Pebble. Bitte warten während der Installationsoption festgestellt wird... Gadget Akkustand niedrig! diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index d888ee7d..4b21c1b5 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -14,6 +14,8 @@ Gestor de App Borrar + + Lista negra de notificaciones Instalador de FW/App Estás a punto de instalar el firmware %s en lugar del que está en tu MiBand. @@ -39,6 +41,7 @@ siempre cuando la pantalla está apagada nunca + Añadir app a la lista negra Opciones de desarrollador Dirección de MiBand Ajustes de Pebble @@ -144,7 +147,7 @@ Tu actividad (ALPHA) No se puede conectar: %1$s No se ha podido encontrar un controlador para instalar este archivo. - No se puede instalar el archivo: %1$s + No se ha podido instalar el fichero: %1$s No se puede instalar este firmware: no coincide con la revision hardware de tu Pebble. Por favor, espera mientras se determina el estado de la instalación... Batería baja del Gadget! @@ -172,4 +175,6 @@ Pasos Actividad Pasos hoy, objetivo: %1$s + No \"ackear\" transferencia de datos de actividad + Si los datos de actividad no son \"ackeados\" a la banda, no serán despejados. Útil si GB se usa conjuntamente con otras apps. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e971ee2f..f9fee5a8 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -13,6 +13,7 @@ Gestionnaire d\'application Supprimer + Vous êtes sur le point d\'installer le firmware %s à la place de celui qui est actuellement sur votre Mi Band. Ce firmware a été testé et est connu pour être compatible avec Gadgetbridge. @@ -70,6 +71,7 @@ Décourir les appareils Arreter de scanner Démarrer le scan + Connecter un nouvelle appareil %1$s (%2$s) Coupler l\'appareil Utiliser l\'appareillage bluetouth d\'android pour coupler l\'appareil @@ -140,7 +142,6 @@ Votre activité (ALPHA) Impossible de se connecter: %1$s Impossible de trouver un gestionnaire pour installer ce fichier. - Impossible d\'installer le fichier donné: %1$s Impossible d\'installer le firmware donnée: il ne correspond pas à la version du matériel de votre Pebble. S\'il vous plait patientez pendant la détermination du status de l\'installation... Gadget batterie Vide! @@ -165,4 +166,5 @@ Installation complète du firmware Installation complète du firmware, redémarrage de l\'appareil Échec lors de l\'écriture du firmware + Pas diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index b71c7f16..a708a1a0 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -7,13 +7,21 @@ Esci Sincronizza Monitoraggio del sonno (ALPHA) + Trova dispositivo smarrito... Salva uno screenshot Disconetti Debug Gestione app Cancella + + Blocco notifiche + Installazione FW/App + Il firmware %s verrà installato al posto di quello attualmente sulla Mi Band. + Questo firmware è stato testato ed è compatibile con Gadgetbridge. + Questo firmware NON è stato testato e potrebbe non essere compatibile con Gadgetbridge.\n\nInstallarlo a proprio rischio sulla Mi Band. + Se hai intenzione di procedere e tutto continua a funzionare ti invitiamo a contattare gli sviluppatori e dire loro di aggiungere il firmware: %s a quelli testati Impostazioni Impostazioni globali @@ -33,11 +41,14 @@ sempre se lo schermo è spento mai + Blocca applicazioni Opzioni di sviluppo Indirizzo Miband Impostazioni Pebble Forza protocollo delle notifiche Questa opzione forza l\'utilizzo della versione più recente delle notifiche in dipendenza del firmware del tuo dispositivo. ABILITALO SOLO SE SAI COSA STAI FACENDO! + Abilita funzionalità non testate + Abilita funzionalità non testate. ABILITARE SOLO SE SI SA QUELLO CHE SI STA FACENDO! non connesso in collegamento connesso @@ -57,6 +68,7 @@ installazione del binario %1$d/%2$d Installazione fallita! installazione conclusa con successo + STAI INSTALLANDO UN FIRMWARE, PROCEDI A TUO RISCHIO.\n\n Questo firmware è per la versione HW: %s Si sta per installare la app:\n\n\n%1$s Versione %2$s di %3$s\n N/A inizializzato @@ -64,6 +76,7 @@ Ricerca dispositivi Interrompi scansione Inizia scansione + Connetti un nuovo dispositivo %1$s (%2$s) Accoppia dispositivo Utilizza la funzione del sistema operativo per accoppiare il dispositivo. @@ -124,9 +137,44 @@ Gio Ven Sab - Risveglio intelligente + Sveglia intelligente C\'è stato un errore impostando le sveglie, prova di nuovo. Sveglie sincronizzate con il dispositivo! Non ci sono dati. Effettua una sincronizzazione con il tuo device. Vengono trasferiti %1$s a partire dal %2$s + Traguardo giornaliero di passi + Errore eseguendo \'%1$s\' + Le tue attività (ALPHA) + Impossibile connettere: %1$s + Impossibile aprire questo file. + Impossibile installare il file: %1$s + Impossibile installare il firmware: non corrisponde alla versione hardware del tuo Pebble. + Lo stato dell\'installazione viene rilevato... + Batteria del dispositivo bassa! + %1$s batteria rimanente: %2$s%% + Ultima ricarica: %s \n + Numero di ricariche: %s + Il tuo sonno + Passi della settimana + Attività e sonno + Aggiornamento del Firmware... + Il file non può essere installato, il dispositivo non è pronto. + Firmware Mi Band: %1$s + Versione compatibile + Versione non testata! + Connessione al device: %1$s + Firmware Pebble: %1$s + Versione hardware corretta + Conflitto nella versione hardware! + %1$s (%2$s) + Problema durante il caricamento del firmware. NON RIAVVIARE la Mi Band! + Problema durante il caricamento dei metadati del firmware + Installazione del firmware completata + Installazione del firmware completata, riavvio del dispositivo... + Scrittura del firmware non riuscita + Passi + Attività in tempo reale + Passi di oggi, traguardo: %1$s + Non confermare il trasferimento dati + Se il trasferimento non viene confermato, i dati rimangono memorizzati sulla Mi Band. Utile se GB è usato insieme ad altre app. diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 3a5b0e91..d6c32271 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -12,6 +12,7 @@ 앱 관리자 삭제 + 설정 diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 7c0c35c3..7da170aa 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -12,6 +12,7 @@ App Mananger Удалить + Настройки From bfd7908f56eec9af4854c963854552a4f358a2c6 Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Sat, 12 Sep 2015 23:31:59 +0200 Subject: [PATCH 18/73] Fix typos in CHANGELOG --- CHANGELOG.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b36bef66..d3578f50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,13 +2,13 @@ ####Version 0.5.4 * Miband: allow the transfer of activity data without clearing MiBand's memory -* Pebble: for generic notificataions use generic icon insted of SMS icons on FW 3.x (thanks @roidelapluie) +* Pebble: for generic notifications use generic icon instead of SMS icons on FW 3.x (thanks @roidelapluie) * In settings, support blacklisting apps for generic notifications ####Version 0.5.3 -* Pebble: For generic notifications, support dismissing individual notficications and "Open on Phone" feature (OG & PT) -* Pebble: Allow to treat K9 notifcations as generic notifications (if notification mode is set to never) -* Ignore QKSMS notificaions to avoid double notification for incoming SMS +* Pebble: For generic notifications, support dismissing individual notifications and "Open on Phone" feature (OG & PT) +* Pebble: Allow to treat K9 notifications as generic notifications (if notification mode is set to never) +* Ignore QKSMS notifications to avoid double notification for incoming SMS * Improved UI of Firmware/App installer * Device state again visible on lockscreen * Date display and navigation now working properly for all charts @@ -26,12 +26,12 @@ * Fix broken "find lost device" which was broken in 0.5.0 ####Version 0.5.0 -* Mi Band: fix setting wear location +* Mi Band: fix setting wear location * Pebble: experimental watchapp installation support for FW 3.x/Pebble Time * Pebble: support Pebble emulator via TCP connection (needs rebuild with INTERNET permission) * Pebble: use SMS/EMAIL icons for FW 3.x/Pebble Time * Pebble: do not throttle notifications -* Support going forward/backwards in time in the activy charts +* Support going forward/backwards in time in the activity charts * Various small bugfixes to the App/Fw Installation Activity ####Version 0.4.6 @@ -68,7 +68,7 @@ ####Version 0.4.2 * Material style for Lollipop -* Support for finding a lost device (vibrate until cacelled) +* Support for finding a lost device (vibrate until cancelled) * Mi Band: Support for vibration profiles, configurable for notifications * Pebble: Support taking screenshots from the device context menu (Pebble Time not supported yet) @@ -76,7 +76,7 @@ * New icons, thanks xphnx! * Improvements to Sleep Monitor charts * Pebble: use new Sleep Monitor for Morpheuz (previously Mi Band only) -* Pebble: expermimental support for FW 3.x notification protocol +* Pebble: experimental support for FW 3.x notification protocol * Pebble: dev option to force latest notification protocol ####Version 0.4.0 @@ -84,13 +84,13 @@ * Pebble: Support launching of watchapps though the AppManager Activity * Pebble: Support CM 12.1 default music app (Eleven) * Pebble: Fix firmware installation when all 8 app slots are in use -* Pebble: Fix firmware installation when Pebble is in recovery mode +* Pebble: Fix firmware installation when Pebble is in recovery mode * Pebble: Fix error when reinstalling apps, useful for upgrading/downgrading * Mi Band: Make vibration count configurable for different kinds of Notifications * Mi Band: Initial support for fetching activity data * Support rebooting Mi Band/Pebble through the Debug Activity * Add highly experimental sleep monitor (accessible via long press on a device) -* Fix Debug activity (SMS and E-Mail buttons were broken) +* Fix Debug activity (SMS and E-Mail buttons were broken) * Add Turkish translation contributed by Tarik Sekmen ####Version 0.3.5 @@ -102,7 +102,7 @@ ####Version 0.3.4 * Pebble: Huge speedup for app/firmware installation. * Pebble: Use a separate notification with progress bar for installation procedure -* Pebble: Bugfix for beeing stuck while waiting for a slot, when none is available +* Pebble: Bugfix for being stuck while waiting for a slot, when none is available * Mi Band: Display connection status in notification (previously Pebble only) ####Version 0.3.3 @@ -117,7 +117,7 @@ * Pebble: Check if firmware is compatible before allowing installation ####Version 0.3.1 -* Mi Band: Fix for notifications only woking in Debug +* Mi Band: Fix for notifications only working in Debug ####Version 0.3.0 * Mi Band: Initial support (see README.md) @@ -131,7 +131,7 @@ * Experimental pbw installation support (watchfaces/apps) * New icons for device and app lists * Fix for device list not refreshing when bluetooth gets turned on -* Filter out annyoing low battery notifications +* Filter out annoying low battery notifications * Fix for crash on some devices when creating a debug notification * Lots of internal changes preparing multi device support @@ -139,16 +139,16 @@ * Fix for DST (summer time) * Option to sync time on connect (enabled by default) * Opening .pbw files with Gadgetbridge prints some package information - (This was not meant to be released yet, but the DST fix made a new release neccessary) + (This was not meant to be released yet, but the DST fix made a new release necessary) ####Version 0.1.4 * New AppManager shows installed Apps/Watchfaces (removal possible via context menu) * Allow back navigation in ActionBar (Debug and AppMananger Activities) * Make sure Intent broadcasts do not leave Gadgetbridge -* Show hint in the Main Activiy (tap to connect etc) +* Show hint in the Main Activity (tap to connect etc) ####Version 0.1.3 -* Remove the connect button, list all suported devices and connect on tap instead +* Remove the connect button, list all supported devices and connect on tap instead * Display connection status and firmware of connected devices in the device list * Remove quit button from the service notification, put a quit item in the context menu instead @@ -159,7 +159,7 @@ ####Version 0.1.1 * Fixed various bugs regarding K-9 Mail notifications. -* "Generic notification support" in Setting now opens Androids "Notifcaion access" dialog. +* "Generic notification support" in Setting now opens Androids "Notification access" dialog. ####Version 0.1.0 * Initial release From d50a82d495cda989d9f741ed4e82cd71ede76cd3 Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Sun, 13 Sep 2015 00:39:53 +0200 Subject: [PATCH 19/73] Pebble: Set application icons for generic notifications Closes #116. --- .../gadgetbridge/devices/EventHandler.java | 3 +- .../externalevents/NotificationListener.java | 19 ++++++++-- .../gadgetbridge/impl/GBDeviceService.java | 6 ++-- .../gadgetbridge/model/DeviceService.java | 1 + .../gadgetbridge/model/NotificationKind.java | 11 ++++++ .../service/DeviceCommunicationService.java | 5 ++- .../service/ServiceDeviceSupport.java | 5 +-- .../service/devices/miband/MiBandSupport.java | 3 +- .../devices/pebble/PebbleProtocol.java | 36 +++++++++++-------- .../serial/AbstractSerialDeviceSupport.java | 5 +-- .../service/serial/GBDeviceProtocol.java | 5 +-- .../service/TestDeviceSupport.java | 3 +- 12 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index b2d6f90d..88cdaea2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; /** @@ -19,7 +20,7 @@ public interface EventHandler { void onEmail(String from, String subject, String body); - void onGenericNotification(String title, String details, int handle); + void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind); void onSetTime(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index ce3c8332..891626d7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -23,6 +23,7 @@ import java.util.HashSet; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; public class NotificationListener extends NotificationListenerService { @@ -153,6 +154,20 @@ public class NotificationListener extends NotificationListenerService { return; } + // Set application icons for generic notifications + NotificationKind notification_kind; + if (source.equals("org.mariotaku.twidere") || + source.equals("com.twitter.android") || + source.equals("org.andstatus.app")) { + notification_kind = NotificationKind.TWITTER; + } else if (source.equals("com.fsck.k9")) { + notification_kind = NotificationKind.EMAIL; + } else if (source.equals("eu.siacs.conversations")) { + notification_kind = NotificationKind.CHAT; + } else { + notification_kind = NotificationKind.UNDEFINED; + } + LOG.info("Processing notification from source " + source); Bundle extras = notification.extras; @@ -166,7 +181,7 @@ public class NotificationListener extends NotificationListenerService { } if (content != null) { - GBApplication.deviceService().onGenericNotification(title, content, (int) sbn.getPostTime()); //FIMXE: a truly unique id would be better + GBApplication.deviceService().onGenericNotification(title, content, (int) sbn.getPostTime(), notification_kind); //FIMXE: a truly unique id would be better } } @@ -184,4 +199,4 @@ public class NotificationListener extends NotificationListenerService { public void onNotificationRemoved(StatusBarNotification sbn) { } -} \ No newline at end of file +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index 72e90bf2..1fc22847 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -12,6 +12,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; public class GBDeviceService implements DeviceService { @@ -96,11 +97,12 @@ public class GBDeviceService implements DeviceService { } @Override - public void onGenericNotification(String title, String details, int handle) { + public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { Intent intent = createIntent().setAction(ACTION_NOTIFICATION_GENERIC) .putExtra(EXTRA_NOTIFICATION_TITLE, title) .putExtra(EXTRA_NOTIFICATION_BODY, details) - .putExtra(EXTRA_NOTIFICATION_HANDLE, handle); + .putExtra(EXTRA_NOTIFICATION_HANDLE, handle) + .putExtra(EXTRA_NOTIFICATION_KIND, notification_kind); invokeService(intent); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index 63e65111..a46146db 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -37,6 +37,7 @@ public interface DeviceService extends EventHandler { static final String EXTRA_NOTIFICATION_SENDER = "notification_sender"; static final String EXTRA_NOTIFICATION_SUBJECT = "notification_subject"; static final String EXTRA_NOTIFICATION_HANDLE = "notification_handle"; + static final String EXTRA_NOTIFICATION_KIND = "notification_kind"; static final String EXTRA_FIND_START = "find_start"; static final String EXTRA_CALL_COMMAND = "call_command"; static final String EXTRA_CALL_PHONENUMBER = "call_phonenumber"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java new file mode 100644 index 00000000..deda5007 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java @@ -0,0 +1,11 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +public enum NotificationKind { + + UNDEFINED, + + CHAT, + EMAIL, + FACEBOOK, + TWITTER, +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index 72046b8e..af6b9f50 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -27,6 +27,7 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -60,6 +61,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUS import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_TRACK; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_BODY; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_HANDLE; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_KIND; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_SENDER; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_SUBJECT; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_TITLE; @@ -182,7 +184,8 @@ public class DeviceCommunicationService extends Service { String title = intent.getStringExtra(EXTRA_NOTIFICATION_TITLE); String body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY); int handle = intent.getIntExtra(EXTRA_NOTIFICATION_HANDLE,-1); - mDeviceSupport.onGenericNotification(title, body, handle); + NotificationKind notification_kind = (NotificationKind) intent.getSerializableExtra(EXTRA_NOTIFICATION_KIND); + mDeviceSupport.onGenericNotification(title, body, handle, notification_kind); break; } case ACTION_NOTIFICATION_SMS: { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index 6639b8cc..6e4d7174 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -14,6 +14,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; /** * Wraps another device support instance and supports busy-checking and throttling of events. @@ -127,11 +128,11 @@ public class ServiceDeviceSupport implements DeviceSupport { } @Override - public void onGenericNotification(String title, String details, int handle) { + public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { if (checkBusy("generic notification") || checkThrottle("generic notification")) { return; } - delegate.onGenericNotification(title, details, handle); + delegate.onGenericNotification(title, details, handle, notification_kind); } @Override 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 f2a2a479..58477bab 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 @@ -29,6 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; @@ -411,7 +412,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } @Override - public void onGenericNotification(String title, String details, int handle) { + public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { performPreferredNotification("generic notification received", ORIGIN_GENERIC, null); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index bbb9fd21..587d9bed 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -24,6 +24,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; public class PebbleProtocol extends GBDeviceProtocol { @@ -456,7 +457,7 @@ public class PebbleProtocol extends GBDeviceProtocol { return buf.array(); } - private byte[] encodeNotification(int id, String title, String subtitle, String body, byte type, boolean hasHandle) { + private byte[] encodeNotification(int id, String title, String subtitle, String body, byte type, boolean hasHandle, NotificationKind notification_kind) { Long ts = System.currentTimeMillis(); if (!isFw3x) { ts += (SimpleTimeZone.getDefault().getOffset(ts)); @@ -466,7 +467,7 @@ public class PebbleProtocol extends GBDeviceProtocol { if (isFw3x) { // 3.x notification //return encodeTimelinePin(id, (int) (ts + 600 & 0xffffffff), (short) 90, 21, title); // really, this is just for testing - return encodeBlobdbNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle); + return encodeBlobdbNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle, notification_kind); } else if (mForceProtocol || type != NOTIFICATION_EMAIL) { // 2.x notification return encodeExtensibleNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle); @@ -480,17 +481,17 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeSMS(String from, String body) { - return encodeNotification(mRandom.nextInt(), from, null, body, NOTIFICATION_SMS, false); + return encodeNotification(mRandom.nextInt(), from, null, body, NOTIFICATION_SMS, false, NotificationKind.UNDEFINED); } @Override public byte[] encodeEmail(String from, String subject, String body) { - return encodeNotification(mRandom.nextInt(), from, subject, body, NOTIFICATION_EMAIL, false); + return encodeNotification(mRandom.nextInt(), from, subject, body, NOTIFICATION_EMAIL, false, NotificationKind.UNDEFINED); } @Override - public byte[] encodeGenericNotification(String title, String details, int handle) { - return encodeNotification(handle, title, null, details, NOTIFICATION_UNDEFINED, true); + public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { + return encodeNotification(handle, title, null, details, NOTIFICATION_UNDEFINED, true, notification_kind); } @Override @@ -691,7 +692,7 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array()); } - private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, byte type, boolean hasHandle) { + private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, byte type, boolean hasHandle, NotificationKind notification_kind) { final short NOTIFICATION_PIN_LENGTH = 46; final short ACTION_LENGTH_MIN = 10; @@ -705,14 +706,21 @@ public class PebbleProtocol extends GBDeviceProtocol { case NOTIFICATION_SMS: icon_id = ICON_GENERIC_SMS; break; - case NOTIFICATION_FACEBOOK: - icon_id = ICON_NOTIFICATION_FACEBOOK; - break; - case NOTIFICATION_TWITTER: - icon_id = ICON_NOTIFICATION_TWITTER; - break; default: - icon_id = ICON_NOTIFICATION_GENERIC; + switch(notification_kind){ + case TWITTER: + icon_id = ICON_NOTIFICATION_TWITTER; + break; + case EMAIL: + icon_id = ICON_GENERIC_EMAIL; + break; + case FACEBOOK: + icon_id = ICON_NOTIFICATION_FACEBOOK; + break; + default: + icon_id = ICON_NOTIFICATION_GENERIC; + break; + } break; } // Calculate length first diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index 448f699f..d608f326 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -7,6 +7,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; @@ -118,8 +119,8 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport } @Override - public void onGenericNotification(String title, String details, int handle) { - byte[] bytes = gbDeviceProtocol.encodeGenericNotification(title, details, handle); + public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { + byte[] bytes = gbDeviceProtocol.encodeGenericNotification(title, details, handle, notification_kind); sendToDevice(bytes); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 90cf1d48..13bfb1cb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -3,6 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.service.serial; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; public abstract class GBDeviceProtocol { @@ -15,7 +16,7 @@ public abstract class GBDeviceProtocol { return null; } - public byte[] encodeGenericNotification(String title, String details, int handle) { + public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { return null; } @@ -66,4 +67,4 @@ public abstract class GBDeviceProtocol { public GBDeviceEvent[] decodeResponse(byte[] responseData) { return null; } -} \ No newline at end of file +} diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index cb85dd2b..f49edda4 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -12,6 +12,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; public class TestDeviceSupport extends AbstractDeviceSupport { @@ -58,7 +59,7 @@ public class TestDeviceSupport extends AbstractDeviceSupport { } @Override - public void onGenericNotification(String title, String details, int handle) { + public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { } From a85c04c02a1a321bfa7469c71afda601a3c80915 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 12:55:10 +0200 Subject: [PATCH 20/73] Pebble: use constant for icons where possible --- .../service/devices/pebble/PebbleProtocol.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 587d9bed..0eeec3c6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -466,7 +466,7 @@ public class PebbleProtocol extends GBDeviceProtocol { if (isFw3x) { // 3.x notification - //return encodeTimelinePin(id, (int) (ts + 600 & 0xffffffff), (short) 90, 21, title); // really, this is just for testing + //return encodeTimelinePin(id, (int) (ts + 600 & 0xffffffff), (short) 90, ICON_TIMELINE_CALENDAR, title); // really, this is just for testing return encodeBlobdbNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle, notification_kind); } else if (mForceProtocol || type != NOTIFICATION_EMAIL) { // 2.x notification @@ -1360,17 +1360,17 @@ public class PebbleProtocol extends GBDeviceProtocol { case 0x01: dismissNotification.event = GBDeviceEventNotificationControl.Event.OPEN; caption = "Opened"; - icon_id = 49; + icon_id = ICON_DURING_PHONE_CALL; break; case 0x02: dismissNotification.event = GBDeviceEventNotificationControl.Event.DISMISS; caption = "Dismissed"; - icon_id = 51; + icon_id = ICON_RESULT_DISMISSED; break; case 0x03: dismissNotification.event = GBDeviceEventNotificationControl.Event.DISMISS_ALL; caption = "All dismissed"; - icon_id = 51; + icon_id = ICON_RESULT_DISMISSED; break; } GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); From 44d8294f8cf3df1e3fc7cae8c27e248ac9cbf051 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 13:32:18 +0200 Subject: [PATCH 21/73] Pebble: use Hipchat icon for chat notifications on FW 3.x --- .../service/devices/pebble/PebbleProtocol.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 0eeec3c6..fc5b494c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -457,7 +457,7 @@ public class PebbleProtocol extends GBDeviceProtocol { return buf.array(); } - private byte[] encodeNotification(int id, String title, String subtitle, String body, byte type, boolean hasHandle, NotificationKind notification_kind) { + private byte[] encodeNotification(int id, String title, String subtitle, String body, byte type, boolean hasHandle, NotificationKind notificationKind) { Long ts = System.currentTimeMillis(); if (!isFw3x) { ts += (SimpleTimeZone.getDefault().getOffset(ts)); @@ -467,7 +467,7 @@ public class PebbleProtocol extends GBDeviceProtocol { if (isFw3x) { // 3.x notification //return encodeTimelinePin(id, (int) (ts + 600 & 0xffffffff), (short) 90, ICON_TIMELINE_CALENDAR, title); // really, this is just for testing - return encodeBlobdbNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle, notification_kind); + return encodeBlobdbNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle, notificationKind); } else if (mForceProtocol || type != NOTIFICATION_EMAIL) { // 2.x notification return encodeExtensibleNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle); @@ -490,8 +490,8 @@ public class PebbleProtocol extends GBDeviceProtocol { } @Override - public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { - return encodeNotification(handle, title, null, details, NOTIFICATION_UNDEFINED, true, notification_kind); + public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { + return encodeNotification(handle, title, null, details, NOTIFICATION_UNDEFINED, true, notificationKind); } @Override @@ -692,7 +692,7 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array()); } - private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, byte type, boolean hasHandle, NotificationKind notification_kind) { + private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, byte type, boolean hasHandle, NotificationKind notificationKind) { final short NOTIFICATION_PIN_LENGTH = 46; final short ACTION_LENGTH_MIN = 10; @@ -707,7 +707,7 @@ public class PebbleProtocol extends GBDeviceProtocol { icon_id = ICON_GENERIC_SMS; break; default: - switch(notification_kind){ + switch(notificationKind){ case TWITTER: icon_id = ICON_NOTIFICATION_TWITTER; break; @@ -717,6 +717,9 @@ public class PebbleProtocol extends GBDeviceProtocol { case FACEBOOK: icon_id = ICON_NOTIFICATION_FACEBOOK; break; + case CHAT: + icon_id = ICON_NOTIFICATION_HIPCHAT; + break; default: icon_id = ICON_NOTIFICATION_GENERIC; break; From 4f808440161a95c83176a051aa75f33189b9d094 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 13:38:11 +0200 Subject: [PATCH 22/73] noficicaion_kind -> notificationKind --- .../gadgetbridge/devices/EventHandler.java | 2 +- .../externalevents/NotificationListener.java | 12 ++++++------ .../gadgetbridge/impl/GBDeviceService.java | 4 ++-- .../gadgetbridge/model/DeviceService.java | 2 +- .../service/DeviceCommunicationService.java | 4 ++-- .../gadgetbridge/service/ServiceDeviceSupport.java | 4 ++-- .../service/devices/miband/MiBandSupport.java | 2 +- .../service/serial/AbstractSerialDeviceSupport.java | 4 ++-- .../service/serial/GBDeviceProtocol.java | 2 +- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index 88cdaea2..2b61352c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -20,7 +20,7 @@ public interface EventHandler { void onEmail(String from, String subject, String body); - void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind); + void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind); void onSetTime(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index 891626d7..e5f08b33 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -155,17 +155,17 @@ public class NotificationListener extends NotificationListenerService { } // Set application icons for generic notifications - NotificationKind notification_kind; + NotificationKind notificationKind; if (source.equals("org.mariotaku.twidere") || source.equals("com.twitter.android") || source.equals("org.andstatus.app")) { - notification_kind = NotificationKind.TWITTER; + notificationKind = NotificationKind.TWITTER; } else if (source.equals("com.fsck.k9")) { - notification_kind = NotificationKind.EMAIL; + notificationKind = NotificationKind.EMAIL; } else if (source.equals("eu.siacs.conversations")) { - notification_kind = NotificationKind.CHAT; + notificationKind = NotificationKind.CHAT; } else { - notification_kind = NotificationKind.UNDEFINED; + notificationKind = NotificationKind.UNDEFINED; } LOG.info("Processing notification from source " + source); @@ -181,7 +181,7 @@ public class NotificationListener extends NotificationListenerService { } if (content != null) { - GBApplication.deviceService().onGenericNotification(title, content, (int) sbn.getPostTime(), notification_kind); //FIMXE: a truly unique id would be better + GBApplication.deviceService().onGenericNotification(title, content, (int) sbn.getPostTime(), notificationKind); //FIMXE: a truly unique id would be better } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index 1fc22847..b86bdf8c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -97,12 +97,12 @@ public class GBDeviceService implements DeviceService { } @Override - public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { + public void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { Intent intent = createIntent().setAction(ACTION_NOTIFICATION_GENERIC) .putExtra(EXTRA_NOTIFICATION_TITLE, title) .putExtra(EXTRA_NOTIFICATION_BODY, details) .putExtra(EXTRA_NOTIFICATION_HANDLE, handle) - .putExtra(EXTRA_NOTIFICATION_KIND, notification_kind); + .putExtra(EXTRA_NOTIFICATION_KIND, notificationKind); invokeService(intent); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index a46146db..02c9d1dd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -37,7 +37,7 @@ public interface DeviceService extends EventHandler { static final String EXTRA_NOTIFICATION_SENDER = "notification_sender"; static final String EXTRA_NOTIFICATION_SUBJECT = "notification_subject"; static final String EXTRA_NOTIFICATION_HANDLE = "notification_handle"; - static final String EXTRA_NOTIFICATION_KIND = "notification_kind"; + static final String EXTRA_NOTIFICATION_KIND = "notificationKind"; static final String EXTRA_FIND_START = "find_start"; static final String EXTRA_CALL_COMMAND = "call_command"; static final String EXTRA_CALL_PHONENUMBER = "call_phonenumber"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index af6b9f50..dd1ccbea 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -184,8 +184,8 @@ public class DeviceCommunicationService extends Service { String title = intent.getStringExtra(EXTRA_NOTIFICATION_TITLE); String body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY); int handle = intent.getIntExtra(EXTRA_NOTIFICATION_HANDLE,-1); - NotificationKind notification_kind = (NotificationKind) intent.getSerializableExtra(EXTRA_NOTIFICATION_KIND); - mDeviceSupport.onGenericNotification(title, body, handle, notification_kind); + NotificationKind notificationKind = (NotificationKind) intent.getSerializableExtra(EXTRA_NOTIFICATION_KIND); + mDeviceSupport.onGenericNotification(title, body, handle, notificationKind); break; } case ACTION_NOTIFICATION_SMS: { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index 6e4d7174..b950eaf1 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -128,11 +128,11 @@ public class ServiceDeviceSupport implements DeviceSupport { } @Override - public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { + public void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { if (checkBusy("generic notification") || checkThrottle("generic notification")) { return; } - delegate.onGenericNotification(title, details, handle, notification_kind); + delegate.onGenericNotification(title, details, handle, notificationKind); } @Override 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 58477bab..6d73a1a6 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 @@ -412,7 +412,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } @Override - public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { + public void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { performPreferredNotification("generic notification received", ORIGIN_GENERIC, null); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index d608f326..fbceaa39 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -119,8 +119,8 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport } @Override - public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { - byte[] bytes = gbDeviceProtocol.encodeGenericNotification(title, details, handle, notification_kind); + public void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { + byte[] bytes = gbDeviceProtocol.encodeGenericNotification(title, details, handle, notificationKind); sendToDevice(bytes); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 13bfb1cb..69e195de 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -16,7 +16,7 @@ public abstract class GBDeviceProtocol { return null; } - public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { + public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { return null; } From a73beceb44c06d6418569f6f61e8a969a265092a Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 13:48:21 +0200 Subject: [PATCH 23/73] Map a few more apps to NotificationKind --- .../externalevents/NotificationListener.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index e5f08b33..e7c64cf2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -156,16 +156,26 @@ public class NotificationListener extends NotificationListenerService { // Set application icons for generic notifications NotificationKind notificationKind; - if (source.equals("org.mariotaku.twidere") || - source.equals("com.twitter.android") || - source.equals("org.andstatus.app")) { - notificationKind = NotificationKind.TWITTER; - } else if (source.equals("com.fsck.k9")) { - notificationKind = NotificationKind.EMAIL; - } else if (source.equals("eu.siacs.conversations")) { - notificationKind = NotificationKind.CHAT; - } else { - notificationKind = NotificationKind.UNDEFINED; + switch (source) { + case "org.mariotaku.twidere": + case "com.twitter.android": + case "org.andstatus.app": + case "org.mustard.android": + notificationKind = NotificationKind.TWITTER; + break; + case "com.fsck.k9": + case "com.android.email": + notificationKind = NotificationKind.EMAIL; + break; + case "eu.siacs.conversations": + notificationKind = NotificationKind.CHAT; + break; + case "org.indywidualni.fblite": + notificationKind = NotificationKind.FACEBOOK; + break; + default: + notificationKind = NotificationKind.UNDEFINED; + break; } LOG.info("Processing notification from source " + source); From c69ae753acd7c1875796725fecd286c95221bf84 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 13:50:53 +0200 Subject: [PATCH 24/73] update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3578f50..45b7c3a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ####Version 0.5.4 * Miband: allow the transfer of activity data without clearing MiBand's memory * Pebble: for generic notifications use generic icon instead of SMS icons on FW 3.x (thanks @roidelapluie) +* Pebble: use different icons for specific groups of applications (chat, mail, etc) (thanks @roidelapluie) * In settings, support blacklisting apps for generic notifications ####Version 0.5.3 From eafb795874fb832e999e2fc25eed5f1b1b31f5de Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Sun, 13 Sep 2015 14:26:55 +0200 Subject: [PATCH 25/73] Fix a small typo in gadgetbridge.model.ServiceCommand --- .../freeyourgadget/gadgetbridge/model/ServiceCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ServiceCommand.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ServiceCommand.java index da29ee76..5cb94511 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ServiceCommand.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ServiceCommand.java @@ -2,7 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.model; public enum ServiceCommand { - UNDEFINEND, + UNDEFINED, CALL_ACCEPT, CALL_END, From 10273365910b135d79c28c22a6360f830566e9c0 Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Sun, 13 Sep 2015 13:41:56 +0200 Subject: [PATCH 26/73] Pebble: Support colors in 3.x notifications (Pebble Time) * Generic notifications are still red * Colors are in a separated static class Closes #120. --- .../devices/pebble/ColorConst.java | 76 +++++++++++++++++++ .../devices/pebble/PebbleProtocol.java | 17 ++++- 2 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/ColorConst.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/ColorConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/ColorConst.java new file mode 100644 index 00000000..9d7cea1b --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/ColorConst.java @@ -0,0 +1,76 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.pebble; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class ColorConst { + private static final Logger LOG = LoggerFactory.getLogger(ColorConst.class); + + public static final byte COLOR_Black = (byte) 0b11000000; + public static final byte COLOR_OxfordBlue = (byte) 0b11000001; + public static final byte COLOR_DukeBlue = (byte) 0b11000010; + public static final byte COLOR_Blue = (byte) 0b11000011; + public static final byte COLOR_DarkGreen = (byte) 0b11000100; + public static final byte COLOR_MidnightGreen = (byte) 0b11000101; + public static final byte COLOR_CobaltBlue = (byte) 0b11000110; + public static final byte COLOR_BlueMoon = (byte) 0b11000111; + public static final byte COLOR_IslamicGreen = (byte) 0b11001000; + public static final byte COLOR_JaegerGreen = (byte) 0b11001001; + public static final byte COLOR_TiffanyBlue = (byte) 0b11001010; + public static final byte COLOR_VividCerulean = (byte) 0b11001011; + public static final byte COLOR_Green = (byte) 0b11001100; + public static final byte COLOR_Malachite = (byte) 0b11001101; + public static final byte COLOR_MediumSpringGreen = (byte) 0b11001110; + public static final byte COLOR_Cyan = (byte) 0b11001111; + public static final byte COLOR_BulgarianRose = (byte) 0b11010000; + public static final byte COLOR_ImperialPurple = (byte) 0b11010001; + public static final byte COLOR_Indigo = (byte) 0b11010010; + public static final byte COLOR_ElectricUltramarine = (byte) 0b11010011; + public static final byte COLOR_ArmyGreen = (byte) 0b11010100; + public static final byte COLOR_DarkGray = (byte) 0b11010101; + public static final byte COLOR_Liberty = (byte) 0b11010110; + public static final byte COLOR_VeryLightBlue = (byte) 0b11010111; + public static final byte COLOR_KellyGreen = (byte) 0b11011000; + public static final byte COLOR_MayGreen = (byte) 0b11011001; + public static final byte COLOR_CadetBlue = (byte) 0b11011010; + public static final byte COLOR_PictonBlue = (byte) 0b11011011; + public static final byte COLOR_BrightGreen = (byte) 0b11011100; + public static final byte COLOR_ScreaminGreen = (byte) 0b11011101; + public static final byte COLOR_MediumAquamarine = (byte) 0b11011110; + public static final byte COLOR_ElectricBlue = (byte) 0b11011111; + public static final byte COLOR_DarkCandyAppleRed = (byte) 0b11100000; + public static final byte COLOR_JazzberryJam = (byte) 0b11100001; + public static final byte COLOR_Purple = (byte) 0b11100010; + public static final byte COLOR_VividViolet = (byte) 0b11100011; + public static final byte COLOR_WindsorTan = (byte) 0b11100100; + public static final byte COLOR_RoseVale = (byte) 0b11100101; + public static final byte COLOR_Purpureus = (byte) 0b11100110; + public static final byte COLOR_LavenderIndigo = (byte) 0b11100111; + public static final byte COLOR_Limerick = (byte) 0b11101000; + public static final byte COLOR_Brass = (byte) 0b11101001; + public static final byte COLOR_LightGray = (byte) 0b11101010; + public static final byte COLOR_BabyBlueEyes = (byte) 0b11101011; + public static final byte COLOR_SpringBud = (byte) 0b11101100; + public static final byte COLOR_Inchworm = (byte) 0b11101101; + public static final byte COLOR_MintGreen = (byte) 0b11101110; + public static final byte COLOR_Celeste = (byte) 0b11101111; + public static final byte COLOR_Red = (byte) 0b11110000; + public static final byte COLOR_Folly = (byte) 0b11110001; + public static final byte COLOR_FashionMagenta = (byte) 0b11110010; + public static final byte COLOR_Magenta = (byte) 0b11110011; + public static final byte COLOR_Orange = (byte) 0b11110100; + public static final byte COLOR_SunsetOrange = (byte) 0b11110101; + public static final byte COLOR_BrilliantRose = (byte) 0b11110110; + public static final byte COLOR_ShockingPink = (byte) 0b11110111; + public static final byte COLOR_ChromeYellow = (byte) 0b11111000; + public static final byte COLOR_Rajah = (byte) 0b11111001; + public static final byte COLOR_Melon = (byte) 0b11111010; + public static final byte COLOR_RichBrilliantLavender = (byte) 0b11111011; + public static final byte COLOR_Yellow = (byte) 0b11111100; + public static final byte COLOR_Icterine = (byte) 0b11111101; + public static final byte COLOR_PastelYellow = (byte) 0b11111110; + public static final byte COLOR_White = (byte) 0b11111111; + public static final byte COLOR_Clear = (byte) 0b00000000; + +} + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index fc5b494c..5c46d2e3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -13,6 +13,7 @@ import java.util.Random; import java.util.SimpleTimeZone; import java.util.UUID; +import nodomain.freeyourgadget.gadgetbridge.devices.pebble.ColorConst; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement; @@ -699,29 +700,37 @@ public class PebbleProtocol extends GBDeviceProtocol { String[] parts = {title, subtitle, body}; int icon_id; + byte color_id; switch (type) { case NOTIFICATION_EMAIL: icon_id = ICON_GENERIC_EMAIL; + color_id = ColorConst.COLOR_JaegerGreen; break; case NOTIFICATION_SMS: icon_id = ICON_GENERIC_SMS; + color_id = ColorConst.COLOR_VividViolet; break; default: switch(notificationKind){ case TWITTER: icon_id = ICON_NOTIFICATION_TWITTER; + color_id = ColorConst.COLOR_BlueMoon; break; case EMAIL: icon_id = ICON_GENERIC_EMAIL; + color_id = ColorConst.COLOR_JaegerGreen; break; case FACEBOOK: icon_id = ICON_NOTIFICATION_FACEBOOK; + color_id = ColorConst.COLOR_VeryLightBlue; break; case CHAT: icon_id = ICON_NOTIFICATION_HIPCHAT; + color_id = ColorConst.COLOR_Inchworm; break; default: icon_id = ICON_NOTIFICATION_GENERIC; + color_id = ColorConst.COLOR_Red; break; } break; @@ -744,8 +753,8 @@ public class PebbleProtocol extends GBDeviceProtocol { actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.length() + open_string.length()); } - byte attributes_count = 1; // icon - short attributes_length = (short) (7 + actions_length); // icon + byte attributes_count = 2; // icon + short attributes_length = (short) (11 + actions_length); if (parts != null) { for (String s : parts) { if (s == null || s.equals("")) { @@ -800,6 +809,10 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.putShort((short) 4); // length of int buf.putInt(0x80000000 | icon_id); + buf.put((byte) 28); // background_color + buf.putShort((short) 1); // length of int + buf.put(color_id); + // dismiss action buf.put(dismiss_action_id); buf.put((byte) 0x02); // generic action, dismiss did not do anything From dfe86d681d05f33684c46b9b518d306e6fa3330b Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 14:59:07 +0200 Subject: [PATCH 27/73] update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45b7c3a4..ff345e45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ####Version 0.5.4 * Miband: allow the transfer of activity data without clearing MiBand's memory * Pebble: for generic notifications use generic icon instead of SMS icons on FW 3.x (thanks @roidelapluie) -* Pebble: use different icons for specific groups of applications (chat, mail, etc) (thanks @roidelapluie) +* Pebble: use different icons and background colors for specific groups of applications (chat, mail, etc) (thanks @roidelapluie) * In settings, support blacklisting apps for generic notifications ####Version 0.5.3 From d3dbde6917e3033750a30515e84c4b206be13b27 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 15:21:07 +0200 Subject: [PATCH 28/73] Some refactoring: - Put Pebble icon ID constants in its own class - remove ICON_ and COLOR_ prefixes from constants --- .../devices/pebble/ColorConst.java | 76 ----------- .../devices/pebble/PebbleColor.java | 72 ++++++++++ .../devices/pebble/PebbleIconID.java | 95 +++++++++++++ .../devices/pebble/PebbleProtocol.java | 128 +++--------------- 4 files changed, 186 insertions(+), 185 deletions(-) delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/ColorConst.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleColor.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleIconID.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/ColorConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/ColorConst.java deleted file mode 100644 index 9d7cea1b..00000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/ColorConst.java +++ /dev/null @@ -1,76 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.devices.pebble; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public final class ColorConst { - private static final Logger LOG = LoggerFactory.getLogger(ColorConst.class); - - public static final byte COLOR_Black = (byte) 0b11000000; - public static final byte COLOR_OxfordBlue = (byte) 0b11000001; - public static final byte COLOR_DukeBlue = (byte) 0b11000010; - public static final byte COLOR_Blue = (byte) 0b11000011; - public static final byte COLOR_DarkGreen = (byte) 0b11000100; - public static final byte COLOR_MidnightGreen = (byte) 0b11000101; - public static final byte COLOR_CobaltBlue = (byte) 0b11000110; - public static final byte COLOR_BlueMoon = (byte) 0b11000111; - public static final byte COLOR_IslamicGreen = (byte) 0b11001000; - public static final byte COLOR_JaegerGreen = (byte) 0b11001001; - public static final byte COLOR_TiffanyBlue = (byte) 0b11001010; - public static final byte COLOR_VividCerulean = (byte) 0b11001011; - public static final byte COLOR_Green = (byte) 0b11001100; - public static final byte COLOR_Malachite = (byte) 0b11001101; - public static final byte COLOR_MediumSpringGreen = (byte) 0b11001110; - public static final byte COLOR_Cyan = (byte) 0b11001111; - public static final byte COLOR_BulgarianRose = (byte) 0b11010000; - public static final byte COLOR_ImperialPurple = (byte) 0b11010001; - public static final byte COLOR_Indigo = (byte) 0b11010010; - public static final byte COLOR_ElectricUltramarine = (byte) 0b11010011; - public static final byte COLOR_ArmyGreen = (byte) 0b11010100; - public static final byte COLOR_DarkGray = (byte) 0b11010101; - public static final byte COLOR_Liberty = (byte) 0b11010110; - public static final byte COLOR_VeryLightBlue = (byte) 0b11010111; - public static final byte COLOR_KellyGreen = (byte) 0b11011000; - public static final byte COLOR_MayGreen = (byte) 0b11011001; - public static final byte COLOR_CadetBlue = (byte) 0b11011010; - public static final byte COLOR_PictonBlue = (byte) 0b11011011; - public static final byte COLOR_BrightGreen = (byte) 0b11011100; - public static final byte COLOR_ScreaminGreen = (byte) 0b11011101; - public static final byte COLOR_MediumAquamarine = (byte) 0b11011110; - public static final byte COLOR_ElectricBlue = (byte) 0b11011111; - public static final byte COLOR_DarkCandyAppleRed = (byte) 0b11100000; - public static final byte COLOR_JazzberryJam = (byte) 0b11100001; - public static final byte COLOR_Purple = (byte) 0b11100010; - public static final byte COLOR_VividViolet = (byte) 0b11100011; - public static final byte COLOR_WindsorTan = (byte) 0b11100100; - public static final byte COLOR_RoseVale = (byte) 0b11100101; - public static final byte COLOR_Purpureus = (byte) 0b11100110; - public static final byte COLOR_LavenderIndigo = (byte) 0b11100111; - public static final byte COLOR_Limerick = (byte) 0b11101000; - public static final byte COLOR_Brass = (byte) 0b11101001; - public static final byte COLOR_LightGray = (byte) 0b11101010; - public static final byte COLOR_BabyBlueEyes = (byte) 0b11101011; - public static final byte COLOR_SpringBud = (byte) 0b11101100; - public static final byte COLOR_Inchworm = (byte) 0b11101101; - public static final byte COLOR_MintGreen = (byte) 0b11101110; - public static final byte COLOR_Celeste = (byte) 0b11101111; - public static final byte COLOR_Red = (byte) 0b11110000; - public static final byte COLOR_Folly = (byte) 0b11110001; - public static final byte COLOR_FashionMagenta = (byte) 0b11110010; - public static final byte COLOR_Magenta = (byte) 0b11110011; - public static final byte COLOR_Orange = (byte) 0b11110100; - public static final byte COLOR_SunsetOrange = (byte) 0b11110101; - public static final byte COLOR_BrilliantRose = (byte) 0b11110110; - public static final byte COLOR_ShockingPink = (byte) 0b11110111; - public static final byte COLOR_ChromeYellow = (byte) 0b11111000; - public static final byte COLOR_Rajah = (byte) 0b11111001; - public static final byte COLOR_Melon = (byte) 0b11111010; - public static final byte COLOR_RichBrilliantLavender = (byte) 0b11111011; - public static final byte COLOR_Yellow = (byte) 0b11111100; - public static final byte COLOR_Icterine = (byte) 0b11111101; - public static final byte COLOR_PastelYellow = (byte) 0b11111110; - public static final byte COLOR_White = (byte) 0b11111111; - public static final byte COLOR_Clear = (byte) 0b00000000; - -} - diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleColor.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleColor.java new file mode 100644 index 00000000..4abc4dde --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleColor.java @@ -0,0 +1,72 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.pebble; + +public final class PebbleColor { + + public static final byte Black = (byte) 0b11000000; + public static final byte OxfordBlue = (byte) 0b11000001; + public static final byte DukeBlue = (byte) 0b11000010; + public static final byte Blue = (byte) 0b11000011; + public static final byte DarkGreen = (byte) 0b11000100; + public static final byte MidnightGreen = (byte) 0b11000101; + public static final byte CobaltBlue = (byte) 0b11000110; + public static final byte BlueMoon = (byte) 0b11000111; + public static final byte IslamicGreen = (byte) 0b11001000; + public static final byte JaegerGreen = (byte) 0b11001001; + public static final byte TiffanyBlue = (byte) 0b11001010; + public static final byte VividCerulean = (byte) 0b11001011; + public static final byte Green = (byte) 0b11001100; + public static final byte Malachite = (byte) 0b11001101; + public static final byte MediumSpringGreen = (byte) 0b11001110; + public static final byte Cyan = (byte) 0b11001111; + public static final byte BulgarianRose = (byte) 0b11010000; + public static final byte ImperialPurple = (byte) 0b11010001; + public static final byte Indigo = (byte) 0b11010010; + public static final byte ElectricUltramarine = (byte) 0b11010011; + public static final byte ArmyGreen = (byte) 0b11010100; + public static final byte DarkGray = (byte) 0b11010101; + public static final byte Liberty = (byte) 0b11010110; + public static final byte VeryLightBlue = (byte) 0b11010111; + public static final byte KellyGreen = (byte) 0b11011000; + public static final byte MayGreen = (byte) 0b11011001; + public static final byte CadetBlue = (byte) 0b11011010; + public static final byte PictonBlue = (byte) 0b11011011; + public static final byte BrightGreen = (byte) 0b11011100; + public static final byte ScreaminGreen = (byte) 0b11011101; + public static final byte MediumAquamarine = (byte) 0b11011110; + public static final byte ElectricBlue = (byte) 0b11011111; + public static final byte DarkCandyAppleRed = (byte) 0b11100000; + public static final byte JazzberryJam = (byte) 0b11100001; + public static final byte Purple = (byte) 0b11100010; + public static final byte VividViolet = (byte) 0b11100011; + public static final byte WindsorTan = (byte) 0b11100100; + public static final byte RoseVale = (byte) 0b11100101; + public static final byte Purpureus = (byte) 0b11100110; + public static final byte LavenderIndigo = (byte) 0b11100111; + public static final byte Limerick = (byte) 0b11101000; + public static final byte Brass = (byte) 0b11101001; + public static final byte LightGray = (byte) 0b11101010; + public static final byte BabyBlueEyes = (byte) 0b11101011; + public static final byte SpringBud = (byte) 0b11101100; + public static final byte Inchworm = (byte) 0b11101101; + public static final byte MintGreen = (byte) 0b11101110; + public static final byte Celeste = (byte) 0b11101111; + public static final byte Red = (byte) 0b11110000; + public static final byte Folly = (byte) 0b11110001; + public static final byte FashionMagenta = (byte) 0b11110010; + public static final byte Magenta = (byte) 0b11110011; + public static final byte Orange = (byte) 0b11110100; + public static final byte SunsetOrange = (byte) 0b11110101; + public static final byte BrilliantRose = (byte) 0b11110110; + public static final byte ShockingPink = (byte) 0b11110111; + public static final byte ChromeYellow = (byte) 0b11111000; + public static final byte Rajah = (byte) 0b11111001; + public static final byte Melon = (byte) 0b11111010; + public static final byte RichBrilliantLavender = (byte) 0b11111011; + public static final byte Yellow = (byte) 0b11111100; + public static final byte Icterine = (byte) 0b11111101; + public static final byte PastelYellow = (byte) 0b11111110; + public static final byte White = (byte) 0b11111111; + public static final byte Clear = (byte) 0b00000000; + +} + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleIconID.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleIconID.java new file mode 100644 index 00000000..18b409ae --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PebbleIconID.java @@ -0,0 +1,95 @@ +package nodomain.freeyourgadget.gadgetbridge.devices.pebble; + +public final class PebbleIconID { + + public static final int NOTIFICATION_GENERIC = 1; + public static final int TIMELINE_MISSED_CALL = 2; + public static final int NOTIFICATION_REMINDER = 3; + public static final int NOTIFICATION_FLAG = 4; + public static final int NOTIFICATION_WHATSAPP = 5; + public static final int NOTIFICATION_TWITTER = 6; + public static final int NOTIFICATION_TELEGRAM = 7; + public static final int NOTIFICATION_GOOGLE_HANGOUTS = 8; + public static final int NOTIFICATION_GMAIL = 9; + public static final int NOTIFICATION_FACEBOOK_MESSENGER = 10; + public static final int NOTIFICATION_FACEBOOK = 11; + public static final int AUDIO_CASSETTE = 12; + public static final int ALARM_CLOCK = 13; + public static final int TIMELINE_WEATHER = 14; + public static final int TIMELINE_SUN = 16; + public static final int TIMELINE_SPORTS = 17; + public static final int GENERIC_EMAIL = 19; + public static final int AMERICAN_FOOTBALL = 20; + public static final int TIMELINE_CALENDAR = 21; + public static final int TIMELINE_BASEBALL = 22; + public static final int BIRTHDAY_EVENT = 23; + public static final int CAR_RENTAL = 24; + public static final int CLOUDY_DAY = 25; + public static final int CRICKET_GAME = 26; + public static final int DINNER_RESERVATION = 27; + public static final int GENERIC_WARNING = 28; + public static final int GLUCOSE_MONITOR = 29; + public static final int HOCKEY_GAME = 30; + public static final int HOTEL_RESERVATION = 31; + public static final int LIGHT_RAIN = 32; + public static final int LIGHT_SNOW = 33; + public static final int MOVIE_EVENT = 34; + public static final int MUSIC_EVENT = 35; + public static final int NEWS_EVENT = 36; + public static final int PARTLY_CLOUDY = 37; + public static final int PAY_BILL = 38; + public static final int RADIO_SHOW = 39; + public static final int SCHEDULED_EVENT = 40; + public static final int SOCCER_GAME = 41; + public static final int STOCKS_EVENT = 42; + public static final int RESULT_DELETED = 43; + public static final int CHECK_INTERNET_CONNECTION = 44; + public static final int GENERIC_SMS = 45; + public static final int RESULT_MUTE = 46; + public static final int RESULT_SENT = 47; + public static final int WATCH_DISCONNECTED = 48; + public static final int DURING_PHONE_CALL = 49; + public static final int TIDE_IS_HIGH = 50; + public static final int RESULT_DISMISSED = 51; + public static final int HEAVY_RAIN = 52; + public static final int HEAVY_SNOW = 53; + public static final int SCHEDULED_FLIGHT = 54; + public static final int GENERIC_CONFIRMATION = 55; + public static final int DAY_SEPARATOR = 56; + public static final int NO_EVENTS = 57; + public static final int NOTIFICATION_BLACKBERRY_MESSENGER = 58; + public static final int NOTIFICATION_INSTAGRAM = 59; + public static final int NOTIFICATION_MAILBOX = 60; + public static final int NOTIFICATION_GOOGLE_INBOX = 61; + public static final int RESULT_FAILED = 62; + public static final int GENERIC_QUESTION = 63; + public static final int NOTIFICATION_OUTLOOK = 64; + public static final int RAINING_AND_SNOWING = 65; + public static final int REACHED_FITNESS_GOAL = 66; + public static final int NOTIFICATION_LINE = 67; + public static final int NOTIFICATION_SKYPE = 68; + public static final int NOTIFICATION_SNAPCHAT = 69; + public static final int NOTIFICATION_VIBER = 70; + public static final int NOTIFICATION_WECHAT = 71; + public static final int NOTIFICATION_YAHOO_MAIL = 72; + public static final int TV_SHOW = 73; + public static final int BASKETBALL = 74; + public static final int DISMISSED_PHONE_CALL = 75; + public static final int NOTIFICATION_GOOGLE_MESSENGER = 76; + public static final int NOTIFICATION_HIPCHAT = 77; + public static final int INCOMING_PHONE_CALL = 78; + public static final int NOTIFICATION_KAKAOTALK = 79; + public static final int NOTIFICATION_KIK = 80; + public static final int NOTIFICATION_LIGHTHOUSE = 81; + public static final int LOCATION = 82; + public static final int SETTINGS = 83; + public static final int SUNRISE = 84; + public static final int SUNSET = 85; + public static final int FACETIME_DISMISSED = 86; + public static final int FACETIME_INCOMING = 87; + public static final int FACETIME_OUTGOING = 88; + public static final int FACETIME_MISSED = 89; + public static final int FACETIME_DURING = 90; + public static final int BLUESCREEN_OF_DEATH = 91; + public static final int START_MUSIC_PHONE = 92; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 5c46d2e3..e338ff83 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -13,7 +13,8 @@ import java.util.Random; import java.util.SimpleTimeZone; import java.util.UUID; -import nodomain.freeyourgadget.gadgetbridge.devices.pebble.ColorConst; +import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor; +import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleIconID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement; @@ -80,97 +81,6 @@ public class PebbleProtocol extends GBDeviceProtocol { static final byte NOTIFICATION_TWITTER = 2; static final byte NOTIFICATION_FACEBOOK = 3; - static final byte ICON_NOTIFICATION_GENERIC = 1; - static final byte ICON_TIMELINE_MISSED_CALL = 2; - static final byte ICON_NOTIFICATION_REMINDER = 3; - static final byte ICON_NOTIFICATION_FLAG = 4; - static final byte ICON_NOTIFICATION_WHATSAPP = 5; - static final byte ICON_NOTIFICATION_TWITTER = 6; - static final byte ICON_NOTIFICATION_TELEGRAM = 7; - static final byte ICON_NOTIFICATION_GOOGLE_HANGOUTS = 8; - static final byte ICON_NOTIFICATION_GMAIL = 9; - static final byte ICON_NOTIFICATION_FACEBOOK_MESSENGER = 10; - static final byte ICON_NOTIFICATION_FACEBOOK = 11; - static final byte ICON_AUDIO_CASSETTE = 12; - static final byte ICON_ALARM_CLOCK = 13; - static final byte ICON_TIMELINE_WEATHER = 14; - static final byte ICON_TIMELINE_SUN = 16; - static final byte ICON_TIMELINE_SPORTS = 17; - static final byte ICON_GENERIC_EMAIL = 19; - static final byte ICON_AMERICAN_FOOTBALL = 20; - static final byte ICON_TIMELINE_CALENDAR = 21; - static final byte ICON_TIMELINE_BASEBALL = 22; - static final byte ICON_BIRTHDAY_EVENT = 23; - static final byte ICON_CAR_RENTAL = 24; - static final byte ICON_CLOUDY_DAY = 25; - static final byte ICON_CRICKET_GAME = 26; - static final byte ICON_DINNER_RESERVATION = 27; - static final byte ICON_GENERIC_WARNING = 28; - static final byte ICON_GLUCOSE_MONITOR = 29; - static final byte ICON_HOCKEY_GAME = 30; - static final byte ICON_HOTEL_RESERVATION = 31; - static final byte ICON_LIGHT_RAIN = 32; - static final byte ICON_LIGHT_SNOW = 33; - static final byte ICON_MOVIE_EVENT = 34; - static final byte ICON_MUSIC_EVENT = 35; - static final byte ICON_NEWS_EVENT = 36; - static final byte ICON_PARTLY_CLOUDY = 37; - static final byte ICON_PAY_BILL = 38; - static final byte ICON_RADIO_SHOW = 39; - static final byte ICON_SCHEDULED_EVENT = 40; - static final byte ICON_SOCCER_GAME = 41; - static final byte ICON_STOCKS_EVENT = 42; - static final byte ICON_RESULT_DELETED = 43; - static final byte ICON_CHECK_INTERNET_CONNECTION = 44; - static final byte ICON_GENERIC_SMS = 45; - static final byte ICON_RESULT_MUTE = 46; - static final byte ICON_RESULT_SENT = 47; - static final byte ICON_WATCH_DISCONNECTED = 48; - static final byte ICON_DURING_PHONE_CALL = 49; - static final byte ICON_TIDE_IS_HIGH = 50; - static final byte ICON_RESULT_DISMISSED = 51; - static final byte ICON_HEAVY_RAIN = 52; - static final byte ICON_HEAVY_SNOW = 53; - static final byte ICON_SCHEDULED_FLIGHT = 54; - static final byte ICON_GENERIC_CONFIRMATION = 55; - static final byte ICON_DAY_SEPARATOR = 56; - static final byte ICON_NO_EVENTS = 57; - static final byte ICON_NOTIFICATION_BLACKBERRY_MESSENGER = 58; - static final byte ICON_NOTIFICATION_INSTAGRAM = 59; - static final byte ICON_NOTIFICATION_MAILBOX = 60; - static final byte ICON_NOTIFICATION_GOOGLE_INBOX = 61; - static final byte ICON_RESULT_FAILED = 62; - static final byte ICON_GENERIC_QUESTION = 63; - static final byte ICON_NOTIFICATION_OUTLOOK = 64; - static final byte ICON_RAINING_AND_SNOWING = 65; - static final byte ICON_REACHED_FITNESS_GOAL = 66; - static final byte ICON_NOTIFICATION_LINE = 67; - static final byte ICON_NOTIFICATION_SKYPE = 68; - static final byte ICON_NOTIFICATION_SNAPCHAT = 69; - static final byte ICON_NOTIFICATION_VIBER = 70; - static final byte ICON_NOTIFICATION_WECHAT = 71; - static final byte ICON_NOTIFICATION_YAHOO_MAIL = 72; - static final byte ICON_TV_SHOW = 73; - static final byte ICON_BASKETBALL = 74; - static final byte ICON_DISMISSED_PHONE_CALL = 75; - static final byte ICON_NOTIFICATION_GOOGLE_MESSENGER = 76; - static final byte ICON_NOTIFICATION_HIPCHAT = 77; - static final byte ICON_INCOMING_PHONE_CALL = 78; - static final byte ICON_NOTIFICATION_KAKAOTALK = 79; - static final byte ICON_NOTIFICATION_KIK = 80; - static final byte ICON_NOTIFICATION_LIGHTHOUSE = 81; - static final byte ICON_LOCATION = 82; - static final byte ICON_SETTINGS = 83; - static final byte ICON_SUNRISE = 84; - static final byte ICON_SUNSET = 85; - static final byte ICON_FACETIME_DISMISSED = 86; - static final byte ICON_FACETIME_INCOMING = 87; - static final byte ICON_FACETIME_OUTGOING = 88; - static final byte ICON_FACETIME_MISSED = 89; - static final byte ICON_FACETIME_DURING = 90; - static final byte ICON_BLUESCREEN_OF_DEATH = 91; - static final byte ICON_START_MUSIC_PHONE = 92; - static final byte PHONECONTROL_ANSWER = 1; static final byte PHONECONTROL_HANGUP = 2; static final byte PHONECONTROL_GETSTATE = 3; @@ -703,34 +613,34 @@ public class PebbleProtocol extends GBDeviceProtocol { byte color_id; switch (type) { case NOTIFICATION_EMAIL: - icon_id = ICON_GENERIC_EMAIL; - color_id = ColorConst.COLOR_JaegerGreen; + icon_id = PebbleIconID.GENERIC_EMAIL; + color_id = PebbleColor.JaegerGreen; break; case NOTIFICATION_SMS: - icon_id = ICON_GENERIC_SMS; - color_id = ColorConst.COLOR_VividViolet; + icon_id = PebbleIconID.GENERIC_SMS; + color_id = PebbleColor.VividViolet; break; default: switch(notificationKind){ case TWITTER: - icon_id = ICON_NOTIFICATION_TWITTER; - color_id = ColorConst.COLOR_BlueMoon; + icon_id = PebbleIconID.NOTIFICATION_TWITTER; + color_id = PebbleColor.BlueMoon; break; case EMAIL: - icon_id = ICON_GENERIC_EMAIL; - color_id = ColorConst.COLOR_JaegerGreen; + icon_id = PebbleIconID.GENERIC_EMAIL; + color_id = PebbleColor.JaegerGreen; break; case FACEBOOK: - icon_id = ICON_NOTIFICATION_FACEBOOK; - color_id = ColorConst.COLOR_VeryLightBlue; + icon_id = PebbleIconID.NOTIFICATION_FACEBOOK; + color_id = PebbleColor.VeryLightBlue; break; case CHAT: - icon_id = ICON_NOTIFICATION_HIPCHAT; - color_id = ColorConst.COLOR_Inchworm; + icon_id = PebbleIconID.NOTIFICATION_HIPCHAT; + color_id = PebbleColor.Inchworm; break; default: - icon_id = ICON_NOTIFICATION_GENERIC; - color_id = ColorConst.COLOR_Red; + icon_id = PebbleIconID.NOTIFICATION_GENERIC; + color_id = PebbleColor.Red; break; } break; @@ -1376,17 +1286,17 @@ public class PebbleProtocol extends GBDeviceProtocol { case 0x01: dismissNotification.event = GBDeviceEventNotificationControl.Event.OPEN; caption = "Opened"; - icon_id = ICON_DURING_PHONE_CALL; + icon_id = PebbleIconID.DURING_PHONE_CALL; break; case 0x02: dismissNotification.event = GBDeviceEventNotificationControl.Event.DISMISS; caption = "Dismissed"; - icon_id = ICON_RESULT_DISMISSED; + icon_id = PebbleIconID.RESULT_DISMISSED; break; case 0x03: dismissNotification.event = GBDeviceEventNotificationControl.Event.DISMISS_ALL; caption = "All dismissed"; - icon_id = ICON_RESULT_DISMISSED; + icon_id = PebbleIconID.RESULT_DISMISSED; break; } GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); From 9a32be97cb7b3a39fcca23e16ab04a3944b9c154 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 18:20:15 +0200 Subject: [PATCH 29/73] Pebble: work towards PebbleKit support #106 - Untested features have to be turned on. - We will accept data from any source. - One way, we do not send out replies. This already works with the minimalistic sports demo from the sdk --- .../devices/pebble/PebbleIoThread.java | 80 +++++++++++++++++++ .../devices/pebble/PebbleProtocol.java | 31 ++++++- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 76a71483..99f788b0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -3,12 +3,17 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.net.Uri; import android.os.ParcelUuid; import android.preference.PreferenceManager; +import org.json.JSONArray; +import org.json.JSONException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -20,6 +25,7 @@ import java.net.InetAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.UUID; import java.util.zip.ZipInputStream; import nodomain.freeyourgadget.gadgetbridge.R; @@ -38,6 +44,18 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB; public class PebbleIoThread extends GBDeviceIoThread { private static final Logger LOG = LoggerFactory.getLogger(PebbleIoThread.class); + + public static final String PEBBLEKIT_ACTION_PEBBLE_CONNECTED = "com.getpebble.action.PEBBLE_CONNECTED"; + public static final String PEBBLEKIT_ACTION_PEBBLE_DISCONNECTED = "com.getpebble.action.PEBBLE_DISCONNECTED"; + public static final String PEBBLEKIT_ACTION_APP_ACK = "com.getpebble.action.app.ACK"; + public static final String PEBBLEKIT_ACTION_APP_NACK = "com.getpebble.action.app.NACK"; + public static final String PEBBLEKIT_ACTION_APP_RECEIVE = "com.getpebble.action.app.RECEIVE"; + public static final String PEBBLEKIT_ACTION_APP_RECEIVE_ACK = "com.getpebble.action.app.RECEIVE_ACK"; + public static final String PEBBLEKIT_ACTION_APP_RECEIVE_NACK = "com.getpebble.action.app.RECEIVE_NACK"; + public static final String PEBBLEKIT_ACTION_APP_SEND = "com.getpebble.action.app.SEND"; + public static final String PEBBLEKIT_ACTION_APP_START = "com.getpebble.action.app.START"; + public static final String PEBBLEKIT_ACTION_APP_STOP = "com.getpebble.action.app.STOP"; + private final PebbleProtocol mPebbleProtocol; private final PebbleSupport mPebbleSupport; private boolean mIsTCP = false; @@ -62,6 +80,35 @@ public class PebbleIoThread extends GBDeviceIoThread { private int mBinarySize = -1; private int mBytesWritten = -1; + private final BroadcastReceiver mPebbleKitReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + LOG.info("Got action: " + action); + UUID uuid; + switch (action) { + case PEBBLEKIT_ACTION_APP_START: + uuid = (UUID) intent.getSerializableExtra("uuid"); + if (uuid != null) { + write(mPebbleProtocol.encodeAppStart(uuid)); + } + break; + case PEBBLEKIT_ACTION_APP_SEND: + uuid = (UUID) intent.getSerializableExtra("uuid"); + String jsonString = intent.getStringExtra("msg_data"); + LOG.info("json string: " + jsonString); + + try { + JSONArray jsonArray = new JSONArray(jsonString); + write(mPebbleProtocol.encodeApplicationMessageFromJSON(uuid, jsonArray)); + } catch (JSONException e) { + e.printStackTrace(); + } + break; + } + } + }; + public PebbleIoThread(PebbleSupport pebbleSupport, GBDevice gbDevice, GBDeviceProtocol gbDeviceProtocol, BluetoothAdapter btAdapter, Context context) { super(gbDevice, context); mPebbleProtocol = (PebbleProtocol) gbDeviceProtocol; @@ -116,6 +163,7 @@ public class PebbleIoThread extends GBDeviceIoThread { gbDevice.sendDeviceUpdateIntent(getContext()); mIsConnected = connect(gbDevice.getAddress()); + enablePebbleKitReceiver(mIsConnected); mQuit = !mIsConnected; // quit if not connected byte[] buffer = new byte[8192]; @@ -285,11 +333,43 @@ public class PebbleIoThread extends GBDeviceIoThread { e.printStackTrace(); } } + enablePebbleKitReceiver(false); mBtSocket = null; gbDevice.setState(GBDevice.State.NOT_CONNECTED); gbDevice.sendDeviceUpdateIntent(getContext()); } + private void enablePebbleKitReceiver(boolean enable) { + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + boolean force_untested = sharedPrefs.getBoolean("pebble_force_untested", false); + + if (enable && force_untested) { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(PEBBLEKIT_ACTION_APP_ACK); + intentFilter.addAction(PEBBLEKIT_ACTION_APP_NACK); + intentFilter.addAction(PEBBLEKIT_ACTION_APP_RECEIVE); + intentFilter.addAction(PEBBLEKIT_ACTION_APP_RECEIVE_ACK); + intentFilter.addAction(PEBBLEKIT_ACTION_APP_RECEIVE_NACK); + intentFilter.addAction(PEBBLEKIT_ACTION_APP_SEND); + intentFilter.addAction(PEBBLEKIT_ACTION_APP_START); + intentFilter.addAction(PEBBLEKIT_ACTION_APP_STOP); + intentFilter.addAction(PEBBLEKIT_ACTION_PEBBLE_CONNECTED); + intentFilter.addAction(PEBBLEKIT_ACTION_PEBBLE_DISCONNECTED); + try { + getContext().registerReceiver(mPebbleKitReceiver, intentFilter); + } catch (IllegalArgumentException e) { + // ignore + } + } else { + try { + getContext().unregisterReceiver(mPebbleKitReceiver); + } catch (IllegalArgumentException e) { + // ignore + } + } + } + + private void write_real(byte[] bytes) { try { if (mIsTCP) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index e338ff83..a8c3b2f6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -2,6 +2,9 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; import android.util.Pair; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,8 +16,6 @@ import java.util.Random; import java.util.SimpleTimeZone; import java.util.UUID; -import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor; -import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleIconID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement; @@ -24,9 +25,11 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificati import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventScreenshot; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; +import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor; +import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleIconID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; +import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; public class PebbleProtocol extends GBDeviceProtocol { @@ -621,7 +624,7 @@ public class PebbleProtocol extends GBDeviceProtocol { color_id = PebbleColor.VividViolet; break; default: - switch(notificationKind){ + switch (notificationKind) { case TWITTER: icon_id = PebbleIconID.NOTIFICATION_TWITTER; color_id = PebbleColor.BlueMoon; @@ -1173,6 +1176,26 @@ public class PebbleProtocol extends GBDeviceProtocol { return buf.array(); } + public byte[] encodeApplicationMessageFromJSON(UUID uuid, JSONArray jsonArray) { + ArrayList> pairs = new ArrayList<>(); + for (int i = 0; i < jsonArray.length(); i++) { + try { + JSONObject jsonObject = (JSONObject) jsonArray.get(i); + String type = (String) jsonObject.get("type"); + int key = (int) jsonObject.get("key"); + if (type.equals("uint") || type.equals("int")) { + pairs.add(new Pair<>(key, (Object) jsonObject.getInt("value"))); + } else if (type.equals("string")) { + pairs.add(new Pair<>(key, (Object) jsonObject.getString("value"))); + } + } catch (JSONException e) { + return null; + } + } + + return encodeApplicationMessagePush(ENDPOINT_APPLICATIONMESSAGE, uuid, pairs); + } + private static byte reverseBits(byte in) { byte out = 0; for (int i = 0; i < 8; i++) { From 6fff4fb7ba5bb99784bc835635df7b4166ddbb0c Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 18:37:59 +0200 Subject: [PATCH 30/73] Pebble: support byte arrays for Appmessages (including PebbleKit ones) --- .../service/devices/pebble/PebbleProtocol.java | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index a8c3b2f6..f0ed9a12 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -1,5 +1,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; +import android.util.Base64; import android.util.Pair; import org.json.JSONArray; @@ -1146,8 +1147,11 @@ public class PebbleProtocol extends GBDeviceProtocol { length += 4; } else if (pair.second instanceof String) { length += ((String) pair.second).length() + 1; + } else if (pair.second instanceof byte[]) { + length += ((byte[]) pair.second).length; } } + ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort((short) length); @@ -1166,10 +1170,16 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.putShort((short) 4); // length of int buf.putInt((int) pair.second); } else if (pair.second instanceof String) { + String str = (String) pair.second; buf.put(TYPE_CSTRING); - buf.putShort((short) (((String) pair.second).length() + 1)); - buf.put(((String) pair.second).getBytes()); + buf.putShort((short) (str.length() + 1)); + buf.put(str.getBytes()); buf.put((byte) 0); + } else if (pair.second instanceof byte[]) { + byte[] bytes = (byte[]) pair.second; + buf.put(TYPE_BYTEARRAY); + buf.putShort((short) bytes.length); + buf.put(bytes); } } @@ -1187,6 +1197,9 @@ public class PebbleProtocol extends GBDeviceProtocol { pairs.add(new Pair<>(key, (Object) jsonObject.getInt("value"))); } else if (type.equals("string")) { pairs.add(new Pair<>(key, (Object) jsonObject.getString("value"))); + } else if (type.equals("bytes")) { + byte[] bytes = Base64.decode(jsonObject.getString("value"), Base64.NO_WRAP); + pairs.add(new Pair<>(key, (Object) bytes)); } } catch (JSONException e) { return null; From 95e22a4e327a385f9ae6ff54de2dada07ebf703c Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 13 Sep 2015 21:44:26 +0200 Subject: [PATCH 31/73] Pebble: Allow stopping apps though PebbleKit messages (also in the API) --- .../activities/AppManagerActivity.java | 2 +- .../gadgetbridge/devices/EventHandler.java | 2 +- .../gadgetbridge/impl/GBDeviceService.java | 7 ++++--- .../gadgetbridge/model/DeviceService.java | 1 + .../service/DeviceCommunicationService.java | 9 ++++++--- .../service/ServiceDeviceSupport.java | 4 ++-- .../service/devices/miband/MiBandSupport.java | 2 +- .../service/devices/pebble/PebbleIoThread.java | 3 ++- .../service/devices/pebble/PebbleProtocol.java | 8 +++++--- .../serial/AbstractSerialDeviceSupport.java | 17 +++++++++-------- .../service/serial/GBDeviceProtocol.java | 6 +++--- 11 files changed, 35 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java index 983da45e..62a02ba6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppManagerActivity.java @@ -114,7 +114,7 @@ public class AppManagerActivity extends Activity { @Override public void onItemClick(AdapterView parent, View v, int position, long id) { UUID uuid = appList.get(position).getUUID(); - GBApplication.deviceService().onAppStart(uuid); + GBApplication.deviceService().onAppStart(uuid, true); } }); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java index 2b61352c..32f638ed 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java @@ -34,7 +34,7 @@ public interface EventHandler { void onAppInfoReq(); - void onAppStart(UUID uuid); + void onAppStart(UUID uuid, boolean start); void onAppDelete(UUID uuid); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java index b86bdf8c..3b28a0d4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java @@ -11,8 +11,8 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; +import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; public class GBDeviceService implements DeviceService { @@ -150,9 +150,10 @@ public class GBDeviceService implements DeviceService { } @Override - public void onAppStart(UUID uuid) { + public void onAppStart(UUID uuid, boolean start) { Intent intent = createIntent().setAction(ACTION_STARTAPP) - .putExtra(EXTRA_APP_UUID, uuid); + .putExtra(EXTRA_APP_UUID, uuid) + .putExtra(EXTRA_APP_START, start); invokeService(intent); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java index 02c9d1dd..62fdb4ed 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java @@ -45,6 +45,7 @@ public interface DeviceService extends EventHandler { static final String EXTRA_MUSIC_ALBUM = "music_album"; static final String EXTRA_MUSIC_TRACK = "music_track"; static final String EXTRA_APP_UUID = "app_uuid"; + static final String EXTRA_APP_START = "app_start"; static final String EXTRA_URI = "uri"; static final String EXTRA_ALARMS = "alarms"; static final String EXTRA_PERFORM_PAIR = "perform_pair"; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java index dd1ccbea..27d81e9d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java @@ -26,7 +26,6 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; -import nodomain.freeyourgadget.gadgetbridge.model.DeviceService; import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.util.GB; @@ -51,6 +50,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SE import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_START; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_STARTAPP; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_ALARMS; +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP_START; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP_UUID; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALL_COMMAND; import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_CALL_PHONENUMBER; @@ -183,7 +183,7 @@ public class DeviceCommunicationService extends Service { case ACTION_NOTIFICATION_GENERIC: { String title = intent.getStringExtra(EXTRA_NOTIFICATION_TITLE); String body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY); - int handle = intent.getIntExtra(EXTRA_NOTIFICATION_HANDLE,-1); + int handle = intent.getIntExtra(EXTRA_NOTIFICATION_HANDLE, -1); NotificationKind notificationKind = (NotificationKind) intent.getSerializableExtra(EXTRA_NOTIFICATION_KIND); mDeviceSupport.onGenericNotification(title, body, handle, notificationKind); break; @@ -247,7 +247,8 @@ public class DeviceCommunicationService extends Service { break; case ACTION_STARTAPP: { UUID uuid = (UUID) intent.getSerializableExtra(EXTRA_APP_UUID); - mDeviceSupport.onAppStart(uuid); + boolean start = intent.getBooleanExtra(EXTRA_APP_START, true); + mDeviceSupport.onAppStart(uuid, start); break; } case ACTION_DELETEAPP: { @@ -273,6 +274,7 @@ public class DeviceCommunicationService extends Service { /** * For testing! + * * @param factory */ public void setDeviceSupportFactory(DeviceSupportFactory factory) { @@ -282,6 +284,7 @@ public class DeviceCommunicationService extends Service { /** * Disposes the current DeviceSupport instance (if any) and sets a new device support instance * (if not null). + * * @param deviceSupport */ private void setDeviceSupport(@Nullable DeviceSupport deviceSupport) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index b950eaf1..3a0606e2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -178,11 +178,11 @@ public class ServiceDeviceSupport implements DeviceSupport { } @Override - public void onAppStart(UUID uuid) { + public void onAppStart(UUID uuid, boolean start) { if (checkBusy("app start")) { return; } - delegate.onAppStart(uuid); + delegate.onAppStart(uuid, start); } @Override 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 6d73a1a6..c75586bb 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 @@ -574,7 +574,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } @Override - public void onAppStart(UUID uuid) { + public void onAppStart(UUID uuid, boolean start) { // not supported } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 99f788b0..4f6767cf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -88,9 +88,10 @@ public class PebbleIoThread extends GBDeviceIoThread { UUID uuid; switch (action) { case PEBBLEKIT_ACTION_APP_START: + case PEBBLEKIT_ACTION_APP_STOP: uuid = (UUID) intent.getSerializableExtra("uuid"); if (uuid != null) { - write(mPebbleProtocol.encodeAppStart(uuid)); + write(mPebbleProtocol.encodeAppStart(uuid, action == PEBBLEKIT_ACTION_APP_START)); } break; case PEBBLEKIT_ACTION_APP_SEND: diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index f0ed9a12..59be0600 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -67,6 +67,7 @@ public class PebbleProtocol extends GBDeviceProtocol { static final short ENDPOINT_PUTBYTES = (short) 48879; static final byte APPRUNSTATE_START = 1; + static final byte APPRUNSTATE_STOP = 2; static final byte BLOBDB_INSERT = 1; static final byte BLOBDB_DELETE = 4; @@ -877,19 +878,20 @@ public class PebbleProtocol extends GBDeviceProtocol { } @Override - public byte[] encodeAppStart(UUID uuid) { + public byte[] encodeAppStart(UUID uuid, boolean start) { if (isFw3x) { ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_APPRUNSTATE); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(LENGTH_APPRUNSTATE); buf.putShort(ENDPOINT_APPRUNSTATE); - buf.put(APPRUNSTATE_START); + buf.put(start ? APPRUNSTATE_START : APPRUNSTATE_STOP); buf.putLong(uuid.getMostSignificantBits()); buf.putLong(uuid.getLeastSignificantBits()); return buf.array(); } else { ArrayList> pairs = new ArrayList<>(); - pairs.add(new Pair<>(1, (Object) 1)); // launch + int param = start ? 1 : 0; + pairs.add(new Pair<>(1, (Object) param)); return encodeApplicationMessagePush(ENDPOINT_LAUNCHER, uuid, pairs); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index fbceaa39..2249f462 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -5,23 +5,23 @@ import org.slf4j.LoggerFactory; import java.util.UUID; -import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; +import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; +import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; /** * An abstract base class for devices speaking a serial protocol, like via * an rfcomm bluetooth socket or a TCP socket. - * + *

* This class uses two helper classes to deal with that: * - GBDeviceIoThread, which creates and maintains the actual socket connection and implements the transport layer * - GBDeviceProtocol, which implements the encoding and decoding of messages, i.e. the actual device specific protocol - * + *

* Note that these two classes need to be implemented in a device specific way. - * + *

* This implementation implements all methods of {@link EventHandler}, calls the {@link GBDeviceProtocol device protocol} * to create the device specific message for the respective events and sends them to the device via {@link #sendToDevice(byte[])}. */ @@ -85,6 +85,7 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport /** * Sends the given message to the device. This implementation delegates the * writing to the {@link #getDeviceIOThread device io thread} + * * @param bytes the message to send to the device */ protected void sendToDevice(byte[] bytes) { @@ -149,8 +150,8 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport } @Override - public void onAppStart(UUID uuid) { - byte[] bytes = gbDeviceProtocol.encodeAppStart(uuid); + public void onAppStart(UUID uuid, boolean start) { + byte[] bytes = gbDeviceProtocol.encodeAppStart(uuid, start); sendToDevice(bytes); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 69e195de..971e02d6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -2,9 +2,9 @@ package nodomain.freeyourgadget.gadgetbridge.service.serial; import java.util.UUID; -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; +import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; public abstract class GBDeviceProtocol { @@ -48,7 +48,7 @@ public abstract class GBDeviceProtocol { return null; } - public byte[] encodeAppStart(UUID uuid) { + public byte[] encodeAppStart(UUID uuid, boolean start) { return null; } From 21d59b23c10ff54924d7dcf368f0407cf9617362 Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Sun, 13 Sep 2015 22:47:56 +0200 Subject: [PATCH 32/73] Allow QKSMS notifications to be handled as a generic notification if SMS notification mode is set to "never" This makes it possible to use the "Open on Phone" and individial dismiss feature with QKSMS. --- .../externalevents/NotificationListener.java | 10 +++++++++- .../gadgetbridge/model/NotificationKind.java | 1 + .../service/devices/pebble/PebbleProtocol.java | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index e7c64cf2..ed56551f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -132,7 +132,6 @@ public class NotificationListener extends NotificationListenerService { source.equals("com.android.systemui") || source.equals("com.android.dialer") || source.equals("com.android.mms") || - source.equals("com.moez.QKSMS") || source.equals("com.cyanogenmod.eleven")) { return; } @@ -149,6 +148,12 @@ public class NotificationListener extends NotificationListenerService { } } + if (source.equals("com.moez.QKSMS")) { + if (!"never".equals(sharedPrefs.getString("notification_mode_sms", "when_screen_off"))) { + return; + } + } + HashSet blacklist = (HashSet) sharedPrefs.getStringSet("package_blacklist", null); if (blacklist != null && blacklist.contains(source)) { return; @@ -167,6 +172,9 @@ public class NotificationListener extends NotificationListenerService { case "com.android.email": notificationKind = NotificationKind.EMAIL; break; + case "com.moez.QKSMS": + notificationKind = NotificationKind.SMS; + break; case "eu.siacs.conversations": notificationKind = NotificationKind.CHAT; break; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java index deda5007..3005a3a6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java @@ -7,5 +7,6 @@ public enum NotificationKind { CHAT, EMAIL, FACEBOOK, + SMS, TWITTER, } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 59be0600..4d7c7813 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -635,6 +635,10 @@ public class PebbleProtocol extends GBDeviceProtocol { icon_id = PebbleIconID.GENERIC_EMAIL; color_id = PebbleColor.JaegerGreen; break; + case SMS: + icon_id = PebbleIconID.GENERIC_SMS; + color_id = PebbleColor.VividViolet; + break; case FACEBOOK: icon_id = PebbleIconID.NOTIFICATION_FACEBOOK; color_id = PebbleColor.VeryLightBlue; From de74a033f625ad75bc01e9cccebfd47add097a53 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Tue, 15 Sep 2015 01:36:33 +0200 Subject: [PATCH 33/73] Try to support controlling multiple music players This tries to control the last player that played a (new) song. It is very limited since we cannot get the source of an intent. Instead we try to guess from the Action. The problem is that we cannot support players that use only the action "com.android.music.XXXX" and not something own. Also try to blindly support getting spotify metadata (for testing #112) --- app/src/main/AndroidManifest.xml | 1 + .../externalevents/MusicPlaybackReceiver.java | 17 +++++++++++++++++ .../receivers/GBMusicControlReceiver.java | 11 +++++++++++ 3 files changed, 29 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 9dfd1d54..3c587002 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -230,6 +230,7 @@ + Date: Tue, 15 Sep 2015 11:59:42 +0200 Subject: [PATCH 34/73] correct some french translate --- app/src/main/res/values-fr/strings.xml | 50 +++++++++++++------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index f9fee5a8..d49071e4 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -17,7 +17,7 @@ Vous êtes sur le point d\'installer le firmware %s à la place de celui qui est actuellement sur votre Mi Band. Ce firmware a été testé et est connu pour être compatible avec Gadgetbridge. - Ce firmware n\'a pas été testé et peut ne pas être compatible avec Gadgetbridge. \ N \ nIl n\'est pas conseillé de flasher votre Mi Band. + Ce firmware n\'a pas été testé et peut ne pas être compatible avec Gadgetbridge. \n \n Il n\'est pas conseillé de flasher votre Mi Band. Paramètre Paramètres généraux @@ -33,21 +33,21 @@ Message Pebble Support pour les applications qui envoient des notifications au Pebble via Intent. Peut être utilisé pour les conversations. Support des notififactions génériques - même lorsque l\'écran est allumé - toujours - quand l\'écran est éteint - jamais + Même lorsque l\'écran est allumé + Toujours + Quand l\'écran est éteint + Jamais Options développeur Adresse Mi Band Paramètres Pebble Protocole des notifications en vigueur - Cette option force l\'utilisant du dernier protocole de notification qui dépend de la verrsion du firmware. ACTIVER LA UNIQUEMENT SI VOUS SAVEZ CE QUE VOUS FAITES! - Activités les fonctionnalités non testé - Activer les fonctionnalités non testés - non connecté - en train de se connecter - connecté - état inconnu + Cette option force l\'utilisation du dernier protocole de notification qui dépend de la verrsion du firmware. ACTIVER LA UNIQUEMENT SI VOUS SAVEZ CE QUE VOUS FAITES! + Activer les fonctionnalités non testé + Activer les fonctionnalités non testés. ACTIVER UNIQUEMENT SI VOUS SAVEZ CE QE VOUS FAITES! + Non connecté + En train de se connecter + Connecté + État inconnu HW: %1$s FW: %2$s FW: %1$s (inconnu) @@ -56,17 +56,17 @@ Ceci est un test de notification venant de Gadgetbridge Le bluetooth n\'est pas supporté Le bluetooth est désactivé - Taper sur lpour le connecter au gestionnaire d\'application + Taper sur l\'appareil pour le connecter au gestionnaire d\'application Tapper sur l\'appareil pour le connecter Ne peut être connecter. L’adresse bluetooth est invalide? Gadgetbridge est en fonctionnement Installation du binaire %1$d/%2$d - installation en échec - installation réalisé + Echec d'installation + Installation réalisé VOUS ÊTES EN TRAIN D\'INSTALLER UN FIRMWARE, PROCEDEZ À VOS PROPRES RISQUES. CE FIRMWARE EST POUR LA VERSION HW: %s Vous êtes sur le point d\'installer l\'application suivante:\n\n\n%1$s Version %2$s par %3$s\n N/A - initialisé + Initialisé %1$s par %2$s Décourir les appareils Arreter de scanner @@ -80,11 +80,11 @@ Aucune adresse mac fournis, ne peut être couplé Paramètres spécifique à l\'appareil Paramètres Mi Band - homme - femme - autre - gauche - droite + Homme + Femme + Autre + Gauche + Droite Aucune donnée utilisateur valide fournis, utilisation des données fictives pour le moment Quand votre Mi Band vibre et clignote, appuyez dessus plusieurs fois d\'affilée. Installer @@ -100,7 +100,7 @@ Nombre de vibration Moniteur de sommeil Ecrire le fichier de logs (besoin de redemarrer) - iniitialisation + Initialisation Récupération des données d\'activité De %1$s à %2$s Port main gauche ou droite? @@ -132,11 +132,11 @@ Jeu Ven Sam - réveil intelligent + Réveil intelligent Il y avais une erreur lors du paramétrage des alarmes, s\'il vous plaît essayer à nouveau! Alarmes envoyer à l\'appareil Aucune donnée. Synchroniser l\'appareil? - A propos du transférer %1$s de données à partir de %2$s + À propos du transférer %1$s de données à partir de %2$s Objectif de pas par jour Erreur d’exécution %1$s\' Votre activité (ALPHA) @@ -161,7 +161,7 @@ Révision correcte du matériel Version Hardware incorrecte! %1$s (%2$s) - Problème avec le transfert du firmware. Ne redémarrez pas votre bande Mi! + Problème avec le transfert du firmware. Ne redémarrez pas votre Mi band! Problème avec le transfert de métadonnées du firmware Installation complète du firmware Installation complète du firmware, redémarrage de l\'appareil From 6e3c8396083d79355b9f31111fb5c0f49c57b714 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 16 Sep 2015 00:53:54 +0200 Subject: [PATCH 35/73] Allow to select preferred music player in preferences, closes #112 --- app/src/main/AndroidManifest.xml | 4 +-- .../activities/SettingsActivity.java | 34 ++++++++++++++++++- .../externalevents/MusicPlaybackReceiver.java | 13 ------- .../receivers/GBMusicControlReceiver.java | 10 +++--- app/src/main/res/values/strings.xml | 3 +- app/src/main/res/xml/preferences.xml | 18 ++++++---- 6 files changed, 52 insertions(+), 30 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3c587002..730ca7e7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -228,9 +228,7 @@ android:name=".externalevents.MusicPlaybackReceiver" android:enabled="false"> - - - + mediaReceivers = pm.queryBroadcastReceivers(mediaButtonIntent, + PackageManager.GET_INTENT_FILTERS | PackageManager.GET_RESOLVED_FILTER); + + + CharSequence[] newEntries = new CharSequence[mediaReceivers.size() + 1]; + CharSequence[] newValues = new CharSequence[mediaReceivers.size() + 1]; + newEntries[0] = getString(R.string.pref_default); + newValues[0] = "default"; + + int i = 1; + for (ResolveInfo resolveInfo : mediaReceivers) { + newEntries[i] = resolveInfo.activityInfo.loadLabel(pm); + newValues[i] = resolveInfo.activityInfo.packageName; + i++; + } + + final ListPreference audioPlayer = (ListPreference) findPreference("audio_player"); + audioPlayer.setEntries(newEntries); + audioPlayer.setEntryValues(newValues); } @Override protected String[] getPreferenceKeysWithSummary() { return new String[]{ + "audio_player", + "notification_mode_sms", + "notification_mode_k9mail", "pebble_emu_addr", - "pebble_emu_port" + "pebble_emu_port", }; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java index 2952f7ef..bb9f0839 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java @@ -18,19 +18,6 @@ public class MusicPlaybackReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - int lastDot = action.lastIndexOf("."); - String source = action.substring(0, lastDot); - - if (!source.equals(mLastSource)) { - mLastSource = source; - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - SharedPreferences.Editor edit = sharedPrefs.edit(); - edit.putString("last_audiosource", mLastSource); - LOG.info("set last audiosource to " + mLastSource); - edit.apply(); - } - String artist = intent.getStringExtra("artist"); String album = intent.getStringExtra("album"); String track = intent.getStringExtra("track"); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBMusicControlReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBMusicControlReceiver.java index 3b721344..8a521679 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBMusicControlReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/receivers/GBMusicControlReceiver.java @@ -54,23 +54,23 @@ public class GBMusicControlReceiver extends BroadcastReceiver { if (keyCode != -1) { SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); - String audioSource = sharedPrefs.getString("last_audiosource", null); + String audioPlayer = sharedPrefs.getString("audio_player", "default"); long eventtime = SystemClock.uptimeMillis(); Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); KeyEvent downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, keyCode, 0); downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent); - if (audioSource != null) { - downIntent.setPackage(audioSource); + if (!"default".equals(audioPlayer)) { + downIntent.setPackage(audioPlayer); } context.sendOrderedBroadcast(downIntent, null); Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); KeyEvent upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, keyCode, 0); upIntent.putExtra(Intent.EXTRA_KEY_EVENT, upEvent); - if (audioSource != null) { - upIntent.setPackage(audioSource); + if (audioPlayer != null) { + upIntent.setPackage(audioPlayer); } context.sendOrderedBroadcast(upIntent, null); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b175c584..4df4ecf9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,7 +33,8 @@ General Settings Connect to device when Bluetooth turned on - + Preferred audio player + default Date and Time Sync time Sync time to device when connecting and when time or timezone changes on Android diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 41a36bed..04ca6649 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -7,6 +7,10 @@ android:defaultValue="false" android:key="general_autoconnectonbluetooth" android:title="@string/pref_title_general_autoconnectonbluetooth" /> + + android:key="pref_key_pebble" + android:title="@string/pref_title_pebble_settings"> + android:summary="@string/pref_summary_pebble_forceprotocol" + android:title="@string/pref_title_pebble_forceprotocol" /> + android:summary="@string/pref_summary_pebble_forceuntested" + android:title="@string/pref_title_pebble_forceuntested" /> Date: Wed, 16 Sep 2015 01:09:03 +0200 Subject: [PATCH 36/73] Handle SMS/MMS as generic notification if disabled (could serve as a workaround for #127) --- .../gadgetbridge/externalevents/NotificationListener.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index ed56551f..68214d6f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -22,8 +22,8 @@ import org.slf4j.LoggerFactory; import java.util.HashSet; import nodomain.freeyourgadget.gadgetbridge.GBApplication; -import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; +import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService; public class NotificationListener extends NotificationListenerService { @@ -131,7 +131,6 @@ public class NotificationListener extends NotificationListenerService { if (source.equals("android") || source.equals("com.android.systemui") || source.equals("com.android.dialer") || - source.equals("com.android.mms") || source.equals("com.cyanogenmod.eleven")) { return; } @@ -148,7 +147,7 @@ public class NotificationListener extends NotificationListenerService { } } - if (source.equals("com.moez.QKSMS")) { + if (source.equals("com.moez.QKSMS") || source.equals("com.android.mms")) { if (!"never".equals(sharedPrefs.getString("notification_mode_sms", "when_screen_off"))) { return; } From 7dedff3ce17e161ff67e63e9842a128b756f4325 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Wed, 16 Sep 2015 20:05:52 +0200 Subject: [PATCH 37/73] Add missing \ before apostrophe --- app/src/main/res/values-fr/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index d49071e4..fc5c236b 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -61,7 +61,7 @@ Ne peut être connecter. L’adresse bluetooth est invalide? Gadgetbridge est en fonctionnement Installation du binaire %1$d/%2$d - Echec d'installation + Echec d\'installation Installation réalisé VOUS ÊTES EN TRAIN D\'INSTALLER UN FIRMWARE, PROCEDEZ À VOS PROPRES RISQUES. CE FIRMWARE EST POUR LA VERSION HW: %s Vous êtes sur le point d\'installer l\'application suivante:\n\n\n%1$s Version %2$s par %3$s\n From 58bbcb003558cef00759b4cf0fc592980f7ad2ec Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 17 Sep 2015 15:30:33 +0200 Subject: [PATCH 38/73] Pebble: allow to configure reconnect attempts This should help #89 --- .../gadgetbridge/activities/SettingsActivity.java | 2 ++ .../service/devices/pebble/PebbleIoThread.java | 12 +++++------- app/src/main/res/values/strings.xml | 4 ++-- app/src/main/res/xml/preferences.xml | 6 ++++++ 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index f726ad1a..cf9f3102 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -97,6 +97,7 @@ public class SettingsActivity extends AbstractSettingsActivity { final ListPreference audioPlayer = (ListPreference) findPreference("audio_player"); audioPlayer.setEntries(newEntries); audioPlayer.setEntryValues(newValues); + audioPlayer.setDefaultValue(newValues[0]); } @Override @@ -107,6 +108,7 @@ public class SettingsActivity extends AbstractSettingsActivity { "notification_mode_k9mail", "pebble_emu_addr", "pebble_emu_port", + "pebble_reconnect_attempts", }; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 4f6767cf..b649621c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -56,6 +56,8 @@ public class PebbleIoThread extends GBDeviceIoThread { public static final String PEBBLEKIT_ACTION_APP_START = "com.getpebble.action.app.START"; public static final String PEBBLEKIT_ACTION_APP_STOP = "com.getpebble.action.app.STOP"; + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + private final PebbleProtocol mPebbleProtocol; private final PebbleSupport mPebbleSupport; private boolean mIsTCP = false; @@ -67,7 +69,6 @@ public class PebbleIoThread extends GBDeviceIoThread { private boolean mQuit = false; private boolean mIsConnected = false; private boolean mIsInstalling = false; - private int mConnectionAttempts = 0; private PBWReader mPBWReader = null; private int mAppInstallToken = -1; @@ -148,7 +149,6 @@ public class PebbleIoThread extends GBDeviceIoThread { return false; } - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); mPebbleProtocol.setForceProtocol(sharedPrefs.getBoolean("pebble_force_protocol", false)); gbDevice.setState(GBDevice.State.CONNECTED); gbDevice.sendDeviceUpdateIntent(getContext()); @@ -311,13 +311,13 @@ public class PebbleIoThread extends GBDeviceIoThread { gbDevice.setState(GBDevice.State.CONNECTING); gbDevice.sendDeviceUpdateIntent(getContext()); - while (mConnectionAttempts++ < 10 && !mQuit) { - LOG.info("Trying to reconnect (attempt " + mConnectionAttempts + ")"); + int reconnectAttempts = Integer.valueOf(sharedPrefs.getString("pebble_reconnect_attempts", "10")); + while (reconnectAttempts-- > 0 && !mQuit) { + LOG.info("Trying to reconnect (attempts left " + reconnectAttempts + ")"); mIsConnected = connect(gbDevice.getAddress()); if (mIsConnected) break; } - mConnectionAttempts = 0; if (!mIsConnected) { mBtSocket = null; LOG.info("Bluetooth socket closed, will quit IO Thread"); @@ -341,7 +341,6 @@ public class PebbleIoThread extends GBDeviceIoThread { } private void enablePebbleKitReceiver(boolean enable) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); boolean force_untested = sharedPrefs.getBoolean("pebble_force_untested", false); if (enable && force_untested) { @@ -403,7 +402,6 @@ public class PebbleIoThread extends GBDeviceIoThread { private boolean evaluateGBDeviceEventPebble(GBDeviceEvent deviceEvent) { if (deviceEvent instanceof GBDeviceEventVersionInfo) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); if (sharedPrefs.getBoolean("datetime_synconconnect", true)) { LOG.info("syncing time"); write(mPebbleProtocol.encodeSetTime()); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4df4ecf9..9fe36c74 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -34,7 +34,7 @@ General Settings Connect to device when Bluetooth turned on Preferred audio player - default + Default Date and Time Sync time Sync time to device when connecting and when time or timezone changes on Android @@ -63,7 +63,7 @@ This option forces using the latest notification protocol depending on the firmware version. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING! Enable untested features Enable features that are untested. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING! - + Reconnect attempts not connected connecting connected diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 04ca6649..4f10aaf0 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -84,6 +84,12 @@ android:key="pebble_force_untested" android:summary="@string/pref_summary_pebble_forceuntested" android:title="@string/pref_title_pebble_forceuntested" /> + Date: Thu, 17 Sep 2015 15:35:25 +0200 Subject: [PATCH 39/73] try to fix tests --- .../freeyourgadget/gadgetbridge/service/TestDeviceSupport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index f49edda4..0f9ecdd3 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -94,7 +94,7 @@ public class TestDeviceSupport extends AbstractDeviceSupport { } @Override - public void onAppStart(UUID uuid) { + public void onAppStart(UUID uuid, boolean start) { } From b73ff49681f278d441b7f0fd7ccc2d44ab94636e Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 17 Sep 2015 15:39:44 +0200 Subject: [PATCH 40/73] Use data type constant instead of hardcoded value --- .../gadgetbridge/devices/miband/MiBandService.java | 11 ++++++----- .../miband/operations/FetchActivityOperation.java | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandService.java index 3d34b439..e436a290 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandService.java @@ -178,13 +178,14 @@ public class MiBandService { */ - /* MODES: unknown - - public static final MODE_REGULAR_DATA_LEN_BYTE = 0x0t; - - public static final MODE_REGULAR_DATA_LEN_MINITE = 0x1t + /* MODES: probably related to the sample data structure */ + public static final byte MODE_REGULAR_DATA_LEN_BYTE = 0x0; + + // was MODE_REGULAR_DATA_LEN_MINITE + public static final byte MODE_REGULAR_DATA_LEN_MINUTE = 0x1; + /* PROFILE: unknown public static final PROFILE_STATE_UNKNOWN:I = 0x0 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 8f57d02e..90ac55c2 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 @@ -111,14 +111,14 @@ public class FetchActivityOperation extends AbstractBTLEOperation // counter of all data held by the band int totalDataToRead = (value[7] & 0xff) | ((value[8] & 0xff) << 8); - totalDataToRead *= (dataType == 1) ? 3 : 1; + totalDataToRead *= (dataType == MiBandService.MODE_REGULAR_DATA_LEN_MINUTE) ? 3 : 1; // counter of this data block int dataUntilNextHeader = (value[9] & 0xff) | ((value[10] & 0xff) << 8); - dataUntilNextHeader *= (dataType == 1) ? 3 : 1; + dataUntilNextHeader *= (dataType == MiBandService.MODE_REGULAR_DATA_LEN_MINUTE) ? 3 : 1; - // there is a total of totalDataToRead that will come in chunks (3 bytes per minute if dataType == 1), + // there is a total of totalDataToRead that will come in chunks (3 bytes per minute if dataType == 1 (MiBandService.MODE_REGULAR_DATA_LEN_MINUTE)), // these chunks are usually 20 bytes long and grouped in blocks // after dataUntilNextHeader bytes we will get a new packet of 11 bytes that should be parsed // as we just did From 55341678b3f3ac315cab391ac310eb24aeabc1d4 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 17 Sep 2015 16:03:15 +0200 Subject: [PATCH 41/73] Add firmwares from the wiki. --- .../gadgetbridge/devices/miband/MiBandFWHelper.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java index 2f96c714..d9144536 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java @@ -32,6 +32,10 @@ public class MiBandFWHelper { 16779547, //1.0.9.27 tested by developer 16779568, //1.0.9.48 tested by developer 16779585, //1.0.9.65 tested by developer + 16779779, //1.0.10.3 reported on the wiki + 16779782, //1.0.10.6 reported on the wikiew + 16779787, //1.0.10.11 tested by developer + 16779790, //1.0.10.14 reported on the wiki }; public MiBandFWHelper(Uri uri, Context context) throws IOException { From 502c005a0ee83cded215e0654ec4f27734e2f7d4 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 17 Sep 2015 16:17:39 +0200 Subject: [PATCH 42/73] Add a further intent filter to grab the firmware/apps from the download content provider. Tested to work with miband firmware on android 5. --- app/src/main/AndroidManifest.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 730ca7e7..d5b8053c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -171,6 +171,14 @@ + + + + + + + + Date: Thu, 17 Sep 2015 19:21:22 +0200 Subject: [PATCH 43/73] Pebble: Implement WIP outbound communication with PebbleKit Android Apps This improves #106 Pebblebike aka Ventoo works to some extent sometimes now ;) --- .../deviceevents/GBDeviceEventAppMessage.java | 9 ++ .../devices/pebble/PebbleIoThread.java | 49 +++++++++-- .../devices/pebble/PebbleProtocol.java | 86 +++++++++++++++++-- 3 files changed, 132 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventAppMessage.java diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventAppMessage.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventAppMessage.java new file mode 100644 index 00000000..79ee6b81 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventAppMessage.java @@ -0,0 +1,9 @@ +package nodomain.freeyourgadget.gadgetbridge.deviceevents; + +import java.util.UUID; + +public class GBDeviceEventAppMessage extends GBDeviceEvent { + public UUID appUUID; + public int id; + public String message; +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index b649621c..9e7cd854 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -32,6 +32,7 @@ import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppMessage; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PBWReader; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleInstallable; @@ -92,10 +93,11 @@ public class PebbleIoThread extends GBDeviceIoThread { case PEBBLEKIT_ACTION_APP_STOP: uuid = (UUID) intent.getSerializableExtra("uuid"); if (uuid != null) { - write(mPebbleProtocol.encodeAppStart(uuid, action == PEBBLEKIT_ACTION_APP_START)); + write(mPebbleProtocol.encodeAppStart(uuid, action.equals(PEBBLEKIT_ACTION_APP_START))); } break; case PEBBLEKIT_ACTION_APP_SEND: + int transaction_id = intent.getIntExtra("transaction_id", -1); uuid = (UUID) intent.getSerializableExtra("uuid"); String jsonString = intent.getStringExtra("msg_data"); LOG.info("json string: " + jsonString); @@ -103,14 +105,48 @@ public class PebbleIoThread extends GBDeviceIoThread { try { JSONArray jsonArray = new JSONArray(jsonString); write(mPebbleProtocol.encodeApplicationMessageFromJSON(uuid, jsonArray)); + sendAppMessageAck(transaction_id); + } catch (JSONException e) { e.printStackTrace(); } break; + case PEBBLEKIT_ACTION_APP_ACK: + // we do not get a uuid and cannot map a transaction id to it, so we ack in PebbleProtocol early + /* + uuid = (UUID) intent.getSerializableExtra("uuid"); + int transaction_id = intent.getIntExtra("transaction_id", -1); + if (transaction_id >= 0 && transaction_id <= 255) { + write(mPebbleProtocol.encodeApplicationMessageAck(uuid, (byte) transaction_id)); + } else { + LOG.warn("illegal transacktion id " + transaction_id); + } + */ + break; } } }; + private void sendAppMessageIntent(GBDeviceEventAppMessage appMessage) { + Intent intent = new Intent(); + intent.setAction(PEBBLEKIT_ACTION_APP_RECEIVE); + intent.putExtra("uuid", appMessage.appUUID); + intent.putExtra("msg_data", appMessage.message); + intent.putExtra("transaction_id", appMessage.id); + LOG.info("broadcasting to uuid " + appMessage.appUUID + " transaction id: " + appMessage.id + " JSON: " + appMessage.message); + getContext().sendBroadcast(intent); + } + + private void sendAppMessageAck(int transactionId) { + if (transactionId > 0 && transactionId <= 255) { + Intent intent = new Intent(); + intent.setAction(PEBBLEKIT_ACTION_APP_RECEIVE_ACK); + intent.putExtra("transaction_id", transactionId); + LOG.info("broadcasting ACK (transaction id " + transactionId + ")"); + getContext().sendBroadcast(intent); + } + } + public PebbleIoThread(PebbleSupport pebbleSupport, GBDevice gbDevice, GBDeviceProtocol gbDeviceProtocol, BluetoothAdapter btAdapter, Context context) { super(gbDevice, context); mPebbleProtocol = (PebbleProtocol) gbDeviceProtocol; @@ -347,14 +383,9 @@ public class PebbleIoThread extends GBDeviceIoThread { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(PEBBLEKIT_ACTION_APP_ACK); intentFilter.addAction(PEBBLEKIT_ACTION_APP_NACK); - intentFilter.addAction(PEBBLEKIT_ACTION_APP_RECEIVE); - intentFilter.addAction(PEBBLEKIT_ACTION_APP_RECEIVE_ACK); - intentFilter.addAction(PEBBLEKIT_ACTION_APP_RECEIVE_NACK); intentFilter.addAction(PEBBLEKIT_ACTION_APP_SEND); intentFilter.addAction(PEBBLEKIT_ACTION_APP_START); intentFilter.addAction(PEBBLEKIT_ACTION_APP_STOP); - intentFilter.addAction(PEBBLEKIT_ACTION_PEBBLE_CONNECTED); - intentFilter.addAction(PEBBLEKIT_ACTION_PEBBLE_DISCONNECTED); try { getContext().registerReceiver(mPebbleKitReceiver, intentFilter); } catch (IllegalArgumentException e) { @@ -475,7 +506,13 @@ public class PebbleIoThread extends GBDeviceIoThread { GBDeviceEventAppInfo appInfoEvent = (GBDeviceEventAppInfo) deviceEvent; setInstallSlot(appInfoEvent.freeSlot); return false; + } else if (deviceEvent instanceof GBDeviceEventAppMessage) { + if (sharedPrefs.getBoolean("pebble_force_untested", false)) { + LOG.info("Got AppMessage event"); + sendAppMessageIntent((GBDeviceEventAppMessage) deviceEvent); + } } + return false; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 4d7c7813..10a040bc 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -20,6 +20,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppInfo; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppManagement; +import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventAppMessage; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventCallControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl; @@ -189,8 +190,8 @@ public class PebbleProtocol extends GBDeviceProtocol { static final byte TYPE_BYTEARRAY = 0; static final byte TYPE_CSTRING = 1; - static final byte TYPE_UINT32 = 2; - static final byte TYPE_INT32 = 3; + static final byte TYPE_UINT = 2; + static final byte TYPE_INT = 3; static final short LENGTH_PREFIX = 4; static final short LENGTH_SIMPLEMESSAGE = 1; @@ -1123,10 +1124,10 @@ public class PebbleProtocol extends GBDeviceProtocol { while (dictSize-- > 0) { Integer key = buf.getInt(); byte type = buf.get(); - short length = buf.getShort(); // length + short length = buf.getShort(); switch (type) { - case TYPE_INT32: - case TYPE_UINT32: + case TYPE_INT: + case TYPE_UINT: dict.add(new Pair(key, buf.getInt())); break; case TYPE_CSTRING: @@ -1145,6 +1146,72 @@ public class PebbleProtocol extends GBDeviceProtocol { return dict; } + private GBDeviceEvent[] decodeDictToJSONAppMessage(UUID uuid, ByteBuffer buf) throws JSONException { + buf.order(ByteOrder.LITTLE_ENDIAN); + byte dictSize = buf.get(); + if (dictSize == 0) { + LOG.info("dict size is 0, ignoring"); + return null; + } + JSONArray jsonArray = new JSONArray(); + while (dictSize-- > 0) { + JSONObject jsonObject = new JSONObject(); + Integer key = buf.getInt(); + byte type = buf.get(); + short length = buf.getShort(); + jsonObject.put("key", key); + jsonObject.put("length", length); + switch (type) { + case TYPE_UINT: + jsonObject.put("type", "uint"); + if (length == 1) { + jsonObject.put("value", buf.get() & 0xff); + } else if (length == 2) { + jsonObject.put("value", buf.getShort() & 0xffff); + } else { + jsonObject.put("value", buf.getInt() & 0xffffffffL); + } + break; + case TYPE_INT: + jsonObject.put("type", "int"); + if (length == 1) { + jsonObject.put("value", buf.get()); + } else if (length == 2) { + jsonObject.put("value", buf.getShort()); + } else { + jsonObject.put("value", buf.getInt()); + } + break; + case TYPE_BYTEARRAY: + case TYPE_CSTRING: + byte[] bytes = new byte[length]; + buf.get(bytes); + if (type == TYPE_BYTEARRAY) { + jsonObject.put("type", "bytes"); + jsonObject.put("value", Base64.encode(bytes, Base64.NO_WRAP)); + } else { + jsonObject.put("type", "string"); + jsonObject.put("value", Arrays.toString(bytes)); + } + break; + default: + LOG.info("unknown type in appmessage, ignoring"); + return null; + } + jsonArray.put(jsonObject); + } + + // this is a hack we send an ack to the Pebble immediately because we cannot map the transaction_id from the intent back to a uuid yet + GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = encodeApplicationMessageAck(uuid, last_id); + + GBDeviceEventAppMessage appMessage = new GBDeviceEventAppMessage(); + appMessage.appUUID = uuid; + appMessage.id = last_id & 0xff; + appMessage.message = jsonArray.toString(); + return new GBDeviceEvent[]{appMessage, sendBytesAck}; + } + byte[] encodeApplicationMessagePush(short endpoint, UUID uuid, ArrayList> pairs) { int length = LENGTH_UUID + 3; // UUID + (PUSH + id + length of dict) for (Pair pair : pairs) { @@ -1172,7 +1239,7 @@ public class PebbleProtocol extends GBDeviceProtocol { for (Pair pair : pairs) { buf.putInt(pair.first); if (pair.second instanceof Integer) { - buf.put(TYPE_INT32); + buf.put(TYPE_INT); buf.putShort((short) 4); // length of int buf.putInt((int) pair.second); } else if (pair.second instanceof String) { @@ -1599,6 +1666,13 @@ public class PebbleProtocol extends GBDeviceProtocol { } else if (GadgetbridgePblSupport.uuid.equals(uuid)) { ArrayList> dict = decodeDict(buf); devEvts = mGadgetbridgePblSupport.handleMessage(dict); + } else { + try { + devEvts = decodeDictToJSONAppMessage(uuid, buf); + } catch (JSONException e) { + e.printStackTrace(); + return null; + } } break; case APPLICATIONMESSAGE_ACK: From 041bd1a7f4e7ea05cc03dd4d8e6588f5d083c9b9 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 17 Sep 2015 23:08:05 +0200 Subject: [PATCH 44/73] Treat Conversations messagess as chat messages, even if arrived via Pebble Intents (which is the default) --- .../gadgetbridge/externalevents/PebbleReceiver.java | 9 ++++++++- .../service/devices/pebble/PebbleProtocol.java | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java index 4fa3bcba..ab408429 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java @@ -13,6 +13,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import nodomain.freeyourgadget.gadgetbridge.GBApplication; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; public class PebbleReceiver extends BroadcastReceiver { @@ -46,6 +47,7 @@ public class PebbleReceiver extends BroadcastReceiver { return; } + String notificationData = intent.getStringExtra("notificationData"); try { JSONArray notificationJSON = new JSONArray(notificationData); @@ -57,7 +59,12 @@ public class PebbleReceiver extends BroadcastReceiver { } if (title != null && body != null) { - GBApplication.deviceService().onSMS(title, body); + NotificationKind notificationKind = NotificationKind.UNDEFINED; + String sender = intent.getStringExtra("sender"); + if ("Conversations".equals(sender)) { + notificationKind = NotificationKind.CHAT; + } + GBApplication.deviceService().onGenericNotification(title, body, -1, notificationKind); } } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 10a040bc..61d7e838 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -383,11 +383,11 @@ public class PebbleProtocol extends GBDeviceProtocol { if (isFw3x) { // 3.x notification - //return encodeTimelinePin(id, (int) (ts + 600 & 0xffffffff), (short) 90, ICON_TIMELINE_CALENDAR, title); // really, this is just for testing - return encodeBlobdbNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle, notificationKind); + //return encodeTimelinePin(id, (int) ((ts + 600) & 0xffffffffL), (short) 90, PebbleIconID.TIMELINE_CALENDAR, title); // really, this is just for testing + return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, body, type, hasHandle, notificationKind); } else if (mForceProtocol || type != NOTIFICATION_EMAIL) { // 2.x notification - return encodeExtensibleNotification(id, (int) (ts & 0xffffffff), title, subtitle, body, type, hasHandle); + return encodeExtensibleNotification(id, (int) (ts & 0xffffffffL), title, subtitle, body, type, hasHandle); } else { // 1.x notification on FW 2.X String[] parts = {title, body, ts.toString(), subtitle}; @@ -408,7 +408,7 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { - return encodeNotification(handle, title, null, details, NOTIFICATION_UNDEFINED, true, notificationKind); + return encodeNotification(handle, title, null, details, NOTIFICATION_UNDEFINED, handle != -1, notificationKind); } @Override From b02c286818e48d1ad5259cbb829377770a3c7498 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 17 Sep 2015 23:22:15 +0200 Subject: [PATCH 45/73] update CHANGELOG and README --- CHANGELOG.md | 7 +++++++ README.md | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ff345e45..def65522 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ ###Changelog +####Next Version +* Pebble: WIP implementantion of PebbleKit Intents to make some 3rd party Android apps work with the Pebble (eg. Ventoo) +* Pebble: Option to set reconnect attempts in settings (one attempt ususally takes about 5 seconds) +* Support contolling all audio players that react to media buttons (can be chosen in settings) +* Treat SMS as generic notification if set to "never" (can be blacklisted there also if desired) +* Treat Conversations messagess as chat messages, even if arrived via Pebble Intents (nice icon for Pebble FW 3.x) + ####Version 0.5.4 * Miband: allow the transfer of activity data without clearing MiBand's memory * Pebble: for generic notifications use generic icon instead of SMS icons on FW 3.x (thanks @roidelapluie) diff --git a/README.md b/README.md index 0c42e1eb..581ffa68 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,12 @@ need to create an account and transmit any of your data to the vendor's servers. * Support for generic notifications (above filtered out) * Dismiss individial notifications or open corresponding app on phone from the action menu (generic notifications) * Dismiss all notifications from the action menu (non-generic notifications) -* Music playback info (artist, album, track). Apollo and CM 12.1 Music App supported. +* Music playback info (artist, album, track) * Music control: play/pause, next track, previous track, volume up, volume down * List and remove installed apps/watchfaces -* Install .pbw files -* Install firmware from .pbz files +* Install watchfaces and firmware files (.pbw and .pbz) * Take and share screenshots from the Pebble's screen +* PebbleKit support for 3rd Party Android Apps support (experiental). * Morpheuz sleep data syncronization (experimental) ## Notes about the Pebble Time From e6a8a1a36c7ad636d24a28bd802ef7c4898265da Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Fri, 18 Sep 2015 00:03:34 +0200 Subject: [PATCH 46/73] Pebble: Better support for 8 and 16 bit integers in AppMessages --- .../devices/pebble/PebbleProtocol.java | 48 +++++++++++++++---- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 61d7e838..c3558b4f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -1218,6 +1218,12 @@ public class PebbleProtocol extends GBDeviceProtocol { length += 7; // key + type + length if (pair.second instanceof Integer) { length += 4; + } + if (pair.second instanceof Short) { + length += 2; + } + if (pair.second instanceof Byte) { + length += 1; } else if (pair.second instanceof String) { length += ((String) pair.second).length() + 1; } else if (pair.second instanceof byte[]) { @@ -1235,13 +1241,21 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.putLong(uuid.getLeastSignificantBits()); buf.put((byte) pairs.size()); - buf.order(ByteOrder.LITTLE_ENDIAN); // Um, yes, really + buf.order(ByteOrder.LITTLE_ENDIAN); for (Pair pair : pairs) { buf.putInt(pair.first); if (pair.second instanceof Integer) { buf.put(TYPE_INT); - buf.putShort((short) 4); // length of int + buf.putShort((short) 4); // length buf.putInt((int) pair.second); + } else if (pair.second instanceof Short) { + buf.put(TYPE_INT); + buf.putShort((short) 2); // length + buf.putShort((short) pair.second); + } else if (pair.second instanceof Byte) { + buf.put(TYPE_INT); + buf.putShort((short) 1); // length + buf.put((byte) pair.second); } else if (pair.second instanceof String) { String str = (String) pair.second; buf.put(TYPE_CSTRING); @@ -1266,13 +1280,29 @@ public class PebbleProtocol extends GBDeviceProtocol { JSONObject jsonObject = (JSONObject) jsonArray.get(i); String type = (String) jsonObject.get("type"); int key = (int) jsonObject.get("key"); - if (type.equals("uint") || type.equals("int")) { - pairs.add(new Pair<>(key, (Object) jsonObject.getInt("value"))); - } else if (type.equals("string")) { - pairs.add(new Pair<>(key, (Object) jsonObject.getString("value"))); - } else if (type.equals("bytes")) { - byte[] bytes = Base64.decode(jsonObject.getString("value"), Base64.NO_WRAP); - pairs.add(new Pair<>(key, (Object) bytes)); + int length = (int) jsonObject.get("length"); + switch (type) { + case "uint": + case "int": + if (length == 1) { + pairs.add(new Pair<>(key, (Object) (byte) jsonObject.getInt("value"))); + } else if (length == 2) { + pairs.add(new Pair<>(key, (Object) (short) jsonObject.getInt("value"))); + } else { + if (type.equals("uint")) { + pairs.add(new Pair<>(key, (Object) (int) (jsonObject.getInt("value") & 0xffffffffL))); + } else { + pairs.add(new Pair<>(key, (Object) jsonObject.getInt("value"))); + } + } + break; + case "string": + pairs.add(new Pair<>(key, (Object) jsonObject.getString("value"))); + break; + case "bytes": + byte[] bytes = Base64.decode(jsonObject.getString("value"), Base64.NO_WRAP); + pairs.add(new Pair<>(key, (Object) bytes)); + break; } } catch (JSONException e) { return null; From 94abac05d1f7ff735332c44dcc6350dd4946d05b Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Fri, 18 Sep 2015 16:36:33 +0200 Subject: [PATCH 47/73] Update CHANGELOG.md --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index def65522..63d8b97e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,12 @@ ####Next Version * Pebble: WIP implementantion of PebbleKit Intents to make some 3rd party Android apps work with the Pebble (eg. Ventoo) -* Pebble: Option to set reconnect attempts in settings (one attempt ususally takes about 5 seconds) +* Pebble: Option to set reconnect attempts in settings (one attempt usually takes about 5 seconds) * Support contolling all audio players that react to media buttons (can be chosen in settings) * Treat SMS as generic notification if set to "never" (can be blacklisted there also if desired) * Treat Conversations messagess as chat messages, even if arrived via Pebble Intents (nice icon for Pebble FW 3.x) +* Allow opening firmware / app files from the download manager "app" (technically a content provider) +* Miband: withelisted a few firmware versions ####Version 0.5.4 * Miband: allow the transfer of activity data without clearing MiBand's memory From 8bef3848556f05c7da1432387209c0378e9583a8 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Fri, 18 Sep 2015 16:37:37 +0200 Subject: [PATCH 48/73] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 581ffa68..cd11f810 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ need to create an account and transmit any of your data to the vendor's servers. * List and remove installed apps/watchfaces * Install watchfaces and firmware files (.pbw and .pbz) * Take and share screenshots from the Pebble's screen -* PebbleKit support for 3rd Party Android Apps support (experiental). +* PebbleKit support for 3rd Party Android Apps support (experimental). * Morpheuz sleep data syncronization (experimental) ## Notes about the Pebble Time From e1b02e1be4363538da8fa3f059529afad2e61e88 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 19 Sep 2015 12:49:34 +0200 Subject: [PATCH 49/73] Pebble: add option for PebbleKit support (default is disabled) Also fix an endless loop when number of reconnects is set to 0 --- .../devices/pebble/PebbleIoThread.java | 10 ++++---- app/src/main/res/values/strings.xml | 4 +++- app/src/main/res/xml/preferences.xml | 23 +++++++++++++------ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 9e7cd854..f8628ba4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -61,6 +61,8 @@ public class PebbleIoThread extends GBDeviceIoThread { private final PebbleProtocol mPebbleProtocol; private final PebbleSupport mPebbleSupport; + private final boolean mEnablePebblekit; + private boolean mIsTCP = false; private BluetoothAdapter mBtAdapter = null; private BluetoothSocket mBtSocket = null; @@ -152,6 +154,7 @@ public class PebbleIoThread extends GBDeviceIoThread { mPebbleProtocol = (PebbleProtocol) gbDeviceProtocol; mBtAdapter = btAdapter; mPebbleSupport = pebbleSupport; + mEnablePebblekit = sharedPrefs.getBoolean("pebble_enable_pebblekit", false); } @@ -346,7 +349,7 @@ public class PebbleIoThread extends GBDeviceIoThread { LOG.info(e.getMessage()); gbDevice.setState(GBDevice.State.CONNECTING); gbDevice.sendDeviceUpdateIntent(getContext()); - + mIsConnected = false; int reconnectAttempts = Integer.valueOf(sharedPrefs.getString("pebble_reconnect_attempts", "10")); while (reconnectAttempts-- > 0 && !mQuit) { LOG.info("Trying to reconnect (attempts left " + reconnectAttempts + ")"); @@ -377,9 +380,8 @@ public class PebbleIoThread extends GBDeviceIoThread { } private void enablePebbleKitReceiver(boolean enable) { - boolean force_untested = sharedPrefs.getBoolean("pebble_force_untested", false); - if (enable && force_untested) { + if (enable && mEnablePebblekit) { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(PEBBLEKIT_ACTION_APP_ACK); intentFilter.addAction(PEBBLEKIT_ACTION_APP_NACK); @@ -507,7 +509,7 @@ public class PebbleIoThread extends GBDeviceIoThread { setInstallSlot(appInfoEvent.freeSlot); return false; } else if (deviceEvent instanceof GBDeviceEventAppMessage) { - if (sharedPrefs.getBoolean("pebble_force_untested", false)) { + if (mEnablePebblekit) { LOG.info("Got AppMessage event"); sendAppMessageIntent((GBDeviceEventAppMessage) deviceEvent); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9fe36c74..1d9e575b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -33,7 +33,7 @@ General Settings Connect to device when Bluetooth turned on - Preferred audio player + Preferred Audioplayer Default Date and Time Sync time @@ -59,6 +59,8 @@ Mi Band address Pebble Settings + Allow 3rd Party Android App Access + Enable experimental support for Android Apps using PebbleKit Force Notification Protocol This option forces using the latest notification protocol depending on the firmware version. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING! Enable untested features diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 4f10aaf0..65b1cdcd 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -9,7 +9,7 @@ android:title="@string/pref_title_general_autoconnectonbluetooth" /> + + + + @@ -84,12 +99,6 @@ android:key="pebble_force_untested" android:summary="@string/pref_summary_pebble_forceuntested" android:title="@string/pref_title_pebble_forceuntested" /> - Date: Sat, 19 Sep 2015 12:53:30 +0200 Subject: [PATCH 50/73] update Spanish translation (thanks) --- app/src/main/res/values-es/strings.xml | 3 +++ app/src/main/res/values/strings.xml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 4b21c1b5..b6896866 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -26,6 +26,8 @@ Ajustes Ajustes generales Conectar al encender el bluetooth + Reproductor de audio preferido + Predeterminado Fecha y hora Sincronizar hora Sincroniza la hora en el dispositivo cuando se conecte o se cambie la hora o zona horaria en Android @@ -49,6 +51,7 @@ Esta opción fuerza el uso del último protocolo de notificación dependiendo de la versión de firmware. ¡HABILÍTALO SOLO SI SABES LO QUE ESTÁS HACIENDO! Habilitar características no probadas Habilita características que no han sido comprobadas. ¡HABILÍTALO SOLO SI SABES LO QUE ESTÁS HACIENDO! + Intentos de reconectar no conectado conectando conectado diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1d9e575b..c96ad764 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -65,7 +65,7 @@ This option forces using the latest notification protocol depending on the firmware version. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING! Enable untested features Enable features that are untested. ENABLE ONLY IF YOU KNOW WHAT YOU ARE DOING! - Reconnect attempts + Reconnection Attempts not connected connecting connected From 4b690ad641c03dcc56a66b1e57302571e97e8259 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 19 Sep 2015 12:56:29 +0200 Subject: [PATCH 51/73] bump version to 0.6.0 (not yet tagged) --- CHANGELOG.md | 10 +++++----- app/build.gradle | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 63d8b97e..0d695525 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,16 @@ ###Changelog -####Next Version +####Version 0.6.0 * Pebble: WIP implementantion of PebbleKit Intents to make some 3rd party Android apps work with the Pebble (eg. Ventoo) -* Pebble: Option to set reconnect attempts in settings (one attempt usually takes about 5 seconds) +* Pebble: Option to set reconnection attempts in settings (one attempt usually takes about 5 seconds) * Support contolling all audio players that react to media buttons (can be chosen in settings) * Treat SMS as generic notification if set to "never" (can be blacklisted there also if desired) * Treat Conversations messagess as chat messages, even if arrived via Pebble Intents (nice icon for Pebble FW 3.x) * Allow opening firmware / app files from the download manager "app" (technically a content provider) -* Miband: withelisted a few firmware versions +* Mi Band: whitelisted a few firmware versions ####Version 0.5.4 -* Miband: allow the transfer of activity data without clearing MiBand's memory +* Mi Band: allow the transfer of activity data without clearing MiBand's memory * Pebble: for generic notifications use generic icon instead of SMS icons on FW 3.x (thanks @roidelapluie) * Pebble: use different icons and background colors for specific groups of applications (chat, mail, etc) (thanks @roidelapluie) * In settings, support blacklisting apps for generic notifications @@ -25,7 +25,7 @@ ####Version 0.5.2 * Pebble: support "dismiss all" action also on Pebble Time/FW 3.x notifications -* Miband: show a notification when the battery is below 10% +* Mi Band: show a notification when the battery is below 10% * Graphs are now using the same theme as the rest of the application * Graphs now show when the device was not worn by the user (for devices that send this information) * Remove unused settings option in charts view diff --git a/app/build.gradle b/app/build.gradle index f69753a2..80b60540 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "nodomain.freeyourgadget.gadgetbridge" minSdkVersion 19 targetSdkVersion 23 - versionCode 25 - versionName "0.5.4" + versionCode 26 + versionName "0.6.0" } buildTypes { release { From a3ef85d243a77c3c8ac149a98f195d047ff6b8a3 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 19 Sep 2015 13:37:09 +0200 Subject: [PATCH 52/73] update German translation --- app/src/main/res/values-de/strings.xml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3d28dbe5..452eb47b 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -25,6 +25,8 @@ Einstellungen Allgemeine Einstellungen Verbinde, wenn Bluetooth eingeschaltet wird + Bevorzugter Audioplayer + Standard Datum und Zeit Uhrzeit synchronisieren Synchronisiere die Urzeit mit dem Gerät (bei Verbindingsaufbau und wenn die Zeit oder Zeitzone auf dem Android Gerät eingestellt wird) @@ -43,10 +45,13 @@ Entwickleroptionen Mi Band MAC Adresse Pebble Einstellungen + Erlaube Zugriff von anderen Android Apps + Experimentelle Unterstützung für Android Apps, die PebbleKit benutzen Benachrichtigungsprotokoll erzwingen Diese Option erzwingt das neuste Benachrichtigungsprotokoll abhängig von der Firmwareversion. NUR EINSCHALTEN, WENN DU WEISST WAS DU TUST! Ungetestete Features freischalten Schaltet ungetetestete Features frei. TU DIES NUR, WENN DU WEIßT, WAS DU TUST! + Neuverbindungsversuche nicht verbunden verbinde verbunden @@ -145,6 +150,7 @@ Deine Aktivität (ALPHA) Kann keine Verbindung herstellen: %1$s Kann keinen Handler für die Installation dieser Datei finden. + Konnte folgende Datei nicht installieren: %1$s Kann die gegebene Firmware nicht installieren. Sie passt nicht zur Hardware Revision der Pebble. Bitte warten während der Installationsoption festgestellt wird... Gadget Akkustand niedrig! @@ -172,4 +178,6 @@ Schritte Live Aktivität Schritte heute, Ziel: %1$s + Transfer von Aktivitätsdaten nicht bestätigen + Wenn der Transfer der Aktivitätsdaten nicht bestätigt wird, werden die Daten nicht auf dem Mi Band gelöscht. Das ist Sinnvoll, wenn neben Gadgetbridge noch andere Apps auf das Mi Band zugreifen. From 0c4dbf75e0a9b677da49462d593b4033611250a5 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 19 Sep 2015 15:32:09 +0200 Subject: [PATCH 53/73] Pebble: fix for PebbleKit AppMessages containing non-latin characters --- .../devices/pebble/PebbleProtocol.java | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index c3558b4f..35035478 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -460,12 +460,12 @@ public class PebbleProtocol extends GBDeviceProtocol { actions_count = 2; dismiss_string = "Dismiss"; dismiss_action_id = 0x02; - actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.length() + open_string.length()); + actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length + open_string.getBytes().length); } else { actions_count = 1; dismiss_string = "Dismiss all"; dismiss_action_id = 0x03; - actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.length() + open_string.length()); + actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length); } byte attributes_count = 0; @@ -523,7 +523,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.put((byte) 0x04); // dismiss buf.put((byte) 0x01); // number attributes buf.put((byte) 0x01); // attribute id (title) - buf.putShort((short) dismiss_string.length()); + buf.putShort((short) dismiss_string.getBytes().length); buf.put(dismiss_string.getBytes()); // open action @@ -532,7 +532,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.put((byte) 0x02); // dissmiss - FIXME: find out how to answer to 2.x generic actions buf.put((byte) 0x01); // number attributes buf.put((byte) 0x01); // attribute id (title) - buf.putShort((short) open_string.length()); + buf.putShort((short) open_string.getBytes().length); buf.put(open_string.getBytes()); } @@ -578,7 +578,7 @@ public class PebbleProtocol extends GBDeviceProtocol { byte attributes_count = 2; byte actions_count = 0; - int attributes_length = 10 + title.length(); + int attributes_length = 10 + title.getBytes().length; int pin_length = TIMELINE_PIN_LENGTH + attributes_length; ByteBuffer buf = ByteBuffer.allocate(pin_length); @@ -665,12 +665,12 @@ public class PebbleProtocol extends GBDeviceProtocol { actions_count = 2; dismiss_string = "Dismiss"; dismiss_action_id = 0x02; - actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.length() + open_string.length()); + actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length + open_string.getBytes().length); } else { actions_count = 1; dismiss_string = "Dismiss all"; dismiss_action_id = 0x03; - actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.length() + open_string.length()); + actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length); } byte attributes_count = 2; // icon @@ -738,7 +738,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.put((byte) 0x02); // generic action, dismiss did not do anything buf.put((byte) 0x01); // number attributes buf.put((byte) 0x01); // attribute id (title) - buf.putShort((short) dismiss_string.length()); + buf.putShort((short) dismiss_string.getBytes().length); buf.put(dismiss_string.getBytes()); // open action @@ -747,14 +747,14 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.put((byte) 0x02); // generic action buf.put((byte) 0x01); // number attributes buf.put((byte) 0x01); // attribute id (title) - buf.putShort((short) open_string.length()); + buf.putShort((short) open_string.getBytes().length); buf.put(open_string.getBytes()); } return encodeBlobdb(UUID.randomUUID(), BLOBDB_INSERT, BLOBDB_NOTIFICATION, buf.array()); } public byte[] encodeActionResponse2x(int id, int iconId, String caption) { - short length = (short) (18 + caption.length()); + short length = (short) (18 + caption.getBytes().length); ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(length); @@ -769,13 +769,13 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.putShort((short) 4); // length buf.putInt(iconId); buf.put((byte) 2); // title - buf.putShort((short) caption.length()); + buf.putShort((short) caption.getBytes().length); buf.put(caption.getBytes()); return buf.array(); } public byte[] encodeActionResponse(UUID uuid, int iconId, String caption) { - short length = (short) (29 + caption.length()); + short length = (short) (29 + caption.getBytes().length); ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length); buf.order(ByteOrder.BIG_ENDIAN); buf.putShort(length); @@ -790,7 +790,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.putShort((short) 4); // length buf.putInt(0x80000000 | iconId); buf.put((byte) 2); // title - buf.putShort((short) caption.length()); + buf.putShort((short) caption.getBytes().length); buf.put(caption.getBytes()); return buf.array(); } @@ -799,7 +799,7 @@ public class PebbleProtocol extends GBDeviceProtocol { final short METADATA_LENGTH = 126; byte[] name_buf = new byte[96]; - System.arraycopy(appName.getBytes(), 0, name_buf, 0, appName.length()); + System.arraycopy(appName.getBytes(), 0, name_buf, 0, appName.getBytes().length); ByteBuffer buf = ByteBuffer.allocate(METADATA_LENGTH); buf.order(ByteOrder.BIG_ENDIAN); @@ -1218,14 +1218,12 @@ public class PebbleProtocol extends GBDeviceProtocol { length += 7; // key + type + length if (pair.second instanceof Integer) { length += 4; - } - if (pair.second instanceof Short) { + } else if (pair.second instanceof Short) { length += 2; - } - if (pair.second instanceof Byte) { + } else if (pair.second instanceof Byte) { length += 1; } else if (pair.second instanceof String) { - length += ((String) pair.second).length() + 1; + length += ((String) pair.second).getBytes().length + 1; } else if (pair.second instanceof byte[]) { length += ((byte[]) pair.second).length; } @@ -1259,7 +1257,7 @@ public class PebbleProtocol extends GBDeviceProtocol { } else if (pair.second instanceof String) { String str = (String) pair.second; buf.put(TYPE_CSTRING); - buf.putShort((short) (str.length() + 1)); + buf.putShort((short) (str.getBytes().length + 1)); buf.put(str.getBytes()); buf.put((byte) 0); } else if (pair.second instanceof byte[]) { From 60b24e004a7bfe63c372f55d6006d597f0f5e237 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 19 Sep 2015 21:35:02 +0200 Subject: [PATCH 54/73] Pebble: Fix bug for Pebble Intent Notifications not arriving on FW 2.x --- .../gadgetbridge/service/devices/pebble/PebbleProtocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 35035478..d5d48c5d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -408,7 +408,7 @@ public class PebbleProtocol extends GBDeviceProtocol { @Override public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { - return encodeNotification(handle, title, null, details, NOTIFICATION_UNDEFINED, handle != -1, notificationKind); + return encodeNotification(handle != -1 ? handle : mRandom.nextInt(), title, null, details, NOTIFICATION_UNDEFINED, handle != -1, notificationKind); } @Override From f6ef72e9fb7c19f824ad423bf8896bbe28ce7c26 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 20 Sep 2015 18:27:41 +0200 Subject: [PATCH 55/73] Pebble: fix some hardware revision strings to match strings in firmware json file This should enable firmware upgrade on Pebble Time and might fix pbw installation on Pebble Time Steel --- .../service/devices/pebble/PebbleIoThread.java | 2 +- .../service/devices/pebble/PebbleProtocol.java | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index f8628ba4..9714143d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -541,7 +541,7 @@ public class PebbleIoThread extends GBDeviceIoThread { return; } - mPBWReader = new PBWReader(uri, getContext(), gbDevice.getHardwareVersion().equals("dvt") ? "basalt" : "aplite"); + mPBWReader = new PBWReader(uri, getContext(), gbDevice.getHardwareVersion().startsWith("snowy") ? "basalt" : "aplite"); mPebbleInstallables = mPBWReader.getPebbleInstallables(); mCurrentInstallableIndex = 0; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index d5d48c5d..6a4446ae 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -214,7 +214,8 @@ public class PebbleProtocol extends GBDeviceProtocol { static final byte LENGTH_UUID = 16; - private static final String[] hwRevisions = {"unknown", "ev1", "ev2", "ev2_3", "ev2_4", "v1_5", "v2_0", "evt2", "dvt"}; + // base is -4 + private static final String[] hwRevisions = {"snowy_bb2", "snowy_bb", "bb2", "bb", "unknown", "ev1", "ev2", "ev2_3", "ev2_4", "v1_5", "v2_0", "snowy_evt2", "snowy_dvt", "unknown", "snowy_s3"}; private static Random mRandom = new Random(); boolean isFw3x = false; @@ -1578,10 +1579,8 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.get(tmp, 0, 9); Byte hwRev = buf.get(); - if (hwRev > 0 && hwRev < hwRevisions.length) { - versionCmd.hwVersion = hwRevisions[hwRev]; - } else if (hwRev == -3) { // basalt emulator - versionCmd.hwVersion = "dvt"; + if (hwRev >= -4 && hwRev < hwRevisions.length - 4) { + versionCmd.hwVersion = hwRevisions[hwRev+4]; } devEvts = new GBDeviceEvent[]{versionCmd}; break; From 98b1abedac073b019e06d2101b8eee234bb3a228 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sun, 20 Sep 2015 22:04:53 +0200 Subject: [PATCH 56/73] Allow phone call notifications (also in call display) to be disabled in preferences This will allow Pebble Dialer to handle these #106 --- .../gadgetbridge/activities/SettingsActivity.java | 1 + .../externalevents/PhoneCallReceiver.java | 12 +++++++++--- app/src/main/res/values/arrays.xml | 9 +++++++++ app/src/main/res/values/strings.xml | 2 +- app/src/main/res/xml/preferences.xml | 7 +++++++ 5 files changed, 27 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java index cf9f3102..a3dd4c67 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java @@ -104,6 +104,7 @@ public class SettingsActivity extends AbstractSettingsActivity { protected String[] getPreferenceKeysWithSummary() { return new String[]{ "audio_player", + "notification_mode_calls", "notification_mode_sms", "notification_mode_k9mail", "pebble_emu_addr", diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java index f19a84d9..c1782917 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PhoneCallReceiver.java @@ -3,6 +3,8 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; import android.telephony.TelephonyManager; import nodomain.freeyourgadget.gadgetbridge.GBApplication; @@ -22,11 +24,11 @@ public class PhoneCallReceiver extends BroadcastReceiver { String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE); String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER); int state = 0; - if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) { + if (TelephonyManager.EXTRA_STATE_IDLE.equals(stateStr)) { state = TelephonyManager.CALL_STATE_IDLE; - } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) { + } else if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(stateStr)) { state = TelephonyManager.CALL_STATE_OFFHOOK; - } else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) { + } else if (TelephonyManager.EXTRA_STATE_RINGING.equals(stateStr)) { state = TelephonyManager.CALL_STATE_RINGING; } @@ -62,6 +64,10 @@ public class PhoneCallReceiver extends BroadcastReceiver { break; } if (callCommand != null) { + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); + if ("never".equals(sharedPrefs.getString("notification_mode_calls", "always"))) { + return; + } GBApplication.deviceService().onSetCallState(mSavedNumber, null, callCommand); } mLastState = state; diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 88b4f5f3..c1857213 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -11,6 +11,15 @@ never + + @string/always + @string/never + + + always + never + + @string/male @string/female diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c96ad764..cbba2238 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -41,8 +41,8 @@ Notifications Repetitions + Phone Calls SMS - Incoming Calls K9-Mail Pebble Messages Support for applications which send Notifications to the Pebble via Intent. Can be used for Conversations. diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index 65b1cdcd..599e88b4 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -25,6 +25,13 @@ android:key="pref_key_notifications" android:title="@string/pref_header_notifications"> + + Date: Sun, 20 Sep 2015 22:13:25 +0200 Subject: [PATCH 57/73] Mi Band: Do not whitelist 1.0.10.14 anymore, vibration seems to be broken with Gadgetbridge --- .../gadgetbridge/devices/miband/MiBandFWHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java index d9144536..0ef50ab7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java @@ -35,7 +35,7 @@ public class MiBandFWHelper { 16779779, //1.0.10.3 reported on the wiki 16779782, //1.0.10.6 reported on the wikiew 16779787, //1.0.10.11 tested by developer - 16779790, //1.0.10.14 reported on the wiki + //16779790, //1.0.10.14 reported on the wiki (vibration does not work currently) }; public MiBandFWHelper(Uri uri, Context context) throws IOException { From 3852fcd756d31ed0b98f4f42cb8810e4e047315f Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sat, 19 Sep 2015 21:54:01 +0200 Subject: [PATCH 58/73] Reuse MiBandDateConverter --- .../devices/miband/MiBandDateConverter.java | 38 ++++++++++++++----- .../service/devices/miband/BatteryInfo.java | 2 +- .../operations/FetchActivityOperation.java | 13 +------ 3 files changed, 31 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java index b356a207..8663921b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java @@ -4,24 +4,44 @@ import java.util.Calendar; import java.util.GregorianCalendar; public class MiBandDateConverter { + /** + * Creates a calendar object representing the current date and time. + */ + public static GregorianCalendar createCalendar() { + return new GregorianCalendar(); + } + /** * uses the standard algorithm to convert bytes received from the MiBand to a Calendar object * @param value * @return */ public static GregorianCalendar rawBytesToCalendar(byte[] value) { - GregorianCalendar timestamp = new GregorianCalendar(); - if (value.length == 6) { - timestamp.set(Calendar.YEAR, (2000 + value[0])); - timestamp.set(Calendar.MONTH, value[1]); - timestamp.set(Calendar.DATE, value[2]); - timestamp.set(Calendar.HOUR_OF_DAY, value[3]); - timestamp.set(Calendar.MINUTE, value[4]); - timestamp.set(Calendar.SECOND, value[5]); + return rawBytesToCalendar(value, 0); + } + return createCalendar(); + } + + /** + * uses the standard algorithm to convert bytes received from the MiBand to a Calendar object + * @param value + * @return + */ + public static GregorianCalendar rawBytesToCalendar(byte[] value, int offset) { + if (value.length - offset >= 6) { + GregorianCalendar timestamp = new GregorianCalendar( + value[offset] + 2000, + value[offset + 1], + value[offset + 2], + value[offset + 3], + value[offset + 4], + value[offset + 5]); + + return timestamp; } - return timestamp; + return createCalendar(); } /** diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java index fa7d6e48..1bb6a33c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java @@ -43,7 +43,7 @@ public class BatteryInfo extends AbstractInfo { } public GregorianCalendar getLastChargeTime() { - GregorianCalendar lastCharge = new GregorianCalendar(); + GregorianCalendar lastCharge = MiBandDateConverter.createCalendar(); if (mData.length >= 10) { lastCharge = MiBandDateConverter.rawBytesToCalendar(new byte[]{ 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 90ac55c2..1047274e 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 @@ -107,7 +107,7 @@ public class FetchActivityOperation extends AbstractBTLEOperation // byte 0 is the data type: 1 means that each minute is represented by a triplet of bytes int dataType = value[0]; // byte 1 to 6 represent a timestamp - GregorianCalendar timestamp = parseTimestamp(value, 1); + GregorianCalendar timestamp = MiBandDateConverter.rawBytesToCalendar(value, 1); // counter of all data held by the band int totalDataToRead = (value[7] & 0xff) | ((value[8] & 0xff) << 8); @@ -273,15 +273,4 @@ public class FetchActivityOperation extends AbstractBTLEOperation LOG.error("Unable to send ack to MI", ex); } } - - private GregorianCalendar parseTimestamp(byte[] value, int offset) { - GregorianCalendar timestamp = new GregorianCalendar( - value[offset] + 2000, - value[offset + 1], - value[offset + 2], - value[offset + 3], - value[offset + 4], - value[offset + 5]); - return timestamp; - } } From d9b4bbe55039334928a561b5a0ff0504410c9773 Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Sat, 19 Sep 2015 23:32:10 +0200 Subject: [PATCH 59/73] Move activity data and progress manipulation into dedicated methods I did this in trying to understand the code better and to easier allow for error handling/transaction rollback to be added. --- .../operations/FetchActivityOperation.java | 114 +++++++++++++----- .../freeyourgadget/gadgetbridge/util/GB.java | 6 + 2 files changed, 90 insertions(+), 30 deletions(-) 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 1047274e..ccc6e1d0 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 @@ -31,28 +31,89 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; +/** + * An operation that fetches activity data. For every fetch, a new operation must + * be created, i.e. an operation may not be reused for multiple fetches. + */ public class FetchActivityOperation extends AbstractBTLEOperation { private static final Logger LOG = LoggerFactory.getLogger(FetchActivityOperation.class); private static final byte[] fetch = new byte[]{MiBandService.COMMAND_FETCH_DATA}; //temporary buffer, size is a multiple of 60 because we want to store complete minutes (1 minute = 3 bytes) - private static final int activityDataHolderSize = 3 * 60 * 4; // 8h + private static final int activityDataHolderSize = 3 * 60 * 4; // 4h private static class ActivityStruct { - public byte[] activityDataHolder = new byte[activityDataHolderSize]; + private byte[] activityDataHolder = new byte[activityDataHolderSize]; //index of the buffer above - public int activityDataHolderProgress = 0; + private int activityDataHolderProgress = 0; //number of bytes we will get in a single data transfer, used as counter - public int activityDataRemainingBytes = 0; + private int activityDataRemainingBytes = 0; //same as above, but remains untouched for the ack message - public int activityDataUntilNextHeader = 0; + private int activityDataUntilNextHeader = 0; //timestamp of the single data transfer, incremented to store each minute's data - public GregorianCalendar activityDataTimestampProgress = null; + private GregorianCalendar activityDataTimestampProgress = null; //same as above, but remains untouched for the ack message - public GregorianCalendar activityDataTimestampToAck = null; + private GregorianCalendar activityDataTimestampToAck = null; + + public boolean hasRoomFor(byte[] value) { + return activityDataRemainingBytes >= value.length; + } + + public boolean isValidData(byte[] value) { + //I don't like this clause, but until we figure out why we get different data sometimes this should work + return value.length == 20 || value.length == activityDataRemainingBytes; + } + + public boolean isBufferFull() { + return activityDataHolderSize == activityDataHolderProgress; + } + + public void buffer(byte[] value) { + System.arraycopy(value, 0, activityDataHolder, activityDataHolderProgress, value.length); + activityDataHolderProgress += value.length; + activityDataRemainingBytes -= value.length; + + validate(); + } + + private void validate() { + GB.assertThat(activityDataRemainingBytes >= 0, "Illegal state, remaining bytes is negative"); + } + + public boolean isFirstChunk() { + return activityDataTimestampProgress == null; + } + + public void startNewBlock(GregorianCalendar timestamp, int dataUntilNextHeader) { + GB.assertThat(timestamp != null, "Timestamp must not be null"); + + if (isFirstChunk()) { + activityDataTimestampProgress = timestamp; + } else { + if (timestamp.getTimeInMillis() >= activityDataTimestampProgress.getTimeInMillis()) { + activityDataTimestampProgress = timestamp; + } else { + // something is fishy here... better not trust the given timestamp and simply + // (re)use the current one + // we do accept the timestamp to ack though, so that the bogus data is properly cleared on the band + } + } + activityDataTimestampToAck = (GregorianCalendar) timestamp.clone(); + activityDataRemainingBytes = activityDataUntilNextHeader = dataUntilNextHeader; + validate(); + } + + public boolean isBlockFinished() { + return activityDataRemainingBytes == 0; + } + + public void bufferFlushed(int minutes) { + activityDataTimestampProgress.add(Calendar.MINUTE, minutes); + activityDataHolderProgress = 0; + } } - private ActivityStruct activityStruct; + private ActivityStruct activityStruct = new ActivityStruct(); public FetchActivityOperation(MiBandSupport support) { super(support); @@ -98,11 +159,6 @@ public class FetchActivityOperation extends AbstractBTLEOperation * @param value */ private void handleActivityNotif(byte[] value) { - boolean firstChunk = activityStruct == null; - if (firstChunk) { - activityStruct = new ActivityStruct(); - } - if (value.length == 11) { // byte 0 is the data type: 1 means that each minute is represented by a triplet of bytes int dataType = value[0]; @@ -123,7 +179,7 @@ public class FetchActivityOperation extends AbstractBTLEOperation // after dataUntilNextHeader bytes we will get a new packet of 11 bytes that should be parsed // as we just did - if (firstChunk && dataUntilNextHeader != 0) { + if (activityStruct.isFirstChunk() && dataUntilNextHeader != 0) { GB.toast(getContext().getString(R.string.user_feedback_miband_activity_data_transfer, DateTimeUtils.formatDurationHoursMinutes((totalDataToRead / 3), TimeUnit.MINUTES), DateFormat.getDateTimeInstance().format(timestamp.getTime())), Toast.LENGTH_LONG, GB.INFO); @@ -132,16 +188,14 @@ public class FetchActivityOperation extends AbstractBTLEOperation LOG.info("data to read until next header: " + dataUntilNextHeader + " len: " + (dataUntilNextHeader / 3) + " minute(s)"); LOG.info("TIMESTAMP: " + DateFormat.getDateTimeInstance().format(timestamp.getTime()).toString() + " magic byte: " + dataUntilNextHeader); - activityStruct.activityDataRemainingBytes = activityStruct.activityDataUntilNextHeader = dataUntilNextHeader; - activityStruct.activityDataTimestampToAck = (GregorianCalendar) timestamp.clone(); - activityStruct.activityDataTimestampProgress = timestamp; + activityStruct.startNewBlock(timestamp, dataUntilNextHeader); } else { bufferActivityData(value); } LOG.debug("activity data: length: " + value.length + ", remaining bytes: " + activityStruct.activityDataRemainingBytes); - if (activityStruct.activityDataRemainingBytes == 0) { + if (activityStruct.isBlockFinished()) { sendAckDataTransfer(activityStruct.activityDataTimestampToAck, activityStruct.activityDataUntilNextHeader); } } @@ -154,15 +208,11 @@ public class FetchActivityOperation extends AbstractBTLEOperation * @param value */ private void bufferActivityData(byte[] value) { + if (activityStruct.hasRoomFor(value)) { + if (activityStruct.isValidData(value)) { + activityStruct.buffer(value); - if (activityStruct.activityDataRemainingBytes >= value.length) { - //I don't like this clause, but until we figure out why we get different data sometimes this should work - if (value.length == 20 || value.length == activityStruct.activityDataRemainingBytes) { - System.arraycopy(value, 0, activityStruct.activityDataHolder, activityStruct.activityDataHolderProgress, value.length); - activityStruct.activityDataHolderProgress += value.length; - activityStruct.activityDataRemainingBytes -= value.length; - - if (this.activityDataHolderSize == activityStruct.activityDataHolderProgress) { + if (activityStruct.isBufferFull()) { flushActivityDataHolder(); } } else { @@ -190,22 +240,26 @@ public class FetchActivityOperation extends AbstractBTLEOperation DBHandler dbHandler = null; try { dbHandler = GBApplication.acquireDB(); + int minutes = 0; try (SQLiteDatabase db = dbHandler.getWritableDatabase()) { // explicitly keep the db open while looping over the samples + int timestampInSeconds = (int) (activityStruct.activityDataTimestampProgress.getTimeInMillis() / 1000); for (int i = 0; i < activityStruct.activityDataHolderProgress; i += 3) { //TODO: check if multiple of 3, if not something is wrong category = activityStruct.activityDataHolder[i]; intensity = activityStruct.activityDataHolder[i + 1]; steps = activityStruct.activityDataHolder[i + 2]; dbHandler.addGBActivitySample( - (int) (activityStruct.activityDataTimestampProgress.getTimeInMillis() / 1000), + timestampInSeconds, SampleProvider.PROVIDER_MIBAND, (short) (intensity & 0xff), (short) (steps & 0xff), category); - activityStruct.activityDataTimestampProgress.add(Calendar.MINUTE, 1); + // next minute + minutes++; + timestampInSeconds += 60; } } finally { - activityStruct.activityDataHolderProgress = 0; + activityStruct.bufferFlushed(minutes); } } catch (Exception ex) { GB.toast(getContext(), ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR); @@ -255,7 +309,7 @@ public class FetchActivityOperation extends AbstractBTLEOperation builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), ack); builder.queue(getQueue()); - // flush to the DB after sending the ACK + // flush to the DB after queueing the ACK flushActivityDataHolder(); //The last data chunk sent by the miband has always length 0. diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index 0108af85..1c7282bb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -339,4 +339,10 @@ public class GB { public static GBEnvironment env() { return environment; } + + public static void assertThat(boolean condition, String errorMessage) { + if (!condition) { + throw new AssertionError(errorMessage); + } + } } From 3bb673d33a3b40c99701521b415cd69ebd3f6987 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 23 Sep 2015 23:19:38 +0200 Subject: [PATCH 60/73] Pebble Time Round support ("chalk" platform) --- .../devices/pebble/PBWInstallHandler.java | 12 +++++++++++- .../devices/pebble/PBWReader.java | 2 +- .../devices/pebble/PebbleIoThread.java | 12 +++++++++++- .../devices/pebble/PebbleProtocol.java | 19 ++++++++++++++----- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java index 7d2e1790..ababb079 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWInstallHandler.java @@ -39,7 +39,17 @@ public class PBWInstallHandler implements InstallHandler { return; } - mPBWReader = new PBWReader(mUri, mContext, device.getHardwareVersion().equals("dvt") ? "basalt" : "aplite"); + String hwRev = device.getHardwareVersion(); + String platformName; + if (hwRev.startsWith("snowy")) { + platformName = "basalt"; + } else if (hwRev.startsWith("spalding")) { + platformName = "chalk"; + } else { + platformName = "aplite"; + } + + mPBWReader = new PBWReader(mUri, mContext, platformName); if (!mPBWReader.isValid()) { installActivity.setInfoText("pbw/pbz is broken or incompatible with your Hardware or Firmware."); installActivity.setInstallEnabled(false); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java index b9f85a67..f5ac8c69 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/PBWReader.java @@ -59,7 +59,7 @@ public class PBWReader { public PBWReader(Uri uri, Context context, String platform) { String platformDir = ""; - if (!uri.toString().endsWith(".pbz") && platform.equals("basalt")) { + if (!uri.toString().endsWith(".pbz") && !platform.equals("aplite")) { platformDir = platform + "/"; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java index 9714143d..45c48d37 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java @@ -541,7 +541,17 @@ public class PebbleIoThread extends GBDeviceIoThread { return; } - mPBWReader = new PBWReader(uri, getContext(), gbDevice.getHardwareVersion().startsWith("snowy") ? "basalt" : "aplite"); + String hwRev = gbDevice.getHardwareVersion(); + String platformName; + if (hwRev.startsWith("snowy")) { + platformName = "basalt"; + } else if (hwRev.startsWith("spalding")) { + platformName = "chalk"; + } else { + platformName = "aplite"; + } + + mPBWReader = new PBWReader(uri, getContext(), platformName); mPebbleInstallables = mPBWReader.getPebbleInstallables(); mCurrentInstallableIndex = 0; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 6a4446ae..56c83b8f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -214,8 +214,17 @@ public class PebbleProtocol extends GBDeviceProtocol { static final byte LENGTH_UUID = 16; - // base is -4 - private static final String[] hwRevisions = {"snowy_bb2", "snowy_bb", "bb2", "bb", "unknown", "ev1", "ev2", "ev2_3", "ev2_4", "v1_5", "v2_0", "snowy_evt2", "snowy_dvt", "unknown", "snowy_s3"}; + // base is -5 + private static final String[] hwRevisions = { + // Emulator + "spalding_bb2", "snowy_bb2", "snowy_bb", "bb2", "bb", + "unknown", + // Pebble + "ev1", "ev2", "ev2_3", "ev2_4", "v1_5", "v2_0", + // Pebble Time + "snowy_evt2", "snowy_dvt", "spalding_dvt", "snowy_s3", "spalding_pvt" + }; + private static Random mRandom = new Random(); boolean isFw3x = false; @@ -1578,9 +1587,9 @@ public class PebbleProtocol extends GBDeviceProtocol { } buf.get(tmp, 0, 9); - Byte hwRev = buf.get(); - if (hwRev >= -4 && hwRev < hwRevisions.length - 4) { - versionCmd.hwVersion = hwRevisions[hwRev+4]; + int hwRev = buf.get() + 5; + if (hwRev >= 0 && hwRev < hwRevisions.length) { + versionCmd.hwVersion = hwRevisions[hwRev]; } devEvts = new GBDeviceEvent[]{versionCmd}; break; From ab78d167d95852d58e55db8dc79e92afc98f7c0f Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Wed, 23 Sep 2015 23:53:16 +0200 Subject: [PATCH 61/73] update CHANGELOG.md --- CHANGELOG.md | 4 ++++ .../gadgetbridge/service/devices/pebble/PebbleProtocol.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d695525..372b1956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ###Changelog +####Next Version +* Pebble: Detect all known Pebble Versions including new "chalk" platform (Pebble Time Round) +* Option to ignore phone calls (useful for Pebble Dialer) + ####Version 0.6.0 * Pebble: WIP implementantion of PebbleKit Intents to make some 3rd party Android apps work with the Pebble (eg. Ventoo) * Pebble: Option to set reconnection attempts in settings (one attempt usually takes about 5 seconds) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 56c83b8f..87dde6e5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -222,7 +222,7 @@ public class PebbleProtocol extends GBDeviceProtocol { // Pebble "ev1", "ev2", "ev2_3", "ev2_4", "v1_5", "v2_0", // Pebble Time - "snowy_evt2", "snowy_dvt", "spalding_dvt", "snowy_s3", "spalding_pvt" + "snowy_evt2", "snowy_dvt", "spalding_dvt", "snowy_s3", "spalding" }; private static Random mRandom = new Random(); From 8ba307657a2e9630960fef0e36458726eef588bf Mon Sep 17 00:00:00 2001 From: cpfeiffer Date: Thu, 24 Sep 2015 00:02:58 +0200 Subject: [PATCH 62/73] Migrate from MPAndroidChart 2.1.0 to 2.1.4 This actually makes our CustomLegendRenderer and CustomBarChart unnecessary. --- app/build.gradle | 2 +- .../charts/ActivitySleepChartFragment.java | 3 +- .../activities/charts/CustomBarChart.java | 31 -------------- .../charts/CustomLegendRenderer.java | 42 ------------------- .../activities/charts/SleepChartFragment.java | 8 ++-- .../charts/WeekStepsChartFragment.java | 3 +- .../res/layout-land/fragment_sleepchart.xml | 4 +- app/src/main/res/layout/fragment_charts.xml | 2 +- .../main/res/layout/fragment_sleepchart.xml | 4 +- 9 files changed, 12 insertions(+), 87 deletions(-) delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/CustomBarChart.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/CustomLegendRenderer.java diff --git a/app/build.gradle b/app/build.gradle index 80b60540..69f9c61b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -46,7 +46,7 @@ dependencies { compile 'com.android.support:support-v4:23.0.0' compile 'com.github.tony19:logback-android-classic:1.1.1-3' compile 'org.slf4j:slf4j-api:1.7.7' - compile 'com.github.PhilJay:MPAndroidChart:2.1.0' + compile 'com.github.PhilJay:MPAndroidChart:v2.1.4' compile 'com.github.pfichtner:durationformatter:0.1.1' } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java index d3a380e4..b60927b4 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivitySleepChartFragment.java @@ -125,8 +125,7 @@ public class ActivitySleepChartFragment extends AbstractChartFragment { legendLabels.add(akDeepSleep.label); legendColors.add(akNotWorn.color); legendLabels.add(akNotWorn.label); - chart.getLegend().setColors(legendColors); - chart.getLegend().setLabels(legendLabels); + chart.getLegend().setCustom(legendColors, legendLabels); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/CustomBarChart.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/CustomBarChart.java deleted file mode 100644 index 34acacf4..00000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/CustomBarChart.java +++ /dev/null @@ -1,31 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.activities.charts; - -import android.content.Context; -import android.util.AttributeSet; - -import com.github.mikephil.charting.charts.BarChart; - -/** - * A BarChart with some specific customization, like - *

  • using a custom legend renderer that always uses fixed labels and colors
  • - */ -public class CustomBarChart extends BarChart { - - public CustomBarChart(Context context) { - super(context); - } - - public CustomBarChart(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public CustomBarChart(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - protected void init() { - super.init(); - mLegendRenderer = new CustomLegendRenderer(getViewPortHandler(), getLegend()); - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/CustomLegendRenderer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/CustomLegendRenderer.java deleted file mode 100644 index b2308cdd..00000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/CustomLegendRenderer.java +++ /dev/null @@ -1,42 +0,0 @@ -package nodomain.freeyourgadget.gadgetbridge.activities.charts; - -import android.graphics.Typeface; - -import com.github.mikephil.charting.components.Legend; -import com.github.mikephil.charting.data.ChartData; -import com.github.mikephil.charting.renderer.LegendRenderer; -import com.github.mikephil.charting.utils.ViewPortHandler; - -/** - * A legend renderer that does *not* calculate the labels and colors automatically - * from the data sets or the data entries. - *

    - * Instead, they have to be provided manually, because otherwise the legend will - * be empty. - */ -public class CustomLegendRenderer extends LegendRenderer { - public CustomLegendRenderer(ViewPortHandler viewPortHandler, Legend legend) { - super(viewPortHandler, legend); - } - - @Override - public void computeLegend(ChartData data) { - if (!mLegend.isEnabled()) { - return; - } - - // don't call super to avoid computing colors and labels - // super.computeLegend(data); - - Typeface tf = mLegend.getTypeface(); - - if (tf != null) - mLegendLabelPaint.setTypeface(tf); - - mLegendLabelPaint.setTextSize(mLegend.getTextSize()); - mLegendLabelPaint.setColor(mLegend.getTextColor()); - - // calculate all dimensions of the mLegend - mLegend.calculateDimensions(mLegendLabelPaint); - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java index 9c40dc7b..6da15864 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepChartFragment.java @@ -16,7 +16,8 @@ import com.github.mikephil.charting.components.YAxis; import com.github.mikephil.charting.data.Entry; import com.github.mikephil.charting.data.PieData; import com.github.mikephil.charting.data.PieDataSet; -import com.github.mikephil.charting.utils.ValueFormatter; +import com.github.mikephil.charting.formatter.ValueFormatter; +import com.github.mikephil.charting.utils.ViewPortHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -71,7 +72,7 @@ public class SleepChartFragment extends AbstractChartFragment { PieDataSet set = new PieDataSet(entries, ""); set.setValueFormatter(new ValueFormatter() { @Override - public String getFormattedValue(float value) { + public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) { return DateTimeUtils.formatDurationHoursMinutes((long) value, TimeUnit.SECONDS); } }); @@ -166,8 +167,7 @@ public class SleepChartFragment extends AbstractChartFragment { legendLabels.add(akLightSleep.label); legendColors.add(akDeepSleep.color); legendLabels.add(akDeepSleep.label); - chart.getLegend().setColors(legendColors); - chart.getLegend().setLabels(legendLabels); + chart.getLegend().setCustom(legendColors, legendLabels); chart.getLegend().setTextColor(LEGEND_TEXT_COLOR); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java index 39068828..4bcd5cb5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java @@ -194,8 +194,7 @@ public class WeekStepsChartFragment extends AbstractChartFragment { List legendLabels = new ArrayList<>(1); legendColors.add(akActivity.color); legendLabels.add(getContext().getString(R.string.chart_steps)); - chart.getLegend().setColors(legendColors); - chart.getLegend().setLabels(legendLabels); + chart.getLegend().setCustom(legendColors, legendLabels); chart.getLegend().setTextColor(LEGEND_TEXT_COLOR); } diff --git a/app/src/main/res/layout-land/fragment_sleepchart.xml b/app/src/main/res/layout-land/fragment_sleepchart.xml index 0323f2c5..5b4e0b40 100644 --- a/app/src/main/res/layout-land/fragment_sleepchart.xml +++ b/app/src/main/res/layout-land/fragment_sleepchart.xml @@ -11,10 +11,10 @@ android:layout_weight="40"> - diff --git a/app/src/main/res/layout/fragment_charts.xml b/app/src/main/res/layout/fragment_charts.xml index 9501bcd3..bd8983f8 100644 --- a/app/src/main/res/layout/fragment_charts.xml +++ b/app/src/main/res/layout/fragment_charts.xml @@ -3,7 +3,7 @@ android:layout_height="match_parent" tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment"> - - From 5578691321ba1c9e551609ffc53722780d522bb2 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 24 Sep 2015 14:02:33 +0200 Subject: [PATCH 63/73] Fix progress bar --- .../devices/miband/operations/UpdateFirmwareOperation.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index 35448d5d..01c1798e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -190,10 +190,10 @@ public class UpdateFirmwareOperation extends AbstractBTLEOperation 0) && (i % 50 == 0)) { builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT), new byte[]{MiBandService.COMMAND_SYNC}); - builder.add(new SetProgressAction("Firmware update in progress", true, (firmwareProgress / len) * 100, getContext())); + builder.add(new SetProgressAction("Firmware update in progress", true, (int)(((float) firmwareProgress) / len * 100), getContext())); } - LOG.info("Firmware update progress:" + firmwareProgress + " total len:" + len + " progress:" + (firmwareProgress / len)); + LOG.info("Firmware update progress:" + firmwareProgress + " total len:" + len + " progress:" + (int)(((float) firmwareProgress) / len * 100)); } if (!(len % packetLength == 0)) { From e1ea8270ca0a01c1239d680e90c39ab30cd1b637 Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Thu, 24 Sep 2015 14:03:01 +0200 Subject: [PATCH 64/73] Add a progress notification for the activity data transfer. --- .../operations/FetchActivityOperation.java | 3 ++ .../freeyourgadget/gadgetbridge/util/GB.java | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+) 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 ccc6e1d0..f89fd2f1 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 @@ -195,8 +195,11 @@ public class FetchActivityOperation extends AbstractBTLEOperation } LOG.debug("activity data: length: " + value.length + ", remaining bytes: " + activityStruct.activityDataRemainingBytes); + GB.updateTransferNotification(getContext().getString(R.string.busy_task_fetch_activity_data), true, (int)(((float) (activityStruct.activityDataUntilNextHeader - activityStruct.activityDataRemainingBytes)) / activityStruct.activityDataUntilNextHeader * 100), getContext()); + if (activityStruct.isBlockFinished()) { sendAckDataTransfer(activityStruct.activityDataTimestampToAck, activityStruct.activityDataUntilNextHeader); + GB.updateTransferNotification("", false, 100, getContext()); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index 1c7282bb..1a1eddb6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -40,6 +40,7 @@ public class GB { public static final int NOTIFICATION_ID = 1; public static final int NOTIFICATION_ID_INSTALL = 2; public static final int NOTIFICATION_ID_LOW_BATTERY = 3; + public static final int NOTIFICATION_ID_TRANSFER = 4; private static final Logger LOG = LoggerFactory.getLogger(GB.class); public static final int INFO = 1; @@ -80,6 +81,11 @@ public class GB { nm.notify(id, notification); } + private static void removeNotification(int id, Context context) { + NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + nm.cancel(id); + } + public static void setReceiversEnableState(boolean enable, Context context) { LOG.info("Setting broadcast receivers to: " + enable); final Class[] receiverClasses = { @@ -275,6 +281,41 @@ public class GB { } } + private static Notification createTransferNotification(String text, boolean ongoing, + int percentage, Context context) { + Intent notificationIntent = new Intent(context, ControlCenter.class); + notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_CLEAR_TASK); + PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, + notificationIntent, 0); + + NotificationCompat.Builder nb = new NotificationCompat.Builder(context) + .setVisibility(Notification.VISIBILITY_PUBLIC) + .setContentTitle(context.getString(R.string.app_name)) + .setContentText(text) + .setContentIntent(pendingIntent) + .setOngoing(ongoing); + + if (ongoing) { + nb.setProgress(100, percentage, percentage == 0); + nb.setSmallIcon(android.R.drawable.stat_sys_download); + } else { + nb.setProgress(0, 0, false); + nb.setSmallIcon(android.R.drawable.stat_sys_download_done); + } + + return nb.build(); + } + + public static void updateTransferNotification(String text, boolean ongoing, int percentage, Context context) { + if(percentage == 100) { + removeNotification(NOTIFICATION_ID_TRANSFER, context); + } else { + Notification notification = createTransferNotification(text, ongoing, percentage, context); + updateNotification(notification, NOTIFICATION_ID_TRANSFER, context); + } + } + private static Notification createInstallNotification(String text, boolean ongoing, int percentage, Context context) { Intent notificationIntent = new Intent(context, ControlCenter.class); From 1d41f2f8e4df71efd5eeeb3ce7baa94762ade110 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 24 Sep 2015 14:45:21 +0200 Subject: [PATCH 65/73] Refactoring The notfification APIs now use NotificationSpec as their only parameter, which contains all information (required and optional ones). We no longer have separate methods and actions for SMS/EMAIL/GENERIC anymore. The type of notification is important now, not how we received them technically. --- .../gadgetbridge/GBApplication.java | 4 +- .../gadgetbridge/GBException.java | 3 + .../activities/AbstractGBFragment.java | 5 +- .../AbstractGBFragmentActivity.java | 8 +-- .../gadgetbridge/activities/AlarmDetails.java | 2 +- .../activities/ConfigureAlarms.java | 3 +- .../activities/ControlCenter.java | 1 - .../activities/DebugActivity.java | 20 +++++-- .../activities/DiscoveryActivity.java | 6 +- .../activities/FwAppInstallerActivity.java | 1 - .../activities/InstallActivity.java | 1 + .../activities/charts/ChartsHost.java | 3 + .../adapter/DeviceCandidateAdapter.java | 4 +- .../adapter/GBAlarmListAdapter.java | 2 +- .../gadgetbridge/adapter/GBDeviceAdapter.java | 2 +- .../adapter/GBDeviceAppAdapter.java | 2 +- .../database/ActivityDatabaseHandler.java | 10 ++-- .../gadgetbridge/database/DBAccess.java | 2 +- .../gadgetbridge/database/DBHandler.java | 2 +- .../gadgetbridge/devices/EventHandler.java | 10 +--- .../devices/UnknownDeviceCoordinator.java | 4 +- .../devices/miband/MiBandCoordinator.java | 12 ++-- .../devices/miband/MiBandDateConverter.java | 3 + .../devices/miband/MiBandFWHelper.java | 3 +- .../devices/miband/MiBandPairingActivity.java | 5 +- .../miband/MiBandPreferencesActivity.java | 4 +- .../devices/miband/MiBandSampleProvider.java | 2 +- .../devices/miband/MiBandService.java | 6 +- .../pebble/MorpheuzSampleProvider.java | 2 +- .../BluetoothStateChangeReceiver.java | 1 - .../externalevents/K9Receiver.java | 16 +++--- .../externalevents/MusicPlaybackReceiver.java | 2 - .../externalevents/NotificationListener.java | 27 +++++---- .../externalevents/PebbleReceiver.java | 19 +++---- .../externalevents/SMSReceiver.java | 14 +++-- .../gadgetbridge/impl/GBDevice.java | 4 +- .../gadgetbridge/impl/GBDeviceCandidate.java | 2 +- .../gadgetbridge/impl/GBDeviceService.java | 35 ++++-------- .../gadgetbridge/model/ActivityAmount.java | 2 - .../gadgetbridge/model/DeviceService.java | 16 ++++-- .../gadgetbridge/model/ItemWithDetails.java | 2 + .../gadgetbridge/model/NotificationSpec.java | 12 ++++ ...icationKind.java => NotificationType.java} | 2 +- .../service/DeviceCommunicationService.java | 47 +++++++--------- .../gadgetbridge/service/DeviceSupport.java | 10 +++- .../service/ServiceDeviceSupport.java | 23 ++------ .../service/btle/AbstractBTLEOperation.java | 5 +- .../service/btle/BTLEOperation.java | 2 - .../gadgetbridge/service/btle/BtLEQueue.java | 9 ++- .../service/btle/Transaction.java | 8 ++- .../service/btle/TransactionBuilder.java | 5 +- .../btle/actions/SetProgressAction.java | 1 + .../service/devices/miband/BatteryInfo.java | 2 +- .../service/devices/miband/MiBandSupport.java | 32 ++++++----- .../operations/FetchActivityOperation.java | 9 ++- .../operations/UpdateFirmwareOperation.java | 18 +++--- .../devices/pebble/PebbleProtocol.java | 56 +++++++++---------- .../devices/pebble/WeatherNeatSupport.java | 2 +- .../serial/AbstractSerialDeviceSupport.java | 18 +----- .../service/serial/GBDeviceProtocol.java | 12 +--- .../gadgetbridge/util/DeviceHelper.java | 4 +- .../gadgetbridge/util/FileUtils.java | 3 +- .../freeyourgadget/gadgetbridge/util/GB.java | 2 +- 63 files changed, 275 insertions(+), 279 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationSpec.java rename app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/{NotificationKind.java => NotificationType.java} (80%) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index f2ef7ae3..91cc0a97 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -101,9 +101,10 @@ public class GBApplication extends Application { * when that was not successful * If acquiring was successful, callers must call #releaseDB when they * are done (from the same thread that acquired the lock! + * * @return the DBHandler - * @see #releaseDB() * @throws GBException + * @see #releaseDB() */ public static DBHandler acquireDB() throws GBException { try { @@ -118,6 +119,7 @@ public class GBApplication extends Application { /** * Releases the database lock. + * * @throws IllegalMonitorStateException if the current thread is not owning the lock * @see #acquireDB() */ diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBException.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBException.java index b5b16c84..7327b558 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBException.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBException.java @@ -4,12 +4,15 @@ public class GBException extends Exception { public GBException(String message, Throwable cause) { super(message, cause); } + public GBException(String message) { super(message); } + public GBException(Throwable cause) { super(cause); } + public GBException() { super(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragment.java index 52da065a..6a77ae4d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragment.java @@ -1,13 +1,14 @@ package nodomain.freeyourgadget.gadgetbridge.activities; -import android.support.v4.app.Fragment; import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; /** * Abstract base class for fragments. Provides hooks that are called when * the fragment is made visible and invisible in the activity. also allows * the fragment to define the title to be shown in the activity. + * * @see AbstractGBFragmentActivity */ public abstract class AbstractGBFragment extends Fragment { @@ -25,6 +26,7 @@ public abstract class AbstractGBFragment extends Fragment { /** * Called when this fragment has been scrolled out of the activity. + * * @see #isVisibleInActivity() * @see #onMadeVisibleInActivity() */ @@ -54,6 +56,7 @@ public abstract class AbstractGBFragment extends Fragment { /** * Internal + * * @hide */ public void onMadeVisibleInActivityInternal() { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java index 257a1804..b76e50c3 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragmentActivity.java @@ -1,20 +1,15 @@ package nodomain.freeyourgadget.gadgetbridge.activities; -import android.content.Context; import android.os.Bundle; -import android.os.PersistableBundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.view.PagerAdapter; -import android.util.AttributeSet; -import android.view.View; /** * A base activity that supports paging through fragments by swiping. * Subclasses will have to add a ViewPager to their layout and add something * like this to hook it to the fragments: - * + *

    *

      * // Set up the ViewPager with the sections adapter.
      * ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
    @@ -50,6 +45,7 @@ public abstract class AbstractGBFragmentActivity extends FragmentActivity {
         /**
          * Creates a PagerAdapter that will create the fragments to be used with this
          * activity. The fragments should typically extend AbstractGBFragment
    +     *
          * @param fragmentManager
          * @return
          */
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java
    index ee949e72..8866f8a7 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AlarmDetails.java
    @@ -8,9 +8,9 @@ import android.view.MenuItem;
     import android.widget.CheckBox;
     import android.widget.TimePicker;
     
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
     import nodomain.freeyourgadget.gadgetbridge.R;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
     
     public class AlarmDetails extends Activity {
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java
    index 9c263cf5..ba7221b3 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ConfigureAlarms.java
    @@ -12,10 +12,9 @@ import java.util.HashSet;
     import java.util.Set;
     
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    -import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
     import nodomain.freeyourgadget.gadgetbridge.R;
     import nodomain.freeyourgadget.gadgetbridge.adapter.GBAlarmListAdapter;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
     
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_ALARMS;
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java
    index 6a97fe90..61eef3d3 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java
    @@ -37,7 +37,6 @@ import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
     import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst;
     import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
     import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
    -import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
     import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
     import nodomain.freeyourgadget.gadgetbridge.util.GB;
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java
    index 0372ba2e..38aa1878 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DebugActivity.java
    @@ -26,6 +26,8 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
     import nodomain.freeyourgadget.gadgetbridge.R;
     import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
     import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
     import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand;
     import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
     import nodomain.freeyourgadget.gadgetbridge.util.GB;
    @@ -70,17 +72,25 @@ public class DebugActivity extends Activity {
             sendSMSButton.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
    -                GBApplication.deviceService().onSMS(getResources().getText(R.string.app_name).toString(), editContent.getText().toString());
    +                NotificationSpec notificationSpec = new NotificationSpec();
    +                notificationSpec.sender = getResources().getText(R.string.app_name).toString();
    +                notificationSpec.body = editContent.getText().toString();
    +                notificationSpec.type = NotificationType.SMS;
    +                notificationSpec.id = -1;
    +                GBApplication.deviceService().onNotification(notificationSpec);
                 }
             });
             sendEmailButton = (Button) findViewById(R.id.sendEmailButton);
             sendEmailButton.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
    -                GBApplication.deviceService().onEmail(
    -                        getResources().getText(R.string.app_name).toString(),
    -                        getResources().getText(R.string.test).toString(),
    -                        editContent.getText().toString());
    +                NotificationSpec notificationSpec = new NotificationSpec();
    +                notificationSpec.sender = getResources().getText(R.string.app_name).toString();
    +                notificationSpec.subject = editContent.getText().toString();
    +                notificationSpec.body = editContent.getText().toString();
    +                notificationSpec.type = NotificationType.EMAIL;
    +                notificationSpec.id = -1;
    +                GBApplication.deviceService().onNotification(notificationSpec);
                 }
             });
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java
    index 0acc5179..53268827 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/DiscoveryActivity.java
    @@ -24,13 +24,13 @@ import org.slf4j.LoggerFactory;
     
     import java.util.ArrayList;
     
    +import nodomain.freeyourgadget.gadgetbridge.R;
    +import nodomain.freeyourgadget.gadgetbridge.adapter.DeviceCandidateAdapter;
     import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
     import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
     import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
     import nodomain.freeyourgadget.gadgetbridge.util.GB;
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
    -import nodomain.freeyourgadget.gadgetbridge.R;
    -import nodomain.freeyourgadget.gadgetbridge.adapter.DeviceCandidateAdapter;
     
     public class DiscoveryActivity extends Activity implements AdapterView.OnItemClickListener {
         private static final Logger LOG = LoggerFactory.getLogger(DiscoveryActivity.class);
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java
    index a9ff065f..74df6ecb 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/FwAppInstallerActivity.java
    @@ -12,7 +12,6 @@ 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;
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/InstallActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/InstallActivity.java
    index c1a60e3c..4c66c217 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/InstallActivity.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/InstallActivity.java
    @@ -4,6 +4,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ItemWithDetails;
     
     public interface InstallActivity {
         void setInfoText(String text);
    +
         void setInstallEnabled(boolean enable);
     
         void clearInstallItems();
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java
    index 0ce8c48f..0d61d8d2 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java
    @@ -12,9 +12,12 @@ public interface ChartsHost {
         GBDevice getDevice();
     
         void setStartDate(Date startDate);
    +
         void setEndDate(Date endDate);
     
         Date getStartDate();
    +
         Date getEndDate();
    +
         void setDateInfo(String dateInfo);
     }
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/DeviceCandidateAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/DeviceCandidateAdapter.java
    index f55cc896..0e127cd8 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/DeviceCandidateAdapter.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/DeviceCandidateAdapter.java
    @@ -10,10 +10,10 @@ import android.widget.TextView;
     
     import java.util.List;
     
    -import nodomain.freeyourgadget.gadgetbridge.util.GB;
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
     import nodomain.freeyourgadget.gadgetbridge.R;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
     import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
    +import nodomain.freeyourgadget.gadgetbridge.util.GB;
     
     public class DeviceCandidateAdapter extends ArrayAdapter {
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java
    index 8e2df766..adc07178 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBAlarmListAdapter.java
    @@ -15,9 +15,9 @@ import java.util.ArrayList;
     import java.util.Collections;
     import java.util.Set;
     
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
     import nodomain.freeyourgadget.gadgetbridge.R;
     import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
     import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
     
     
    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 0e52d29d..0cf8fe90 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAdapter.java
    @@ -13,8 +13,8 @@ import android.widget.TextView;
     
     import java.util.List;
     
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
     import nodomain.freeyourgadget.gadgetbridge.R;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
     import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
     
     public class GBDeviceAdapter extends ArrayAdapter {
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java
    index 901071c4..ed808676 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/GBDeviceAppAdapter.java
    @@ -10,8 +10,8 @@ import android.widget.TextView;
     
     import java.util.List;
     
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
     import nodomain.freeyourgadget.gadgetbridge.R;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
     
     public class GBDeviceAppAdapter extends ArrayAdapter {
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java
    index fd642d49..e35c8935 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/ActivityDatabaseHandler.java
    @@ -12,13 +12,13 @@ import org.slf4j.LoggerFactory;
     
     import java.util.ArrayList;
     
    -import nodomain.freeyourgadget.gadgetbridge.util.GB;
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBActivitySample;
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    -import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
     import nodomain.freeyourgadget.gadgetbridge.database.schema.ActivityDBCreationScript;
    -import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
     import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBActivitySample;
    +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
    +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
    +import nodomain.freeyourgadget.gadgetbridge.util.GB;
     
     import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.DATABASE_NAME;
     import static nodomain.freeyourgadget.gadgetbridge.database.DBConstants.KEY_INTENSITY;
    @@ -179,7 +179,7 @@ public class ActivityDatabaseHandler extends SQLiteOpenHelper implements DBHandl
             }
             ArrayList samples = new ArrayList();
             final String where = "(provider=" + provider.getID() + " and timestamp>=" + timestamp_from + " and timestamp<=" + timestamp_to + getWhereClauseFor(activityTypes, provider) + ")";
    -        LOG.info("Activity query where: "+ where);
    +        LOG.info("Activity query where: " + where);
             final String order = "timestamp";
             try (SQLiteDatabase db = this.getReadableDatabase()) {
                 try (Cursor cursor = db.query(TABLE_GBACTIVITYSAMPLES, null, where, null, null, null, order)) {
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBAccess.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBAccess.java
    index 5899d2e0..ed42b28d 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBAccess.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBAccess.java
    @@ -4,9 +4,9 @@ import android.content.Context;
     import android.os.AsyncTask;
     import android.widget.Toast;
     
    -import nodomain.freeyourgadget.gadgetbridge.util.GB;
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
     import nodomain.freeyourgadget.gadgetbridge.R;
    +import nodomain.freeyourgadget.gadgetbridge.util.GB;
     
     public abstract class DBAccess extends AsyncTask {
         private final String mTask;
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java
    index fb42e7ff..7ea09634 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/database/DBHandler.java
    @@ -6,8 +6,8 @@ import android.database.sqlite.SQLiteOpenHelper;
     import java.util.List;
     
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    -import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
     import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
    +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
     
     public interface DBHandler {
         public SQLiteOpenHelper getHelper();
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java
    index 32f638ed..4c1568cf 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/EventHandler.java
    @@ -6,9 +6,9 @@ import android.support.annotation.Nullable;
     import java.util.ArrayList;
     import java.util.UUID;
     
    -import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand;
    -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind;
     import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
    +import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand;
     
     /**
      * Specifies all events that GadgetBridge intends to send to the gadget device.
    @@ -16,11 +16,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
      * Implementations need to send/encode event to the connected device.
      */
     public interface EventHandler {
    -    void onSMS(String from, String body);
    -
    -    void onEmail(String from, String subject, String body);
    -
    -    void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind);
    +    void onNotification(NotificationSpec notificationSpec);
     
         void onSetTime();
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/UnknownDeviceCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/UnknownDeviceCoordinator.java
    index e293f23a..d3c2bcc1 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/UnknownDeviceCoordinator.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/UnknownDeviceCoordinator.java
    @@ -4,11 +4,11 @@ import android.app.Activity;
     import android.content.Context;
     import android.net.Uri;
     
    -import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
     import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter;
     import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
    -import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
     import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
    +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
    +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
     
     public class UnknownDeviceCoordinator implements DeviceCoordinator {
         private final UnknownSampleProvider sampleProvider;
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java
    index eea1d008..ef98120f 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandCoordinator.java
    @@ -9,18 +9,16 @@ import android.preference.PreferenceManager;
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     
    -import java.io.IOException;
     import java.util.Calendar;
    -import java.util.GregorianCalendar;
     
    +import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    +import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
     import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
     import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
    -import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
    -import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
    -import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
    -import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
     import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
    +import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
    +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
     
     public class MiBandCoordinator implements DeviceCoordinator {
         private static final Logger LOG = LoggerFactory.getLogger(MiBandCoordinator.class);
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java
    index 8663921b..88a5e230 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandDateConverter.java
    @@ -13,6 +13,7 @@ public class MiBandDateConverter {
     
         /**
          * uses the standard algorithm to convert bytes received from the MiBand to a Calendar object
    +     *
          * @param value
          * @return
          */
    @@ -25,6 +26,7 @@ public class MiBandDateConverter {
     
         /**
          * uses the standard algorithm to convert bytes received from the MiBand to a Calendar object
    +     *
          * @param value
          * @return
          */
    @@ -46,6 +48,7 @@ public class MiBandDateConverter {
     
         /**
          * uses the standard algorithm to convert a Calendar object to a byte array to send to MiBand
    +     *
          * @param timestamp
          * @return
          */
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java
    index 0ef50ab7..64a177de 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandFWHelper.java
    @@ -12,7 +12,6 @@ import java.io.IOException;
     import java.io.InputStream;
     import java.util.Locale;
     
    -import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
     import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
     
     public class MiBandFWHelper {
    @@ -48,7 +47,7 @@ public class MiBandFWHelper {
                 throw new IOException("Firmware has a filename that looks like a Pebble app/firmware.");
             }
     
    -        try (InputStream in = new BufferedInputStream(cr.openInputStream(uri))){
    +        try (InputStream in = new BufferedInputStream(cr.openInputStream(uri))) {
                 this.fw = FileUtils.readAll(in, 1024 * 1024); // 1 MB
                 if (fw.length <= firmwareVersionMajor || fw[firmwareVersionMajor] != 1) {
                     throw new IOException("Firmware major version should be 1, probably this isn't a MiBand firmware.");
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java
    index ba756e49..1049f9d8 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPairingActivity.java
    @@ -13,12 +13,11 @@ import android.widget.TextView;
     import android.widget.Toast;
     
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    -import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
    +import nodomain.freeyourgadget.gadgetbridge.R;
     import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter;
    +import nodomain.freeyourgadget.gadgetbridge.activities.DiscoveryActivity;
     import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
     import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
    -import nodomain.freeyourgadget.gadgetbridge.R;
    -import nodomain.freeyourgadget.gadgetbridge.activities.DiscoveryActivity;
     
     public class MiBandPairingActivity extends Activity {
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java
    index fd16cf35..99ff144d 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandPreferencesActivity.java
    @@ -5,9 +5,9 @@ import android.os.Bundle;
     import android.preference.Preference;
     import android.support.v4.content.LocalBroadcastManager;
     
    -import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter;
     import nodomain.freeyourgadget.gadgetbridge.R;
     import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity;
    +import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter;
     
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_GENERIC;
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_INCOMING_CALL;
    @@ -15,8 +15,8 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.OR
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_PEBBLEMSG;
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_SMS;
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_ADDRESS;
    -import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_FITNESS_GOAL;
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_DONT_ACK_TRANSFER;
    +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_FITNESS_GOAL;
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_MIBAND_WEARSIDE;
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_USER_ALIAS;
     import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.PREF_USER_GENDER;
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandSampleProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandSampleProvider.java
    index 80405991..a2fc1dc7 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandSampleProvider.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandSampleProvider.java
    @@ -1,7 +1,7 @@
     package nodomain.freeyourgadget.gadgetbridge.devices.miband;
     
    -import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
     import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
    +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
     
     public class MiBandSampleProvider implements SampleProvider {
         public static final byte TYPE_DEEP_SLEEP = 5;
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandService.java
    index e436a290..29a2ec1f 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandService.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/miband/MiBandService.java
    @@ -179,12 +179,12 @@ public class MiBandService {
         */
     
         /* MODES: probably related to the sample data structure
    -	*/
    +    */
     
    -	public static final byte MODE_REGULAR_DATA_LEN_BYTE = 0x0;
    +    public static final byte MODE_REGULAR_DATA_LEN_BYTE = 0x0;
     
         // was MODE_REGULAR_DATA_LEN_MINITE
    -	public static final byte MODE_REGULAR_DATA_LEN_MINUTE = 0x1;
    +    public static final byte MODE_REGULAR_DATA_LEN_MINUTE = 0x1;
     
         /* PROFILE: unknown
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/MorpheuzSampleProvider.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/MorpheuzSampleProvider.java
    index 6ec7d153..e9bdf7a0 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/MorpheuzSampleProvider.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/pebble/MorpheuzSampleProvider.java
    @@ -1,7 +1,7 @@
     package nodomain.freeyourgadget.gadgetbridge.devices.pebble;
     
    -import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
     import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
    +import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
     
     public class MorpheuzSampleProvider implements SampleProvider {
         // raw types
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java
    index b68eb561..22d06fd4 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/BluetoothStateChangeReceiver.java
    @@ -10,7 +10,6 @@ import android.support.v4.content.LocalBroadcastManager;
     
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
     import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenter;
    -import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
     
     public class BluetoothStateChangeReceiver extends BroadcastReceiver {
         @Override
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java
    index 519020f0..c8bf1cd9 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/K9Receiver.java
    @@ -13,6 +13,8 @@ import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
     
     public class K9Receiver extends BroadcastReceiver {
     
    @@ -42,9 +44,9 @@ public class K9Receiver extends BroadcastReceiver {
                     "uri"
             };
     
    -        String sender = "";
    -        String subject = "";
    -        String preview = "";
    +        NotificationSpec notificationSpec = new NotificationSpec();
    +        notificationSpec.id = -1;
    +        notificationSpec.type = NotificationType.EMAIL;
     
             /*
              * there seems to be no way to specify the the uri in the where clause.
    @@ -57,14 +59,14 @@ public class K9Receiver extends BroadcastReceiver {
             do {
                 String uri = c.getString(c.getColumnIndex("uri"));
                 if (uri.equals(uriWanted)) {
    -                sender = c.getString(c.getColumnIndex("senderAddress"));
    -                subject = c.getString(c.getColumnIndex("subject"));
    -                preview = c.getString(c.getColumnIndex("preview"));
    +                notificationSpec.sender = c.getString(c.getColumnIndex("senderAddress"));
    +                notificationSpec.subject = c.getString(c.getColumnIndex("subject"));
    +                notificationSpec.body = c.getString(c.getColumnIndex("preview"));
                     break;
                 }
             } while (c.moveToNext());
             c.close();
     
    -        GBApplication.deviceService().onEmail(sender, subject, preview);
    +        GBApplication.deviceService().onNotification(notificationSpec);
         }
     }
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java
    index bb9f0839..371e33d4 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/MusicPlaybackReceiver.java
    @@ -3,8 +3,6 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents;
     import android.content.BroadcastReceiver;
     import android.content.Context;
     import android.content.Intent;
    -import android.content.SharedPreferences;
    -import android.preference.PreferenceManager;
     
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
    index 68214d6f..a9d0180b 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java
    @@ -22,7 +22,8 @@ import org.slf4j.LoggerFactory;
     import java.util.HashSet;
     
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
     import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
     
     public class NotificationListener extends NotificationListenerService {
    @@ -159,47 +160,45 @@ public class NotificationListener extends NotificationListenerService {
             }
     
             // Set application icons for generic notifications
    -        NotificationKind notificationKind;
    +        NotificationSpec notificationSpec = new NotificationSpec();
             switch (source) {
                 case "org.mariotaku.twidere":
                 case "com.twitter.android":
                 case "org.andstatus.app":
                 case "org.mustard.android":
    -                notificationKind = NotificationKind.TWITTER;
    +                notificationSpec.type = NotificationType.TWITTER;
                     break;
                 case "com.fsck.k9":
                 case "com.android.email":
    -                notificationKind = NotificationKind.EMAIL;
    +                notificationSpec.type = NotificationType.EMAIL;
                     break;
                 case "com.moez.QKSMS":
    -                notificationKind = NotificationKind.SMS;
    +                notificationSpec.type = NotificationType.SMS;
                     break;
                 case "eu.siacs.conversations":
    -                notificationKind = NotificationKind.CHAT;
    +                notificationSpec.type = NotificationType.CHAT;
                     break;
                 case "org.indywidualni.fblite":
    -                notificationKind = NotificationKind.FACEBOOK;
    +                notificationSpec.type = NotificationType.FACEBOOK;
                     break;
                 default:
    -                notificationKind = NotificationKind.UNDEFINED;
    +                notificationSpec.type = NotificationType.UNDEFINED;
                     break;
             }
     
             LOG.info("Processing notification from source " + source);
     
             Bundle extras = notification.extras;
    -        String title = extras.getCharSequence(Notification.EXTRA_TITLE).toString();
    -        String content = null;
    +        notificationSpec.title = extras.getCharSequence(Notification.EXTRA_TITLE).toString();
             if (extras.containsKey(Notification.EXTRA_TEXT)) {
                 CharSequence contentCS = extras.getCharSequence(Notification.EXTRA_TEXT);
                 if (contentCS != null) {
    -                content = contentCS.toString();
    +                notificationSpec.body = contentCS.toString();
                 }
             }
     
    -        if (content != null) {
    -            GBApplication.deviceService().onGenericNotification(title, content, (int) sbn.getPostTime(), notificationKind); //FIMXE: a truly unique id would be better
    -        }
    +        notificationSpec.id = (int) sbn.getPostTime(); //FIMXE: a truly unique id would be better
    +        GBApplication.deviceService().onNotification(notificationSpec);
         }
     
         private boolean isServiceRunning() {
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java
    index ab408429..f24fe593 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java
    @@ -13,7 +13,8 @@ import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
     
     public class PebbleReceiver extends BroadcastReceiver {
     
    @@ -33,9 +34,6 @@ public class PebbleReceiver extends BroadcastReceiver {
                 }
             }
     
    -        String title;
    -        String body;
    -
             String messageType = intent.getStringExtra("messageType");
             if (!messageType.equals("PEBBLE_ALERT")) {
                 LOG.info("non PEBBLE_ALERT message type not supported");
    @@ -47,24 +45,25 @@ public class PebbleReceiver extends BroadcastReceiver {
                 return;
             }
     
    +        NotificationSpec notificationSpec = new NotificationSpec();
     
             String notificationData = intent.getStringExtra("notificationData");
             try {
                 JSONArray notificationJSON = new JSONArray(notificationData);
    -            title = notificationJSON.getJSONObject(0).getString("title");
    -            body = notificationJSON.getJSONObject(0).getString("body");
    +            notificationSpec.title = notificationJSON.getJSONObject(0).getString("title");
    +            notificationSpec.body = notificationJSON.getJSONObject(0).getString("body");
             } catch (JSONException e) {
                 e.printStackTrace();
                 return;
             }
     
    -        if (title != null && body != null) {
    -            NotificationKind notificationKind = NotificationKind.UNDEFINED;
    +        if (notificationSpec.title != null) {
    +            notificationSpec.type = NotificationType.UNDEFINED;
                 String sender = intent.getStringExtra("sender");
                 if ("Conversations".equals(sender)) {
    -                notificationKind = NotificationKind.CHAT;
    +                notificationSpec.type = NotificationType.CHAT;
                 }
    -            GBApplication.deviceService().onGenericNotification(title, body, -1, notificationKind);
    +            GBApplication.deviceService().onNotification(notificationSpec);
             }
         }
     }
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java
    index 72cff999..13e80c6c 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/SMSReceiver.java
    @@ -10,6 +10,8 @@ import android.preference.PreferenceManager;
     import android.telephony.SmsMessage;
     
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
     
     public class SMSReceiver extends BroadcastReceiver {
     
    @@ -27,16 +29,20 @@ public class SMSReceiver extends BroadcastReceiver {
                 }
             }
     
    +        NotificationSpec notificationSpec = new NotificationSpec();
    +        notificationSpec.id = -1;
    +        notificationSpec.type = NotificationType.SMS;
    +
             Bundle bundle = intent.getExtras();
             if (bundle != null) {
                 Object[] pdus = (Object[]) bundle.get("pdus");
                 for (Object pdu1 : pdus) {
                     byte[] pdu = (byte[]) pdu1;
                     SmsMessage message = SmsMessage.createFromPdu(pdu);
    -                String body = message.getDisplayMessageBody();
    -                String sender = message.getOriginatingAddress();
    -                if (sender != null && body != null) {
    -                    GBApplication.deviceService().onSMS(sender, body);
    +                notificationSpec.body = message.getDisplayMessageBody();
    +                notificationSpec.phoneNumber = message.getOriginatingAddress();
    +                if (notificationSpec.phoneNumber != null) {
    +                    GBApplication.deviceService().onNotification(notificationSpec);
                     }
                 }
             }
    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 429414c3..a0292e88 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDevice.java
    @@ -9,10 +9,10 @@ import android.support.v4.content.LocalBroadcastManager;
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     
    -import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
    -import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
     import nodomain.freeyourgadget.gadgetbridge.R;
    +import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
    +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
     
     public class GBDevice implements Parcelable {
         public static final String ACTION_DEVICE_CHANGED
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java
    index 3d65a98c..62f77297 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceCandidate.java
    @@ -4,9 +4,9 @@ import android.bluetooth.BluetoothDevice;
     import android.os.Parcel;
     import android.os.Parcelable;
     
    -import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
     import nodomain.freeyourgadget.gadgetbridge.GBApplication;
     import nodomain.freeyourgadget.gadgetbridge.R;
    +import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
     
     /**
      */
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java
    index 3b28a0d4..aa14cf84 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/impl/GBDeviceService.java
    @@ -11,7 +11,7 @@ import java.util.UUID;
     
     import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
     import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
    -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
     import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand;
     import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
     
    @@ -80,29 +80,16 @@ public class GBDeviceService implements DeviceService {
         }
     
         @Override
    -    public void onSMS(String from, String body) {
    -        Intent intent = createIntent().setAction(ACTION_NOTIFICATION_SMS)
    -                .putExtra(EXTRA_NOTIFICATION_SENDER, from)
    -                .putExtra(EXTRA_NOTIFICATION_BODY, body);
    -        invokeService(intent);
    -    }
    -
    -    @Override
    -    public void onEmail(String from, String subject, String body) {
    -        Intent intent = createIntent().setAction(ACTION_NOTIFICATION_EMAIL)
    -                .putExtra(EXTRA_NOTIFICATION_SENDER, from)
    -                .putExtra(EXTRA_NOTIFICATION_SUBJECT, subject)
    -                .putExtra(EXTRA_NOTIFICATION_BODY, body);
    -        invokeService(intent);
    -    }
    -
    -    @Override
    -    public void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind) {
    -        Intent intent = createIntent().setAction(ACTION_NOTIFICATION_GENERIC)
    -                .putExtra(EXTRA_NOTIFICATION_TITLE, title)
    -                .putExtra(EXTRA_NOTIFICATION_BODY, details)
    -                .putExtra(EXTRA_NOTIFICATION_HANDLE, handle)
    -                .putExtra(EXTRA_NOTIFICATION_KIND, notificationKind);
    +    public void onNotification(NotificationSpec notificationSpec) {
    +        Intent intent = createIntent().setAction(ACTION_NOTIFICATION)
    +                .putExtra(EXTRA_NOTIFICATION_PHONENUMBER, notificationSpec.phoneNumber)
    +                .putExtra(EXTRA_NOTIFICATION_SENDER, notificationSpec.sender)
    +                .putExtra(EXTRA_NOTIFICATION_SUBJECT, notificationSpec.subject)
    +                .putExtra(EXTRA_NOTIFICATION_TITLE, notificationSpec.title)
    +                .putExtra(EXTRA_NOTIFICATION_BODY, notificationSpec.body)
    +                .putExtra(EXTRA_NOTIFICATION_ID, notificationSpec.id)
    +                .putExtra(EXTRA_NOTIFICATION_TYPE, notificationSpec.type)
    +                .putExtra(EXTRA_NOTIFICATION_SOURCENAME, notificationSpec.sourceName);
             invokeService(intent);
         }
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityAmount.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityAmount.java
    index 4507a8d7..7726be44 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityAmount.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityAmount.java
    @@ -2,8 +2,6 @@ package nodomain.freeyourgadget.gadgetbridge.model;
     
     import android.content.Context;
     
    -import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
    -
     public class ActivityAmount {
         private int activityKind;
         private short percent;
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java
    index 62fdb4ed..9a9be0b3 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/DeviceService.java
    @@ -13,9 +13,8 @@ public interface DeviceService extends EventHandler {
     
         static final String ACTION_START = PREFIX + ".action.start";
         static final String ACTION_CONNECT = PREFIX + ".action.connect";
    -    static final String ACTION_NOTIFICATION_GENERIC = PREFIX + ".action.notification_generic";
    +    static final String ACTION_NOTIFICATION = PREFIX + ".action.notification";
         static final String ACTION_NOTIFICATION_SMS = PREFIX + ".action.notification_sms";
    -    static final String ACTION_NOTIFICATION_EMAIL = PREFIX + ".action.notification_email";
         static final String ACTION_CALLSTATE = PREFIX + ".action.callstate";
         static final String ACTION_SETTIME = PREFIX + ".action.settime";
         static final String ACTION_SETMUSICINFO = PREFIX + ".action.setmusicinfo";
    @@ -32,12 +31,14 @@ public interface DeviceService extends EventHandler {
         static final String ACTION_SET_ALARMS = PREFIX + ".action.set_alarms";
     
         static final String EXTRA_DEVICE_ADDRESS = "device_address";
    -    static final String EXTRA_NOTIFICATION_TITLE = "notification_title";
         static final String EXTRA_NOTIFICATION_BODY = "notification_body";
    +    static final String EXTRA_NOTIFICATION_ID = "notification_id";
    +    static final String EXTRA_NOTIFICATION_PHONENUMBER = "notification_phonenumber";
         static final String EXTRA_NOTIFICATION_SENDER = "notification_sender";
    +    static final String EXTRA_NOTIFICATION_SOURCENAME = "notification_sourcename";
         static final String EXTRA_NOTIFICATION_SUBJECT = "notification_subject";
    -    static final String EXTRA_NOTIFICATION_HANDLE = "notification_handle";
    -    static final String EXTRA_NOTIFICATION_KIND = "notificationKind";
    +    static final String EXTRA_NOTIFICATION_TITLE = "notification_title";
    +    static final String EXTRA_NOTIFICATION_TYPE = "notification_type";
         static final String EXTRA_FIND_START = "find_start";
         static final String EXTRA_CALL_COMMAND = "call_command";
         static final String EXTRA_CALL_PHONENUMBER = "call_phonenumber";
    @@ -51,15 +52,18 @@ public interface DeviceService extends EventHandler {
         static final String EXTRA_PERFORM_PAIR = "perform_pair";
     
     
    -
         void start();
     
         void connect();
    +
         void connect(@Nullable String deviceAddress);
    +
         void connect(@Nullable String deviceAddress, boolean performPair);
    +
         void disconnect();
     
         void quit();
    +
         /**
          * Requests information from the {@link DeviceCommunicationService} about the connection state,
          * firmware info, etc.
    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 1fe0313d..dcb76883 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ItemWithDetails.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ItemWithDetails.java
    @@ -2,6 +2,8 @@ package nodomain.freeyourgadget.gadgetbridge.model;
     
     public interface ItemWithDetails {
         String getName();
    +
         String getDetails();
    +
         int getIcon();
     }
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationSpec.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationSpec.java
    new file mode 100644
    index 00000000..e29a30d8
    --- /dev/null
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationSpec.java
    @@ -0,0 +1,12 @@
    +package nodomain.freeyourgadget.gadgetbridge.model;
    +
    +public class NotificationSpec {
    +    public int id;
    +    public String sender;
    +    public String phoneNumber;
    +    public String title;
    +    public String subject;
    +    public String body;
    +    public NotificationType type;
    +    public String sourceName;
    +}
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java
    similarity index 80%
    rename from app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java
    rename to app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java
    index 3005a3a6..63feca89 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationKind.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/NotificationType.java
    @@ -1,6 +1,6 @@
     package nodomain.freeyourgadget.gadgetbridge.model;
     
    -public enum NotificationKind {
    +public enum NotificationType {
     
         UNDEFINED,
     
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java
    index 27d81e9d..7e7f2550 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceCommunicationService.java
    @@ -26,7 +26,8 @@ import java.util.UUID;
     import nodomain.freeyourgadget.gadgetbridge.R;
     import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
     import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
    -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
    +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
     import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand;
     import nodomain.freeyourgadget.gadgetbridge.util.GB;
     
    @@ -37,9 +38,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DI
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_FETCH_ACTIVITY_DATA;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_FIND_DEVICE;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_INSTALL;
    -import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_NOTIFICATION_EMAIL;
    -import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_NOTIFICATION_GENERIC;
    -import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_NOTIFICATION_SMS;
    +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_NOTIFICATION;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_REBOOT;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_REQUEST_APPINFO;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_REQUEST_DEVICEINFO;
    @@ -60,11 +59,13 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUS
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_ARTIST;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_TRACK;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_BODY;
    -import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_HANDLE;
    -import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_KIND;
    +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_ID;
    +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_PHONENUMBER;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_SENDER;
    +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_SOURCENAME;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_SUBJECT;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_TITLE;
    +import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_TYPE;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_PERFORM_PAIR;
     import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_URI;
     
    @@ -180,26 +181,20 @@ public class DeviceCommunicationService extends Service {
                 case ACTION_REQUEST_DEVICEINFO:
                     mGBDevice.sendDeviceUpdateIntent(this);
                     break;
    -            case ACTION_NOTIFICATION_GENERIC: {
    -                String title = intent.getStringExtra(EXTRA_NOTIFICATION_TITLE);
    -                String body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY);
    -                int handle = intent.getIntExtra(EXTRA_NOTIFICATION_HANDLE, -1);
    -                NotificationKind notificationKind = (NotificationKind) intent.getSerializableExtra(EXTRA_NOTIFICATION_KIND);
    -                mDeviceSupport.onGenericNotification(title, body, handle, notificationKind);
    -                break;
    -            }
    -            case ACTION_NOTIFICATION_SMS: {
    -                String sender = intent.getStringExtra(EXTRA_NOTIFICATION_SENDER);
    -                String body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY);
    -                String senderName = getContactDisplayNameByNumber(sender);
    -                mDeviceSupport.onSMS(senderName, body);
    -                break;
    -            }
    -            case ACTION_NOTIFICATION_EMAIL: {
    -                String sender = intent.getStringExtra(EXTRA_NOTIFICATION_SENDER);
    -                String subject = intent.getStringExtra(EXTRA_NOTIFICATION_SUBJECT);
    -                String body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY);
    -                mDeviceSupport.onEmail(sender, subject, body);
    +            case ACTION_NOTIFICATION: {
    +                NotificationSpec notificationSpec = new NotificationSpec();
    +                notificationSpec.phoneNumber = intent.getStringExtra(EXTRA_NOTIFICATION_PHONENUMBER);
    +                notificationSpec.sender = intent.getStringExtra(EXTRA_NOTIFICATION_SENDER);
    +                notificationSpec.subject = intent.getStringExtra(EXTRA_NOTIFICATION_SUBJECT);
    +                notificationSpec.title = intent.getStringExtra(EXTRA_NOTIFICATION_TITLE);
    +                notificationSpec.body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY);
    +                notificationSpec.type = (NotificationType) intent.getSerializableExtra(EXTRA_NOTIFICATION_TYPE);
    +                notificationSpec.id = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
    +                notificationSpec.sourceName = intent.getStringExtra(EXTRA_NOTIFICATION_SOURCENAME);
    +                if (notificationSpec.type == NotificationType.SMS && notificationSpec.phoneNumber != null) {
    +                    notificationSpec.sender = getContactDisplayNameByNumber(notificationSpec.phoneNumber);
    +                }
    +                mDeviceSupport.onNotification(notificationSpec);
                     break;
                 }
                 case ACTION_REBOOT: {
    diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupport.java
    index a76285c1..bce4e64b 100644
    --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupport.java
    +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupport.java
    @@ -22,14 +22,16 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
     public interface DeviceSupport extends EventHandler {
         /**
          * Sets all context information needed for the instance to operate.
    -     * @param gbDevice the device to operate with
    +     *
    +     * @param gbDevice  the device to operate with
          * @param btAdapter the bluetooth adapter to use
    -     * @param context the android context, e.g. to look up resources
    +     * @param context   the android context, e.g. to look up resources
          */
         void setContext(GBDevice gbDevice, BluetoothAdapter btAdapter, Context context);
     
         /**
          * Returns whether a transport-level connection is established with the device
    +     *
          * @return whether the device is connected with the system running this software
          */
         boolean isConnected();
    @@ -40,9 +42,10 @@ public interface DeviceSupport extends EventHandler {
          * Returns true if a connection attempt was made. If the implementation is synchronous
          * it may also return true if the connection was successfully established, however
          * callers shall not rely on that.
    -     *
    +     * 

    * The actual connection state change (successful or not) will be reported via the * #getDevice device as a device change Intent. + * * @see GBDevice#ACTION_DEVICE_CHANGED */ boolean connect(); @@ -62,6 +65,7 @@ public interface DeviceSupport extends EventHandler { /** * Attempts to pair and connect this device with the gadget device. Success * will be reported via a device change Intent. + * * @see GBDevice#ACTION_DEVICE_CHANGED */ void pair(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java index 3a0606e2..8b79b819 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/ServiceDeviceSupport.java @@ -13,8 +13,8 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; /** * Wraps another device support instance and supports busy-checking and throttling of events. @@ -25,6 +25,7 @@ public class ServiceDeviceSupport implements DeviceSupport { THROTTLING, BUSY_CHECKING, } + private static final Logger LOG = LoggerFactory.getLogger(ServiceDeviceSupport.class); private static final long THROTTLING_THRESHOLD = 1000; // throttle multiple events in between one second @@ -112,27 +113,11 @@ public class ServiceDeviceSupport implements DeviceSupport { } @Override - public void onSMS(String from, String body) { - if (checkBusy("sms") || checkThrottle("sms")) { - return; - } - delegate.onSMS(from, body); - } - - @Override - public void onEmail(String from, String subject, String body) { - if (checkBusy("email") || checkThrottle("email")) { - return; - } - delegate.onEmail(from, subject, body); - } - - @Override - public void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { + public void onNotification(NotificationSpec notificationSpec) { if (checkBusy("generic notification") || checkThrottle("generic notification")) { return; } - delegate.onGenericNotification(title, details, handle, notificationKind); + delegate.onNotification(notificationSpec); } @Override diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java index 3fe5aa69..165a72cb 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEOperation.java @@ -14,10 +14,10 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; * Abstract base class for a BTLEOperation, i.e. an operation that does more than * just sending a few bytes to the device. It typically involves exchanging many messages * between the mobile and the device. - * + *

    * One operation may execute multiple @{link Transaction transactions} with each * multiple @{link BTLEAction actions}. - * + *

    * This class implements GattCallback so that subclasses may override those methods * to handle those events. * Note: by default all Gatt events are forwarded to AbstractBTLEDeviceSupport, subclasses may override @@ -33,6 +33,7 @@ public abstract class AbstractBTLEOperation /** * Delegates to the DeviceSupport instance and additionally sets this instance as the Gatt * callback for the transaction. + * * @param taskName * @return * @throws IOException diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BTLEOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BTLEOperation.java index 3b64e3d8..f1c57d3d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BTLEOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BTLEOperation.java @@ -2,8 +2,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.btle; import java.io.IOException; -import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.MiBandSupport; - public interface BTLEOperation { public void perform() throws IOException; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java index f8d2a5dd..84898961 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/BtLEQueue.java @@ -207,6 +207,7 @@ public final class BtLEQueue { /** * Depending on certain criteria, connects to the BluetoothGatt. + * * @return true if a reconnection attempt was made, or false otherwise */ private boolean maybeReconnect() { @@ -275,7 +276,9 @@ public final class BtLEQueue { // Implements callback methods for GATT events that the app cares about. For example, // connection change and services discovered. private final class InternalGattCallback extends BluetoothGattCallback { - private @Nullable GattCallback mTransactionGattCallback; + private + @Nullable + GattCallback mTransactionGattCallback; private GattCallback mExternalGattCallback; public InternalGattCallback(GattCallback externalGattCallback) { @@ -449,5 +452,7 @@ public final class BtLEQueue { } mTransactionGattCallback = null; } - }; + } + + ; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/Transaction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/Transaction.java index 4006e1cd..1fccb528 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/Transaction.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/Transaction.java @@ -19,7 +19,9 @@ public class Transaction { private String mName; private List mActions = new ArrayList<>(4); private long creationTimestamp = System.currentTimeMillis(); - private @Nullable GattCallback gattCallback; + private + @Nullable + GattCallback gattCallback; public Transaction(String taskName) { this.mName = taskName; @@ -57,7 +59,9 @@ public class Transaction { /** * Returns the GattCallback for this transaction, or null if none. */ - public @Nullable GattCallback getGattCallback() { + public + @Nullable + GattCallback getGattCallback() { return gattCallback; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/TransactionBuilder.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/TransactionBuilder.java index 85eb3da6..90efe84b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/TransactionBuilder.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/TransactionBuilder.java @@ -64,13 +64,16 @@ public class TransactionBuilder { /** * Sets a GattCallback instance that will be called when the transaction is executed, * resulting in GattCallback events. + * * @param callback the callback to set, may be null */ public void setGattCallback(@Nullable GattCallback callback) { mTransaction.setGattCallback(callback); } - public @Nullable GattCallback getGattCallback() { + public + @Nullable + GattCallback getGattCallback() { return mTransaction.getGattCallback(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/SetProgressAction.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/SetProgressAction.java index 95c94d3e..8312b5fd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/SetProgressAction.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/actions/SetProgressAction.java @@ -14,6 +14,7 @@ public class SetProgressAction extends PlainAction { /** * When run, will update the progress notification. + * * @param text * @param ongoing * @param percentage diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java index 1bb6a33c..c866b784 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/BatteryInfo.java @@ -11,7 +11,7 @@ public class BatteryInfo extends AbstractInfo { public static final byte DEVICE_BATTERY_CHARGING = 2; public static final byte DEVICE_BATTERY_CHARGING_FULL = 3; public static final byte DEVICE_BATTERY_CHARGE_OFF = 4; - + public BatteryInfo(byte[] data) { super(data); } 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 c75586bb..0261e03d 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 @@ -28,8 +28,8 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandService; import nodomain.freeyourgadget.gadgetbridge.devices.miband.VibrationProfile; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice.State; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport; import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEAction; import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder; @@ -54,6 +54,7 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.FL import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.FLASH_ORIGINAL_COLOUR; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_GENERIC; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_K9MAIL; +import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_PEBBLEMSG; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ORIGIN_SMS; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.VIBRATION_COUNT; import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.VIBRATION_DURATION; @@ -402,18 +403,21 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { } @Override - public void onSMS(String from, String body) { - performPreferredNotification("sms received", ORIGIN_SMS, null); - } - - @Override - public void onEmail(String from, String subject, String body) { - performPreferredNotification("email received", ORIGIN_K9MAIL, null); - } - - @Override - public void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { - performPreferredNotification("generic notification received", ORIGIN_GENERIC, null); + public void onNotification(NotificationSpec notificationSpec) { + // FIXME: these ORIGIN contants do not really make sense anymore + switch (notificationSpec.type) { + case SMS: + performPreferredNotification("sms received", ORIGIN_SMS, null); + break; + case EMAIL: + performPreferredNotification("email received", ORIGIN_K9MAIL, null); + break; + case CHAT: + performPreferredNotification("chat message received", ORIGIN_PEBBLEMSG, null); + break; + default: + performPreferredNotification("generic notification received", ORIGIN_GENERIC, null); + } } @Override @@ -598,7 +602,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport { handleBatteryInfo(characteristic.getValue(), BluetoothGatt.GATT_SUCCESS); } else if (MiBandService.UUID_CHARACTERISTIC_NOTIFICATION.equals(characteristicUUID)) { handleNotificationNotif(characteristic.getValue()); - } else{ + } else { LOG.info("Unhandled characteristic changed: " + characteristicUUID); } } 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 f89fd2f1..486d3e41 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 @@ -151,12 +151,11 @@ public class FetchActivityOperation extends AbstractBTLEOperation * There are two kind of messages we currently know: * - the first one is 11 bytes long and contains metadata (how many bytes to expect, when the data starts, etc.) * - the second one is 20 bytes long and contains the actual activity data - * + *

    * The first message type is parsed by this method, for every other length of the value param, bufferActivityData is called. - * @see #bufferActivityData(byte[]) - * * * @param value + * @see #bufferActivityData(byte[]) */ private void handleActivityNotif(byte[] value) { if (value.length == 11) { @@ -205,7 +204,7 @@ public class FetchActivityOperation extends AbstractBTLEOperation /** * Method to store temporarily the activity data values got from the Mi Band. - * + *

    * Since we expect chunks of 20 bytes each, we do not store the received bytes it the length is different. * * @param value @@ -275,7 +274,7 @@ public class FetchActivityOperation extends AbstractBTLEOperation /** * Acknowledge the transfer of activity data to the Mi Band. - * + *

    * After receiving data from the band, it has to be acknowledged. This way the Mi Band will delete * the data it has on record. * diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java index 01c1798e..0d7c71d6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/miband/operations/UpdateFirmwareOperation.java @@ -72,21 +72,21 @@ public class UpdateFirmwareOperation extends AbstractBTLEOperation * Upon receiving known values that request further action by GB, the appropriate method is called. * * @param value */ private void handleNotificationNotif(byte[] value) { - if(value.length != 1) { + if (value.length != 1) { LOG.error("Notifications should be 1 byte long."); getSupport().logMessageContent(value); return; } switch (value[0]) { case MiBandService.NOTIFY_FW_CHECK_SUCCESS: - if(firmwareInfoSent && newFirmware != null) { - if(sendFirmwareData(newFirmware)) { + if (firmwareInfoSent && newFirmware != null) { + if (sendFirmwareData(newFirmware)) { rebootWhenBandReady = true; } else { //TODO: the firmware transfer failed, but the miband should be still functional with the old firmware. What should we do? @@ -131,14 +131,14 @@ public class UpdateFirmwareOperation extends AbstractBTLEOperation * The Mi Band will send a notification after receiving these data to confirm if the metadata looks good to it. - * @see MiBandSupport#handleNotificationNotif * * @param currentFwVersion * @param newFwVersion * @param newFwSize * @param checksum + * @see MiBandSupport#handleNotificationNotif */ private void sendFirmwareInfo(int currentFwVersion, int newFwVersion, int newFwSize, int checksum) throws IOException { byte[] fwInfo = new byte[]{ @@ -165,13 +165,13 @@ public class UpdateFirmwareOperation extends AbstractBTLEOperation * The Mi Band will send a notification after receiving these data to confirm if the firmware looks good to it. - * @see MiBandSupport#handleNotificationNotif * * @param fwbytes * @return whether the transfer succeeded or not. Only a BT layer exception will cause the transmission to fail. - * */ + * @see MiBandSupport#handleNotificationNotif + */ private boolean sendFirmwareData(byte fwbytes[]) { int len = fwbytes.length; final int packetLength = 20; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 87dde6e5..523b467e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -30,7 +30,8 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInf import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleIconID; import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol; @@ -384,7 +385,21 @@ public class PebbleProtocol extends GBDeviceProtocol { return buf.array(); } - private byte[] encodeNotification(int id, String title, String subtitle, String body, byte type, boolean hasHandle, NotificationKind notificationKind) { + @Override + public byte[] encodeNotification(NotificationSpec notificationSpec) { + boolean hasHandle = notificationSpec.id != -1; + int id = notificationSpec.id != -1 ? notificationSpec.id : mRandom.nextInt(); + String title; + String subtitle = null; + + // for SMS and EMAIL that came in though SMS or K9 receiver + if (notificationSpec.sender != null) { + title = notificationSpec.sender; + subtitle = notificationSpec.subject; + } else { + title = notificationSpec.title; + } + Long ts = System.currentTimeMillis(); if (!isFw3x) { ts += (SimpleTimeZone.getDefault().getOffset(ts)); @@ -394,33 +409,18 @@ public class PebbleProtocol extends GBDeviceProtocol { if (isFw3x) { // 3.x notification //return encodeTimelinePin(id, (int) ((ts + 600) & 0xffffffffL), (short) 90, PebbleIconID.TIMELINE_CALENDAR, title); // really, this is just for testing - return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, body, type, hasHandle, notificationKind); - } else if (mForceProtocol || type != NOTIFICATION_EMAIL) { + return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, hasHandle, notificationSpec.type); + } else if (mForceProtocol || notificationSpec.type != NotificationType.EMAIL) { // 2.x notification - return encodeExtensibleNotification(id, (int) (ts & 0xffffffffL), title, subtitle, body, type, hasHandle); + return encodeExtensibleNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, hasHandle); } else { // 1.x notification on FW 2.X - String[] parts = {title, body, ts.toString(), subtitle}; + String[] parts = {title, notificationSpec.body, ts.toString(), subtitle}; // be aware that type is at this point always NOTIFICATION_EMAIL - return encodeMessage(ENDPOINT_NOTIFICATION, type, 0, parts); + return encodeMessage(ENDPOINT_NOTIFICATION, NOTIFICATION_EMAIL, 0, parts); } } - @Override - public byte[] encodeSMS(String from, String body) { - return encodeNotification(mRandom.nextInt(), from, null, body, NOTIFICATION_SMS, false, NotificationKind.UNDEFINED); - } - - @Override - public byte[] encodeEmail(String from, String subject, String body) { - return encodeNotification(mRandom.nextInt(), from, subject, body, NOTIFICATION_EMAIL, false, NotificationKind.UNDEFINED); - } - - @Override - public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { - return encodeNotification(handle != -1 ? handle : mRandom.nextInt(), title, null, details, NOTIFICATION_UNDEFINED, handle != -1, notificationKind); - } - @Override public byte[] encodeSetTime() { long ts = System.currentTimeMillis(); @@ -455,7 +455,7 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeSetCallState("Where are you?", "Gadgetbridge", start ? ServiceCommand.CALL_INCOMING : ServiceCommand.CALL_END); } - private static byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, byte type, boolean hasHandle) { + private static byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, boolean hasHandle) { final short ACTION_LENGTH_MIN = 10; String[] parts = {title, subtitle, body}; @@ -619,7 +619,7 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array()); } - private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, byte type, boolean hasHandle, NotificationKind notificationKind) { + private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, boolean hasHandle, NotificationType notificationType) { final short NOTIFICATION_PIN_LENGTH = 46; final short ACTION_LENGTH_MIN = 10; @@ -627,17 +627,17 @@ public class PebbleProtocol extends GBDeviceProtocol { int icon_id; byte color_id; - switch (type) { - case NOTIFICATION_EMAIL: + switch (notificationType) { + case EMAIL: icon_id = PebbleIconID.GENERIC_EMAIL; color_id = PebbleColor.JaegerGreen; break; - case NOTIFICATION_SMS: + case SMS: icon_id = PebbleIconID.GENERIC_SMS; color_id = PebbleColor.VividViolet; break; default: - switch (notificationKind) { + switch (notificationType) { case TWITTER: icon_id = PebbleIconID.NOTIFICATION_TWITTER; color_id = PebbleColor.BlueMoon; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/WeatherNeatSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/WeatherNeatSupport.java index cd6c5bb9..fc2fc1c2 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/WeatherNeatSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/WeatherNeatSupport.java @@ -51,6 +51,6 @@ public class WeatherNeatSupport { public GBDeviceEvent[] handleMessage(ArrayList> pairs) { GBDeviceEventSendBytes sendBytes = new GBDeviceEventSendBytes(); sendBytes.encodedBytes = encodeWeatherNeatMessage("Berlin", "22 C", "cloudy", 0); - return new GBDeviceEvent[] {sendBytes}; + return new GBDeviceEvent[]{sendBytes}; } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java index 2249f462..84ea9c33 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/AbstractSerialDeviceSupport.java @@ -8,7 +8,7 @@ import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes; import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; @@ -108,20 +108,8 @@ public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport } @Override - public void onSMS(String from, String body) { - byte[] bytes = gbDeviceProtocol.encodeSMS(from, body); - sendToDevice(bytes); - } - - @Override - public void onEmail(String from, String subject, String body) { - byte[] bytes = gbDeviceProtocol.encodeEmail(from, subject, body); - sendToDevice(bytes); - } - - @Override - public void onGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { - byte[] bytes = gbDeviceProtocol.encodeGenericNotification(title, details, handle, notificationKind); + public void onNotification(NotificationSpec notificationSpec) { + byte[] bytes = gbDeviceProtocol.encodeNotification(notificationSpec); sendToDevice(bytes); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java index 971e02d6..e99b03ab 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/serial/GBDeviceProtocol.java @@ -3,20 +3,12 @@ package nodomain.freeyourgadget.gadgetbridge.service.serial; import java.util.UUID; import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; public abstract class GBDeviceProtocol { - public byte[] encodeSMS(String from, String body) { - return null; - } - - public byte[] encodeEmail(String from, String subject, String body) { - return null; - } - - public byte[] encodeGenericNotification(String title, String details, int handle, NotificationKind notificationKind) { + public byte[] encodeNotification(NotificationSpec notificationSpec) { return null; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java index 960cb5c4..c2ebea51 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DeviceHelper.java @@ -5,10 +5,10 @@ import java.util.List; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.UnknownDeviceCoordinator; -import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; -import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleCoordinator; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; +import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate; public class DeviceHelper { private static DeviceHelper instance = new DeviceHelper(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java index b2631f13..e9c1f396 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/FileUtils.java @@ -51,7 +51,8 @@ public class FileUtils { * Reads the contents of the given InputStream into a byte array, but does not * read more than maxLen bytes. If the stream provides more than maxLen bytes, * an IOException is thrown. - * @param in the stream to read from + * + * @param in the stream to read from * @param maxLen the maximum number of bytes to read/return * @return the bytes read from the InputStream * @throws IOException when reading failed or when maxLen was exceeded diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index 1a1eddb6..5af7227e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -355,7 +355,7 @@ public class GB { notificationIntent, 0); NotificationCompat.Builder nb = new NotificationCompat.Builder(context) - .setContentTitle( context.getString(R.string.notif_battery_low_title)) + .setContentTitle(context.getString(R.string.notif_battery_low_title)) .setContentText(text) .setContentIntent(pendingIntent) .setSmallIcon(R.drawable.ic_notification_low_battery) From 94ad7f2eb957569ac12d79b12f665254806df54b Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Thu, 24 Sep 2015 17:26:40 +0200 Subject: [PATCH 66/73] set type to SMS when receiving an SMS via generic notification listener --- .../gadgetbridge/externalevents/NotificationListener.java | 1 + .../gadgetbridge/externalevents/PebbleReceiver.java | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index a9d0180b..c2da97c7 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -173,6 +173,7 @@ public class NotificationListener extends NotificationListenerService { notificationSpec.type = NotificationType.EMAIL; break; case "com.moez.QKSMS": + case "com.android.mms": notificationSpec.type = NotificationType.SMS; break; case "eu.siacs.conversations": diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java index f24fe593..01dab88f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/PebbleReceiver.java @@ -46,6 +46,7 @@ public class PebbleReceiver extends BroadcastReceiver { } NotificationSpec notificationSpec = new NotificationSpec(); + notificationSpec.id = -1; String notificationData = intent.getStringExtra("notificationData"); try { From e3533a2b18e248121f184c664a1fe0025cf327eb Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Fri, 25 Sep 2015 00:53:40 +0200 Subject: [PATCH 67/73] Pebble: Allow muting (blacklisting) Apps from within generic notifications on the watch Closes #113 --- CHANGELOG.md | 1 + .../gadgetbridge/GBApplication.java | 40 ++++++++- .../activities/AppBlacklistActivity.java | 41 +-------- .../GBDeviceEventNotificationControl.java | 3 +- .../externalevents/NotificationListener.java | 89 ++++++++++++------- .../service/AbstractDeviceSupport.java | 3 + .../devices/pebble/PebbleProtocol.java | 66 ++++++++++---- .../freeyourgadget/gadgetbridge/util/GB.java | 2 +- 8 files changed, 158 insertions(+), 87 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 372b1956..a70bdfb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ###Changelog ####Next Version +* Pebble: Allow muting (blacklisting) Apps from within generic notifications on the watch * Pebble: Detect all known Pebble Versions including new "chalk" platform (Pebble Time Round) * Option to ignore phone calls (useful for Pebble Dialer) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index 91cc0a97..e3cb2d6f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -13,6 +13,7 @@ import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; +import java.util.HashSet; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -31,6 +32,7 @@ public class GBApplication extends Application { private static ActivityDatabaseHandler mActivityDatabaseHandler; private static final Lock dbLock = new ReentrantLock(); private static DeviceService deviceService; + private static SharedPreferences sharedPrefs; public GBApplication() { context = this; @@ -46,6 +48,8 @@ public class GBApplication extends Application { public void onCreate() { super.onCreate(); + sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context); + // don't do anything here before we set up logging, otherwise // slf4j may be implicitly initialized before we properly configured it. setupLogging(); @@ -57,14 +61,14 @@ public class GBApplication extends Application { GB.environment = GBEnvironment.createDeviceEnvironment(); mActivityDatabaseHandler = new ActivityDatabaseHandler(context); + loadBlackList(); // for testing DB stuff // SQLiteDatabase db = mActivityDatabaseHandler.getWritableDatabase(); // db.close(); } public static boolean isFileLoggingEnabled() { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(GBApplication.getContext()); - return prefs.getBoolean("log_to_file", false); + return sharedPrefs.getBoolean("log_to_file", false); } private void setupLogging() { @@ -130,4 +134,36 @@ public class GBApplication extends Application { public static boolean isRunningLollipopOrLater() { return VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; } + + public static HashSet blacklist = null; + + public static void loadBlackList() { + blacklist = (HashSet) sharedPrefs.getStringSet("package_blacklist", null); + if (blacklist == null) { + blacklist = new HashSet<>(); + } + } + + public static void saveBlackList() { + SharedPreferences.Editor editor = sharedPrefs.edit(); + if (blacklist.isEmpty()) { + editor.putStringSet("package_blacklist", null); + } else { + editor.putStringSet("package_blacklist", blacklist); + } + editor.apply(); + } + + public static void addToBlacklist(String packageName) { + if (!blacklist.contains(packageName)) { + blacklist.add(packageName); + saveBlackList(); + } + } + + public static synchronized void removeFromBlacklist(String packageName) { + blacklist.remove(packageName); + saveBlackList(); + } + } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java index aec7cd9a..d95fd767 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java @@ -26,9 +26,9 @@ import android.widget.TextView; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashSet; import java.util.List; +import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; @@ -47,37 +47,6 @@ public class AppBlacklistActivity extends Activity { private SharedPreferences sharedPrefs; - private HashSet blacklist = null; - - private void loadBlackList() { - blacklist = (HashSet) sharedPrefs.getStringSet("package_blacklist", null); - if (blacklist == null) { - blacklist = new HashSet<>(); - } - } - - private void saveBlackList() { - SharedPreferences.Editor editor = sharedPrefs.edit(); - if (blacklist.isEmpty()) { - editor.putStringSet("package_blacklist", null); - } else { - editor.putStringSet("package_blacklist", blacklist); - } - editor.apply(); - } - - private synchronized void addToBlacklist(String packageName) { - if (!blacklist.contains(packageName)) { - blacklist.add(packageName); - saveBlackList(); - } - } - - private synchronized void removeFromBlacklist(String packageName) { - blacklist.remove(packageName); - saveBlackList(); - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -87,8 +56,6 @@ public class AppBlacklistActivity extends Activity { final PackageManager pm = getPackageManager(); sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - loadBlackList(); - final List packageList = pm.getInstalledApplications(PackageManager.GET_META_DATA); ListView appListView = (ListView) findViewById(R.id.appListView); @@ -110,7 +77,7 @@ public class AppBlacklistActivity extends Activity { deviceAppNameLabel.setText(appInfo.loadLabel(pm)); deviceImageView.setImageDrawable(appInfo.loadIcon(pm)); - if (blacklist.contains(appInfo.packageName)) { + if (GBApplication.blacklist.contains(appInfo.packageName)) { checkbox.setChecked(true); } @@ -126,9 +93,9 @@ public class AppBlacklistActivity extends Activity { CheckBox checkBox = ((CheckBox) v.findViewById(R.id.item_checkbox)); checkBox.toggle(); if (checkBox.isChecked()) { - addToBlacklist(packageName); + GBApplication.addToBlacklist(packageName); } else { - removeFromBlacklist(packageName); + GBApplication.removeFromBlacklist(packageName); } } }); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventNotificationControl.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventNotificationControl.java index 010ff0af..567782cd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventNotificationControl.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/deviceevents/GBDeviceEventNotificationControl.java @@ -9,6 +9,7 @@ public class GBDeviceEventNotificationControl extends GBDeviceEvent { UNKNOWN, DISMISS, DISMISS_ALL, - OPEN + OPEN, + MUTE } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java index c2da97c7..11a88c19 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/externalevents/NotificationListener.java @@ -9,6 +9,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.os.Bundle; import android.os.PowerManager; import android.preference.PreferenceManager; @@ -19,8 +21,6 @@ import android.support.v4.content.LocalBroadcastManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.HashSet; - import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; @@ -36,45 +36,60 @@ public class NotificationListener extends NotificationListenerService { = "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.dismiss_all"; public static final String ACTION_OPEN = "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.open"; + public static final String ACTION_MUTE + = "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.mute"; private BroadcastReceiver mReceiver = new BroadcastReceiver() { @SuppressLint("NewApi") @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (action.equals(ACTION_OPEN)) { - StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications(); - int handle = intent.getIntExtra("handle", -1); - for (StatusBarNotification sbn : sbns) { - if ((int) sbn.getPostTime() == handle) { - try { - PendingIntent pi = sbn.getNotification().contentIntent; - if (pi != null) { - pi.send(); + switch (action) { + case ACTION_MUTE: + case ACTION_OPEN: { + StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications(); + int handle = intent.getIntExtra("handle", -1); + for (StatusBarNotification sbn : sbns) { + if ((int) sbn.getPostTime() == handle) { + if (action.equals(ACTION_OPEN)) { + try { + PendingIntent pi = sbn.getNotification().contentIntent; + if (pi != null) { + pi.send(); + } + } catch (PendingIntent.CanceledException e) { + e.printStackTrace(); + } + } else { + // ACTION_MUTE + LOG.info("going to mute " + sbn.getPackageName()); + GBApplication.addToBlacklist(sbn.getPackageName()); } - } catch (PendingIntent.CanceledException e) { - e.printStackTrace(); } } + break; } - } else if (action.equals(ACTION_DISMISS)) { - StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications(); - int handle = intent.getIntExtra("handle", -1); - for (StatusBarNotification sbn : sbns) { - if ((int) sbn.getPostTime() == handle) { - if (GBApplication.isRunningLollipopOrLater()) { - String key = sbn.getKey(); - NotificationListener.this.cancelNotification(key); - } else { - int id = sbn.getId(); - String pkg = sbn.getPackageName(); - String tag = sbn.getTag(); - NotificationListener.this.cancelNotification(pkg, tag, id); + case ACTION_DISMISS: { + StatusBarNotification[] sbns = NotificationListener.this.getActiveNotifications(); + int handle = intent.getIntExtra("handle", -1); + for (StatusBarNotification sbn : sbns) { + if ((int) sbn.getPostTime() == handle) { + if (GBApplication.isRunningLollipopOrLater()) { + String key = sbn.getKey(); + NotificationListener.this.cancelNotification(key); + } else { + int id = sbn.getId(); + String pkg = sbn.getPackageName(); + String tag = sbn.getTag(); + NotificationListener.this.cancelNotification(pkg, tag, id); + } } } + break; } - } else if (action.equals(ACTION_DISMISS_ALL)) { - NotificationListener.this.cancelAllNotifications(); + case ACTION_DISMISS_ALL: + NotificationListener.this.cancelAllNotifications(); + break; } } @@ -87,6 +102,7 @@ public class NotificationListener extends NotificationListenerService { filterLocal.addAction(ACTION_OPEN); filterLocal.addAction(ACTION_DISMISS); filterLocal.addAction(ACTION_DISMISS_ALL); + filterLocal.addAction(ACTION_MUTE); LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal); } @@ -154,13 +170,24 @@ public class NotificationListener extends NotificationListenerService { } } - HashSet blacklist = (HashSet) sharedPrefs.getStringSet("package_blacklist", null); - if (blacklist != null && blacklist.contains(source)) { + if (GBApplication.blacklist != null && GBApplication.blacklist.contains(source)) { return; } - // Set application icons for generic notifications NotificationSpec notificationSpec = new NotificationSpec(); + + // determinate Source App Name ("Label") + PackageManager pm = getPackageManager(); + ApplicationInfo ai = null; + try { + ai = pm.getApplicationInfo(source, 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + if (ai != null) { + notificationSpec.sourceName = (String) pm.getApplicationLabel(ai); + } + switch (source) { case "org.mariotaku.twidere": case "com.twitter.android": diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java index 3bc4e64d..cc499efd 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/AbstractDeviceSupport.java @@ -220,6 +220,9 @@ public abstract class AbstractDeviceSupport implements DeviceSupport { case OPEN: action = NotificationListener.ACTION_OPEN; break; + case MUTE: + action = NotificationListener.ACTION_MUTE; + break; } if (action != null) { Intent notificationListenerIntent = new Intent(action); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java index 523b467e..1eda9688 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java @@ -409,10 +409,10 @@ public class PebbleProtocol extends GBDeviceProtocol { if (isFw3x) { // 3.x notification //return encodeTimelinePin(id, (int) ((ts + 600) & 0xffffffffL), (short) 90, PebbleIconID.TIMELINE_CALENDAR, title); // really, this is just for testing - return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, hasHandle, notificationSpec.type); + return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, notificationSpec.sourceName, hasHandle, notificationSpec.type); } else if (mForceProtocol || notificationSpec.type != NotificationType.EMAIL) { // 2.x notification - return encodeExtensibleNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, hasHandle); + return encodeExtensibleNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, notificationSpec.sourceName, hasHandle); } else { // 1.x notification on FW 2.X String[] parts = {title, notificationSpec.body, ts.toString(), subtitle}; @@ -455,7 +455,7 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeSetCallState("Where are you?", "Gadgetbridge", start ? ServiceCommand.CALL_INCOMING : ServiceCommand.CALL_END); } - private static byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, boolean hasHandle) { + private static byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle) { final short ACTION_LENGTH_MIN = 10; String[] parts = {title, subtitle, body}; @@ -465,12 +465,18 @@ public class PebbleProtocol extends GBDeviceProtocol { short actions_length; String dismiss_string; String open_string = "Open on phone"; + String mute_string = "Mute"; + if (sourceName != null) { + mute_string += " " + sourceName; + } + byte dismiss_action_id; + if (hasHandle) { - actions_count = 2; + actions_count = 3; dismiss_string = "Dismiss"; dismiss_action_id = 0x02; - actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length + open_string.getBytes().length); + actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length + open_string.getBytes().length + mute_string.getBytes().length); } else { actions_count = 1; dismiss_string = "Dismiss all"; @@ -539,11 +545,19 @@ public class PebbleProtocol extends GBDeviceProtocol { // open action if (hasHandle) { buf.put((byte) 0x01); - buf.put((byte) 0x02); // dissmiss - FIXME: find out how to answer to 2.x generic actions + buf.put((byte) 0x02); // generic buf.put((byte) 0x01); // number attributes buf.put((byte) 0x01); // attribute id (title) buf.putShort((short) open_string.getBytes().length); buf.put(open_string.getBytes()); + + buf.put((byte) 0x04); + buf.put((byte) 0x02); // generic + buf.put((byte) 0x01); // number attributes + buf.put((byte) 0x01); // attribute id (title) + buf.putShort((short) mute_string.getBytes().length); + buf.put(mute_string.getBytes()); + } return buf.array(); @@ -619,7 +633,7 @@ public class PebbleProtocol extends GBDeviceProtocol { return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array()); } - private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, boolean hasHandle, NotificationType notificationType) { + private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, NotificationType notificationType) { final short NOTIFICATION_PIN_LENGTH = 46; final short ACTION_LENGTH_MIN = 10; @@ -670,12 +684,17 @@ public class PebbleProtocol extends GBDeviceProtocol { short actions_length; String dismiss_string; String open_string = "Open on phone"; + String mute_string = "Mute"; + if (sourceName != null) { + mute_string += " " + sourceName; + } + byte dismiss_action_id; if (hasHandle) { - actions_count = 2; + actions_count = 3; dismiss_string = "Dismiss"; dismiss_action_id = 0x02; - actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length + open_string.getBytes().length); + actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length + open_string.getBytes().length + mute_string.getBytes().length); } else { actions_count = 1; dismiss_string = "Dismiss all"; @@ -751,7 +770,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.putShort((short) dismiss_string.getBytes().length); buf.put(dismiss_string.getBytes()); - // open action + // open and mute actions if (hasHandle) { buf.put((byte) 0x01); buf.put((byte) 0x02); // generic action @@ -759,11 +778,18 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.put((byte) 0x01); // attribute id (title) buf.putShort((short) open_string.getBytes().length); buf.put(open_string.getBytes()); + + buf.put((byte) 0x04); + buf.put((byte) 0x02); // generic action + buf.put((byte) 0x01); // number attributes + buf.put((byte) 0x01); // attribute id (title) + buf.putShort((short) mute_string.getBytes().length); + buf.put(mute_string.getBytes()); } return encodeBlobdb(UUID.randomUUID(), BLOBDB_INSERT, BLOBDB_NOTIFICATION, buf.array()); } - public byte[] encodeActionResponse2x(int id, int iconId, String caption) { + public byte[] encodeActionResponse2x(int id, byte actionId, int iconId, String caption) { short length = (short) (18 + caption.getBytes().length); ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + length); buf.order(ByteOrder.BIG_ENDIAN); @@ -772,7 +798,7 @@ public class PebbleProtocol extends GBDeviceProtocol { buf.order(ByteOrder.LITTLE_ENDIAN); buf.put(NOTIFICATIONACTION_RESPONSE); buf.putInt(id); - buf.put((byte) 0x01); // action id? + buf.put(actionId); buf.put(NOTIFICATIONACTION_ACK); buf.put((byte) 2); //nr of attributes buf.put((byte) 6); // icon @@ -1386,7 +1412,7 @@ public class PebbleProtocol extends GBDeviceProtocol { if (command == 0x02) { int id = buf.getInt(); byte action = buf.get(); - if (action >= 0x01 && action <= 0x03) { + if (action >= 0x01 && action <= 0x04) { GBDeviceEventNotificationControl devEvtNotificationControl = new GBDeviceEventNotificationControl(); devEvtNotificationControl.handle = id; GBDeviceEventSendBytes sendBytesAck = null; @@ -1395,7 +1421,7 @@ public class PebbleProtocol extends GBDeviceProtocol { case 0x01: devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.OPEN; sendBytesAck = new GBDeviceEventSendBytes(); - sendBytesAck.encodedBytes = encodeActionResponse2x(id, 6, "Opened"); + sendBytesAck.encodedBytes = encodeActionResponse2x(id, action, 6, "Opened"); break; case 0x02: devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.DISMISS; @@ -1403,6 +1429,11 @@ public class PebbleProtocol extends GBDeviceProtocol { case 0x03: devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.DISMISS_ALL; break; + case 0x04: + devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.MUTE; + sendBytesAck = new GBDeviceEventSendBytes(); + sendBytesAck.encodedBytes = encodeActionResponse2x(id, action, 6, "Muted"); + break; default: return null; } @@ -1424,7 +1455,7 @@ public class PebbleProtocol extends GBDeviceProtocol { long uuid_low = buf.getLong(); int id = (int) (uuid_low & 0xffffffff); byte action = buf.get(); - if (action >= 0x01 && action <= 0x03) { + if (action >= 0x01 && action <= 0x04) { GBDeviceEventNotificationControl dismissNotification = new GBDeviceEventNotificationControl(); dismissNotification.handle = id; String caption = "undefined"; @@ -1445,6 +1476,11 @@ public class PebbleProtocol extends GBDeviceProtocol { caption = "All dismissed"; icon_id = PebbleIconID.RESULT_DISMISSED; break; + case 0x04: + dismissNotification.event = GBDeviceEventNotificationControl.Event.MUTE; + caption = "Muted"; + icon_id = PebbleIconID.RESULT_MUTE; + break; } GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes(); sendBytesAck.encodedBytes = encodeActionResponse(new UUID(uuid_high, uuid_low), icon_id, caption); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java index 5af7227e..8660f997 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/GB.java @@ -308,7 +308,7 @@ public class GB { } public static void updateTransferNotification(String text, boolean ongoing, int percentage, Context context) { - if(percentage == 100) { + if (percentage == 100) { removeNotification(NOTIFICATION_ID_TRANSFER, context); } else { Notification notification = createTransferNotification(text, ongoing, percentage, context); From 720eaa111d9018a629b62b30d769a1c1953ff7fc Mon Sep 17 00:00:00 2001 From: Daniele Gobbetti Date: Fri, 25 Sep 2015 17:45:06 +0200 Subject: [PATCH 68/73] Add generic service for immediate alert and prepare the code to support characteristics from different services --- .../service/btle/AbstractBTLEDeviceSupport.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java index 486215e3..9932a599 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/btle/AbstractBTLEDeviceSupport.java @@ -39,6 +39,8 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im public static final UUID UUID_DESCRIPTOR_CHARACTERISTIC_USER_CONFIGURATION = UUID.fromString(String.format(BASE_UUID, "2901")); public static final UUID UUID_DESCRIPTOR_CLIENT_CHARACTERISTIC_CONFIGURATION = UUID.fromString(String.format(BASE_UUID, "2902")); + //part of the generic BLE specs see https://developer.bluetooth.org/gatt/services/Pages/ServiceViewer.aspx?u=org.bluetooth.service.immediate_alert.xml + public static final UUID UUID_SERVICE_IMMEDIATE_ALERT = UUID.fromString((String.format(BASE_UUID, "1802"))); @Override public boolean connect() { @@ -140,13 +142,13 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im } private void gattServicesDiscovered(List discoveredGattServices) { - mAvailableCharacteristics = null; + if (discoveredGattServices == null) { return; } Set supportedServices = getSupportedServices(); - + mAvailableCharacteristics = new HashMap(); for (BluetoothGattService service : discoveredGattServices) { if (supportedServices.contains(service.getUuid())) { List characteristics = service.getCharacteristics(); @@ -154,10 +156,11 @@ public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport im LOG.warn("Supported LE service " + service.getUuid() + "did not return any characteristics"); continue; } - mAvailableCharacteristics = new HashMap<>(characteristics.size()); + HashMap intmAvailableCharacteristics = new HashMap<>(characteristics.size()); for (BluetoothGattCharacteristic characteristic : characteristics) { - mAvailableCharacteristics.put(characteristic.getUuid(), characteristic); + intmAvailableCharacteristics.put(characteristic.getUuid(), characteristic); } + mAvailableCharacteristics.putAll(intmAvailableCharacteristics); } } } From c8a08510ce4ee34483fd961ba9bdad07d54c0612 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Fri, 25 Sep 2015 21:31:40 +0200 Subject: [PATCH 69/73] always initialize checkboxes AppBlacklistActivity, not only when App is in blacklist Closes #129 --- .../gadgetbridge/activities/AppBlacklistActivity.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java index d95fd767..371572db 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AppBlacklistActivity.java @@ -77,9 +77,7 @@ public class AppBlacklistActivity extends Activity { deviceAppNameLabel.setText(appInfo.loadLabel(pm)); deviceImageView.setImageDrawable(appInfo.loadIcon(pm)); - if (GBApplication.blacklist.contains(appInfo.packageName)) { - checkbox.setChecked(true); - } + checkbox.setChecked(GBApplication.blacklist.contains(appInfo.packageName)); return view; } From e7e583a5ba1ff13a985c7d5fe32f28d026625d84 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 26 Sep 2015 21:23:20 +0200 Subject: [PATCH 70/73] update translations (thanks) --- app/src/main/res/values-de/strings.xml | 1 - app/src/main/res/values-es/strings.xml | 1 - app/src/main/res/values-fr/strings.xml | 1 - app/src/main/res/values-it/strings.xml | 1 - app/src/main/res/values-ko/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 57 +++++++++++++++++++++++++- 6 files changed, 56 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 452eb47b..d5d45d4d 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -33,7 +33,6 @@ Benachrichtigungen Wiederholungen SMS - Eingehende Anrufe K9-Mail Pebble Nachrichten Unterstützung für Anwendungen, die Benachrichtigungen per Intent an die Pebble schicken. Kann für Conversations verwendet werden. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index b6896866..5b2d75e5 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -34,7 +34,6 @@ Notificaciones Repeticiones SMS - Llamadas entrantes K9-Mail Mensajes de Pebble Soporte para aplicaciones que envían notificaciones a Pebble a través de Intent. Puede ser usado por Conversations. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index fc5c236b..aa95ffc4 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -28,7 +28,6 @@ Notifications Répétitions SMS - Appel entrant K9-Email Message Pebble Support pour les applications qui envoient des notifications au Pebble via Intent. Peut être utilisé pour les conversations. diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index a708a1a0..68f23ad2 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -32,7 +32,6 @@ Notifiche Ripetizioni SMS - Chiamate in arrivo K9-Mail Pebble Messages Supporto per applicazioni che inviano le notifiche a Pebble usando Intents. Può essere usato per Conversations. diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index d6c32271..859e5770 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -24,7 +24,6 @@ 알림 반복 SMS - 걸려오는 전화 K-9 메일 Pebble 메세지 인텐트를 통해 Pebble에 알림을 전송할 수 있는 앱 지원. Conversations 앱 등에 사용할 수 있습니다. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 7da170aa..5aa98396 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -5,7 +5,9 @@ Настройки Отладка Выход + Синхронизировать Анализ сна (АЛЬФА) + Найти устройство... Сделать снимок экрана Отключиться Отладка @@ -13,18 +15,26 @@ App Mananger Удалить + Заблокированные уведомления + Установщик прошивки/приложений + Вы собираетесь установить прошивку %s заместо текущей на вашем Mi Band. + Эта прошивка была проверена и совместима с Gadgetbridge. + Эта прошивка не протестирована и может быть несовместима с Gadgetbridge.\n\nНе рекомендуется устанавливать её на ваш Mi Band! + Если вы желаете продолжить и впоследствии всё функционирует нормально, пожалуйста, сообщите разработчикам Gadgetbridge, чтобы они пометили как совместимую версию прошивки: %s Настройки Общие настройки Подключение к устройству при активации Bluetooth + Предпочтительный музыкальный плеер + По-умолчанию Дата и время Синхронизировать время при подключении Синхронизировать время при подключении к устройству, а также при изменении времени или временной зоны в системе Уведомления Повторы + Вызовы СМС-сообщения - Входящие звонки K9-Mail Сообщения Pebble Поддержка приложений, посылающих уведомления на Pebble с помощью Intent. Может использоваться для Conversations. @@ -33,11 +43,17 @@ всегда когда экран выключен никогда + Нежелательные приложения Настройки для разработчиков Адрес Mi Band Настройки Pebble + Разрешить доступ приложениям третьих лиц + Добавить экспериментальную поддержку приложений Android, использующих PebbleKit Принудительный протокол уведомлений Эта настройка заставляет принудительно использовать самый новый протокол уведомлений, зависящий от версии прошивки. ВКЛЮЧАЙТЕ, ТОЛЬКО ЕСЛИ ЗНАЕТЕ НА ЧТО ВЫ ИДЁТЕ. + Включить непроверенные функции + Включить функции, которые не протестированы. ВКЛЮЧАЙТЕ НА СВОЙ СТРАХ И РИСК! + Попытки переподключения нет соединения соединение соединено @@ -57,6 +73,7 @@ установки бинарного файла %1$d/%2$d установка не удалась! установка завершена + ВЫ ПЫТАЕТЕСЬ УСТАНОВИТЬ ПРОШИВКУ, ПРОДОЛЖАЙТЕ НА СВОЙ СТРАХ И РИСК.\n\n\n Эта прошивка для ревизии устройства: %s Вы собираетесь установить приложение:\n\n\n%1$s версия %2$s от %3$s\n Недоступно Инициализировано @@ -64,6 +81,7 @@ Поиск устройства Остановить поиск Умный поиск + Подключиться к новому устройству %1$s (%2$s) Сопряжение устройств Для сопряжения устройств используйте диалог Android. @@ -113,6 +131,7 @@ Уведомления о входящем звонке Найти потерянное устройство Отмените, чтобы остановить вибро + Ваша активность Завести Будильник Завести будильник Свойства будильника @@ -127,4 +146,40 @@ Произошла ошибка при настройке будильника, попробуйте ещё! Будильник был послан на устройство! Нет данных. Синхронизировать устройство? + Будет передано %1$s данных, начиная с %2$s + Цель шагов на каждый день + Произошла ошибка при выполнении \'%1$s\' + Ваша активность (АЛЬФА) + Подключиться не удалось: %1$s + Не удалось найти обработчик для установки этого файла. + Не удалось установить данный файл: %1$s + Не удалось установить данную прошивку: она не совпадает с версией устройства вашего Pebble + Пожалуйста подождите, идёт определение статуса установки... + Низкий заряд устройства! + %1$s осталось заряда: %2$s%% + Последний раз устройство заряжалось: %s \n + Количество циклов перезарядки: %s + Ваш сон + Шагов в неделю + Ваша активность и сон + Обновление прошивки... + Файл не может быть установлен, устройство не готово. + Версия прошивки Mi Band: %1$s + Совместимая версия + Не протестированная версия! + Подключение к устройству: %1$s + Версия прошивки Pebble: %1$s + Корректная ревизия устройства + Ревизия устройства не совпадает! + %1$s (%2$s) + Проблема с передачей прошивки. НЕ ПЕРЕЗАГРУЖАЙТЕ ваш Mi Band! + Проблема с передачей метаданных прошивки + Установка прошивки завершена + Установка прошивки завершена, устройство перезагружается... + Запись прошивки завершилась неудачей + Шаги + Жизненная активность + Шагов сегодня, цель: %1$s + Не передавать данные об активности + Если данные об активности не будут переданы на устройство, оно не будет очищено. Полезно, если GB используется с другими приложениями. From 949c49f2c9bd221647f5db941748d2d46450d3a0 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 26 Sep 2015 21:28:58 +0200 Subject: [PATCH 71/73] Bump version, update CHANGELOG --- CHANGELOG.md | 4 +++- app/build.gradle | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a70bdfb4..24d57af0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ ###Changelog -####Next Version +####Version 0.6.1 * Pebble: Allow muting (blacklisting) Apps from within generic notifications on the watch * Pebble: Detect all known Pebble Versions including new "chalk" platform (Pebble Time Round) * Option to ignore phone calls (useful for Pebble Dialer) +* Mi Band: Added progressbar for activity data transfer and fixes for firmware transfer progressbar +* Bugfix for app blacklist (some checkboxes where wrongly drawn as checked) ####Version 0.6.0 * Pebble: WIP implementantion of PebbleKit Intents to make some 3rd party Android apps work with the Pebble (eg. Ventoo) diff --git a/app/build.gradle b/app/build.gradle index 69f9c61b..da8eb113 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { applicationId "nodomain.freeyourgadget.gadgetbridge" minSdkVersion 19 targetSdkVersion 23 - versionCode 26 - versionName "0.6.0" + versionCode 27 + versionName "0.6.1" } buildTypes { release { From 4f5edb723142abeb5442db1c13a351191d418d3d Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 26 Sep 2015 21:33:55 +0200 Subject: [PATCH 72/73] update German translation --- app/src/main/res/values-de/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d5d45d4d..56536ab6 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -32,6 +32,7 @@ Synchronisiere die Urzeit mit dem Gerät (bei Verbindingsaufbau und wenn die Zeit oder Zeitzone auf dem Android Gerät eingestellt wird) Benachrichtigungen Wiederholungen + Anrufe SMS K9-Mail Pebble Nachrichten From 8fca35f94f17a0ebded42e60332055dbcb7a6ae6 Mon Sep 17 00:00:00 2001 From: Andreas Shimokawa Date: Sat, 26 Sep 2015 22:24:52 +0200 Subject: [PATCH 73/73] try to fix tests --- .../gadgetbridge/service/TestDeviceSupport.java | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java index 0f9ecdd3..56ddea6a 100644 --- a/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java +++ b/app/src/test/java/nodomain/freeyourgadget/gadgetbridge/service/TestDeviceSupport.java @@ -12,7 +12,8 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.Alarm; import nodomain.freeyourgadget.gadgetbridge.model.DeviceType; import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand; -import nodomain.freeyourgadget.gadgetbridge.model.NotificationKind; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationType; +import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec; import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport; public class TestDeviceSupport extends AbstractDeviceSupport { @@ -49,17 +50,7 @@ public class TestDeviceSupport extends AbstractDeviceSupport { } @Override - public void onSMS(String from, String body) { - - } - - @Override - public void onEmail(String from, String subject, String body) { - - } - - @Override - public void onGenericNotification(String title, String details, int handle, NotificationKind notification_kind) { + public void onNotification(NotificationSpec notificationSpec) { }