Merge branch 'master' into feature-weather

This commit is contained in:
Andreas Shimokawa 2016-05-24 11:09:21 +02:00
commit ec154c9041
34 changed files with 465 additions and 180 deletions

View File

@ -1,4 +1,12 @@
###Changelog ###Changelog
####Version 0.9.8
* Pebble: fix more reconnnect issues
* Pebble: fix deep sleep not being detected with Firmware 3.12 when using Pebble Health
* Pebble: option in AppManager to delete files from cache
* Pebble: enable pbw cache and watchface configuration for Firmware 2.x
* Pebble: allow enabling of Pebble Health without "untested features" being enabled
* Honour "Do Not Disturb" for phone calls and SMS
####Version 0.9.7 ####Version 0.9.7
* Pebble: hopefully fix some reconnect issues * Pebble: hopefully fix some reconnect issues
* Mi Band: fix live activity monitoring running forever if back button pressed * Mi Band: fix live activity monitoring running forever if back button pressed

28
CONTRIBUTORS.md Normal file
View File

@ -0,0 +1,28 @@
Andreas Shimokawa <shimokawa@fsfe.org>
cpfeiffer <cpfeiffer@users.noreply.github.com>
Daniele Gobbetti <daniele+github@gobbetti.name>
Daniele Gobbetti <daniele@gobbetti.name>
danielegobbetti <daniele+github@gobbetti.name>
Carsten Pfeiffer <cpfeiffer@users.noreply.github.com>
Julien Pivotto <roidelapluie@inuits.eu>
Lem Dulfo <lemuel.dulfo@gmail.com>
Sergey Trofimov <sarg@sarg.org.ru>
Daniele Gobbetti <daniele.gobbetti@gmail.com>
cpfeiffer <cpfeiffer@users.github.com>
0nse <0nse@users.noreply.github.com>
Christian Fischer <sw-dev@computerlyrik.de>
Normano64 <per.bergqwist@gmail.com>
Ⲇⲁⲛⲓ Φi <daniphii@outlook.com>
xphnx <xphnx@users.noreply.github.com>
Tarik Sekmen <tarik@ilixi.org>
rober <rober@prtl.nodomain.net>
Nicolò Balzarotti <anothersms@gmail.com>
Marc Schlaich <marc.schlaich@googlemail.com>
kevlarcade <kevlarcade@gmail.com>
Kasha <kasha_malaga@hotmail.com>
Chris Perelstein <chris.perelstein@gmail.com>
Alexey Afanasev <avafanasiev@gmail.com>
And all the Transifex translators, which I cannot automatically list, at the moment.
git log --raw | grep "^Author: " | sort | uniq -c | sort -k 1 -n -r | cut -f 2- -d: > CONTRIBUTORS.md

View File

@ -16,8 +16,8 @@ android {
targetSdkVersion 23 targetSdkVersion 23
// note: always bump BOTH versionCode and versionName! // note: always bump BOTH versionCode and versionName!
versionName "0.9.7" versionName "0.9.8"
versionCode 51 versionCode 52
} }
buildTypes { buildTypes {
release { release {

View File

@ -1,15 +1,21 @@
package nodomain.freeyourgadget.gadgetbridge; package nodomain.freeyourgadget.gadgetbridge;
import android.annotation.TargetApi;
import android.app.Application; import android.app.Application;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Build.VERSION; import android.os.Build.VERSION;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.provider.ContactsContract.PhoneLookup;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.util.Log; import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
@ -59,6 +65,10 @@ public class GBApplication extends Application {
private static Appender<ILoggingEvent> fileLogger; private static Appender<ILoggingEvent> fileLogger;
private static Prefs prefs; private static Prefs prefs;
private static GBPrefs gbPrefs; private static GBPrefs gbPrefs;
/**
* Note: is null on Lollipop and Kitkat
*/
private static NotificationManager notificationManager;
public static final String ACTION_QUIT public static final String ACTION_QUIT
= "nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit"; = "nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit";
@ -119,6 +129,10 @@ public class GBApplication extends Application {
filterLocal.addAction(ACTION_QUIT); filterLocal.addAction(ACTION_QUIT);
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal); LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
if (isRunningMarshmallowOrLater()) {
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
// for testing DB stuff // for testing DB stuff
// SQLiteDatabase db = mActivityDatabaseHandler.getWritableDatabase(); // SQLiteDatabase db = mActivityDatabaseHandler.getWritableDatabase();
// db.close(); // db.close();
@ -247,6 +261,63 @@ public class GBApplication extends Application {
return VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; return VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
} }
public static boolean isRunningMarshmallowOrLater() {
return VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
private static boolean isPrioritySender(int prioritySenders, String number) {
if (prioritySenders == Policy.PRIORITY_SENDERS_ANY) {
return true;
} else {
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
String[] projection = new String[]{PhoneLookup._ID, PhoneLookup.STARRED};
Cursor cursor = context.getContentResolver().query(uri, projection, null, null, null);
boolean exists = false;
int starred = 0;
try {
if (cursor != null && cursor.moveToFirst()) {
exists = true;
starred = cursor.getInt(cursor.getColumnIndexOrThrow(PhoneLookup.STARRED));
}
} finally {
if (cursor != null) {
cursor.close();
}
}
if (prioritySenders == Policy.PRIORITY_SENDERS_CONTACTS && exists) {
return true;
} else if (prioritySenders == Policy.PRIORITY_SENDERS_STARRED && starred == 1) {
return true;
}
return false;
}
}
@TargetApi(Build.VERSION_CODES.M)
public static boolean isPriorityNumber(int priorityType, String number) {
NotificationManager.Policy notificationPolicy = notificationManager.getNotificationPolicy();
if(priorityType == Policy.PRIORITY_CATEGORY_MESSAGES) {
if ((notificationPolicy.priorityCategories & Policy.PRIORITY_CATEGORY_MESSAGES) == Policy.PRIORITY_CATEGORY_MESSAGES) {
return isPrioritySender(notificationPolicy.priorityMessageSenders, number);
}
} else if (priorityType == Policy.PRIORITY_CATEGORY_CALLS) {
if ((notificationPolicy.priorityCategories & Policy.PRIORITY_CATEGORY_CALLS) == Policy.PRIORITY_CATEGORY_CALLS) {
return isPrioritySender(notificationPolicy.priorityCallSenders, number);
}
}
return false;
}
@TargetApi(Build.VERSION_CODES.M)
public static int getGrantedInterruptionFilter() {
if (prefs.getBoolean("notification_filter", false) && GBApplication.isRunningMarshmallowOrLater()) {
if (notificationManager.isNotificationPolicyAccessGranted()) {
return notificationManager.getCurrentInterruptionFilter();
}
}
return NotificationManager.INTERRUPTION_FILTER_ALL;
}
public static HashSet<String> blacklist = null; public static HashSet<String> blacklist = null;
private static void loadBlackList() { private static void loadBlackList() {

View File

@ -22,6 +22,7 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ListIterator;
import java.util.UUID; import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBApplication;
@ -47,7 +48,6 @@ public class AppManagerActivity extends GBActivity {
if (action.equals(GBApplication.ACTION_QUIT)) { if (action.equals(GBApplication.ACTION_QUIT)) {
finish(); finish();
} else if (action.equals(ACTION_REFRESH_APPLIST)) { } else if (action.equals(ACTION_REFRESH_APPLIST)) {
appList.clear();
int appCount = intent.getIntExtra("app_count", 0); int appCount = intent.getIntExtra("app_count", 0);
for (Integer i = 0; i < appCount; i++) { for (Integer i = 0; i < appCount; i++) {
String appName = intent.getStringExtra("app_name" + i.toString()); String appName = intent.getStringExtra("app_name" + i.toString());
@ -55,11 +55,21 @@ public class AppManagerActivity extends GBActivity {
UUID uuid = UUID.fromString(intent.getStringExtra("app_uuid" + i.toString())); UUID uuid = UUID.fromString(intent.getStringExtra("app_uuid" + i.toString()));
GBDeviceApp.Type appType = GBDeviceApp.Type.values()[intent.getIntExtra("app_type" + i.toString(), 0)]; GBDeviceApp.Type appType = GBDeviceApp.Type.values()[intent.getIntExtra("app_type" + i.toString(), 0)];
appList.add(new GBDeviceApp(uuid, appName, appCreator, "", appType)); boolean found = false;
} for (final ListIterator<GBDeviceApp> iter = appList.listIterator(); iter.hasNext(); ) {
final GBDeviceApp app = iter.next();
if (prefs.getBoolean("pebble_force_untested", false)) { if (app.getUUID().equals(uuid)) {
appList.addAll(getSystemApps()); app.setOnDevice(true);
iter.set(app);
found = true;
break;
}
}
if (!found) {
GBDeviceApp app = new GBDeviceApp(uuid, appName, appCreator, "", appType);
app.setOnDevice(true);
appList.add(app);
}
} }
mGBDeviceAppAdapter.notifyDataSetChanged(); mGBDeviceAppAdapter.notifyDataSetChanged();
@ -76,8 +86,10 @@ public class AppManagerActivity extends GBActivity {
private List<GBDeviceApp> getSystemApps() { private List<GBDeviceApp> getSystemApps() {
List<GBDeviceApp> systemApps = new ArrayList<>(); List<GBDeviceApp> systemApps = new ArrayList<>();
systemApps.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); if (prefs.getBoolean("pebble_force_untested", false)) {
systemApps.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); systemApps.add(new GBDeviceApp(UUID.fromString("4dab81a6-d2fc-458a-992c-7a1f3b96a970"), "Sports (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
systemApps.add(new GBDeviceApp(UUID.fromString("cf1e816a-9db0-4511-bbb8-f60c48ca8fac"), "Golf (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
}
if (mGBDevice != null && !"aplite".equals(PebbleUtils.getPlatformName(mGBDevice.getHardwareVersion()))) { if (mGBDevice != null && !"aplite".equals(PebbleUtils.getPlatformName(mGBDevice.getHardwareVersion()))) {
systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_PEBBLE_HEALTH, "Health (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM)); systemApps.add(new GBDeviceApp(PebbleProtocol.UUID_PEBBLE_HEALTH, "Health (System)", "Pebble Inc.", "", GBDeviceApp.Type.APP_SYSTEM));
} }
@ -149,9 +161,7 @@ public class AppManagerActivity extends GBActivity {
appList.addAll(getCachedApps()); appList.addAll(getCachedApps());
if (prefs.getBoolean("pebble_force_untested", false)) { appList.addAll(getSystemApps());
appList.addAll(getSystemApps());
}
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
filter.addAction(GBApplication.ACTION_QUIT); filter.addAction(GBApplication.ACTION_QUIT);
@ -171,11 +181,13 @@ public class AppManagerActivity extends GBActivity {
if (!selectedApp.isInCache()) { if (!selectedApp.isInCache()) {
menu.removeItem(R.id.appmanager_app_reinstall); menu.removeItem(R.id.appmanager_app_reinstall);
menu.removeItem(R.id.appmanager_app_delete_cache);
} }
if (!PebbleProtocol.UUID_PEBBLE_HEALTH.equals(selectedApp.getUUID())) { if (!PebbleProtocol.UUID_PEBBLE_HEALTH.equals(selectedApp.getUUID())) {
menu.removeItem(R.id.appmanager_health_activate); menu.removeItem(R.id.appmanager_health_activate);
menu.removeItem(R.id.appmanager_health_deactivate); menu.removeItem(R.id.appmanager_health_deactivate);
} else if (PebbleProtocol.UUID_PEBBLE_HEALTH.equals(selectedApp.getUUID())) { }
if (selectedApp.getType() == GBDeviceApp.Type.APP_SYSTEM) {
menu.removeItem(R.id.appmanager_app_delete); menu.removeItem(R.id.appmanager_app_delete);
} }
if (!selectedApp.isConfigurable()) { if (!selectedApp.isConfigurable()) {
@ -184,10 +196,42 @@ public class AppManagerActivity extends GBActivity {
menu.setHeaderTitle(selectedApp.getName()); menu.setHeaderTitle(selectedApp.getName());
} }
private void removeAppFromList(UUID uuid) {
for (final ListIterator<GBDeviceApp> iter = appList.listIterator(); iter.hasNext(); ) {
final GBDeviceApp app = iter.next();
if (app.getUUID().equals(uuid)) {
iter.remove();
mGBDeviceAppAdapter.notifyDataSetChanged();
break;
}
}
}
@Override @Override
public boolean onContextItemSelected(MenuItem item) { public boolean onContextItemSelected(MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.appmanager_health_deactivate: case R.id.appmanager_health_deactivate:
case R.id.appmanager_app_delete_cache:
String baseName;
try {
baseName = FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID();
} catch (IOException e) {
LOG.warn("could not get external dir while trying to access pbw cache.");
return true;
}
String[] suffixToDelete = new String[]{".pbw", ".json", "_config.js"};
for (String suffix : suffixToDelete) {
File fileToDelete = new File(baseName + suffix);
if (!fileToDelete.delete()) {
LOG.warn("could not delete file from pbw cache: " + fileToDelete.toString());
} else {
LOG.info("deleted file: " + fileToDelete.toString());
}
}
removeAppFromList(selectedApp.getUUID());
// fall through
case R.id.appmanager_app_delete: case R.id.appmanager_app_delete:
GBApplication.deviceService().onAppDelete(selectedApp.getUUID()); GBApplication.deviceService().onAppDelete(selectedApp.getUUID());
return true; return true;
@ -196,7 +240,7 @@ public class AppManagerActivity extends GBActivity {
try { try {
cachePath = new File(FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID() + ".pbw"); cachePath = new File(FileUtils.getExternalFilesDir().getPath() + "/pbw-cache/" + selectedApp.getUUID() + ".pbw");
} catch (IOException e) { } catch (IOException e) {
LOG.warn("could not get external dir while reading pbw cache."); LOG.warn("could not get external dir while trying to access pbw cache.");
return true; return true;
} }
GBApplication.deviceService().onInstallApp(Uri.fromFile(cachePath)); GBApplication.deviceService().onInstallApp(Uri.fromFile(cachePath));

View File

@ -6,6 +6,7 @@ import android.content.pm.ResolveInfo;
import android.os.Bundle; import android.os.Bundle;
import android.preference.ListPreference; import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceCategory;
import android.support.v4.content.LocalBroadcastManager; import android.support.v4.content.LocalBroadcastManager;
import android.widget.Toast; import android.widget.Toast;
@ -107,6 +108,12 @@ public class SettingsActivity extends AbstractSettingsActivity {
}); });
if (!GBApplication.isRunningMarshmallowOrLater()) {
pref = findPreference("notification_filter");
PreferenceCategory category = (PreferenceCategory) findPreference("pref_key_notifications");
category.removePreference(pref);
}
// Get all receivers of Media Buttons // Get all receivers of Media Buttons
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);

View File

@ -41,7 +41,15 @@ public class GBDeviceAppAdapter extends ArrayAdapter<GBDeviceApp> {
ImageView deviceImageView = (ImageView) view.findViewById(R.id.item_image); ImageView deviceImageView = (ImageView) view.findViewById(R.id.item_image);
deviceAppVersionAuthorLabel.setText(getContext().getString(R.string.appversion_by_creator, deviceApp.getVersion(), deviceApp.getCreator())); deviceAppVersionAuthorLabel.setText(getContext().getString(R.string.appversion_by_creator, deviceApp.getVersion(), deviceApp.getCreator()));
deviceAppNameLabel.setText(deviceApp.getName());
// FIXME: replace with small icons
String appNameLabelText = deviceApp.getName();
if (deviceApp.isInCache() || deviceApp.isOnDevice()) {
appNameLabelText += " (" + (deviceApp.isInCache() ? "C" : "")
+ (deviceApp.isOnDevice() ? "D" : "") + ")";
}
deviceAppNameLabel.setText(appNameLabelText);
switch (deviceApp.getType()) { switch (deviceApp.getType()) {
case APP_GENERIC: case APP_GENERIC:
deviceImageView.setImageResource(R.drawable.ic_watchapp); deviceImageView.setImageResource(R.drawable.ic_watchapp);

View File

@ -129,10 +129,6 @@ public class PBWInstallHandler implements InstallHandler {
return; return;
} }
if (!device.getFirmwareVersion().startsWith("v3")) {
return;
}
File destDir; File destDir;
GBDeviceApp app = mPBWReader.getGBDeviceApp(); GBDeviceApp app = mPBWReader.getGBDeviceApp();
try { try {

View File

@ -0,0 +1,43 @@
package nodomain.freeyourgadget.gadgetbridge.externalevents;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
public class BluetoothConnectReceiver extends BroadcastReceiver {
private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class);
final DeviceCommunicationService service;
public BluetoothConnectReceiver(DeviceCommunicationService service) {
this.service = service;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (!action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
return;
}
LOG.info("got connection attempt");
GBDevice gbDevice = service.getGBDevice();
if (gbDevice != null) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getAddress().equals(gbDevice.getAddress())) {
LOG.info("will connect to " + gbDevice.getName());
GBApplication.deviceService().connect();
} else {
LOG.info("won't connect to " + device.getAddress() + "(" + device.getName() + ")");
}
}
}
}

View File

@ -1,5 +1,6 @@
package nodomain.freeyourgadget.gadgetbridge.externalevents; package nodomain.freeyourgadget.gadgetbridge.externalevents;
import android.app.NotificationManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -33,6 +34,14 @@ public class K9Receiver extends BroadcastReceiver {
return; return;
} }
} }
switch (GBApplication.getGrantedInterruptionFilter()) {
case NotificationManager.INTERRUPTION_FILTER_ALL:
break;
case NotificationManager.INTERRUPTION_FILTER_ALARMS:
case NotificationManager.INTERRUPTION_FILTER_NONE:
case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
return;
}
String uriWanted = intent.getData().toString(); String uriWanted = intent.getData().toString();

View File

@ -3,6 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.externalevents;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@ -167,6 +168,16 @@ public class NotificationListener extends NotificationListenerService {
return; return;
} }
} }
switch (GBApplication.getGrantedInterruptionFilter()) {
case NotificationManager.INTERRUPTION_FILTER_ALL:
break;
case NotificationManager.INTERRUPTION_FILTER_ALARMS:
case NotificationManager.INTERRUPTION_FILTER_NONE:
return;
case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
// FIXME: Handle Reminders and Events if they are enabled in Do Not Disturb
return;
}
String source = sbn.getPackageName(); String source = sbn.getPackageName();
Notification notification = sbn.getNotification(); Notification notification = sbn.getNotification();

View File

@ -1,5 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.externalevents; package nodomain.freeyourgadget.gadgetbridge.externalevents;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -67,6 +69,19 @@ public class PhoneCallReceiver extends BroadcastReceiver {
if ("never".equals(prefs.getString("notification_mode_calls", "always"))) { if ("never".equals(prefs.getString("notification_mode_calls", "always"))) {
return; return;
} }
switch (GBApplication.getGrantedInterruptionFilter()) {
case NotificationManager.INTERRUPTION_FILTER_ALL:
break;
case NotificationManager.INTERRUPTION_FILTER_ALARMS:
case NotificationManager.INTERRUPTION_FILTER_NONE:
return;
case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
if (GBApplication.isPriorityNumber(Policy.PRIORITY_CATEGORY_CALLS, mSavedNumber)) {
break;
}
// FIXME: Handle Repeat callers if it is enabled in Do Not Disturb
return;
}
CallSpec callSpec = new CallSpec(); CallSpec callSpec = new CallSpec();
callSpec.number = mSavedNumber; callSpec.number = mSavedNumber;
callSpec.command = callCommand; callSpec.command = callCommand;

View File

@ -1,5 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge.externalevents; package nodomain.freeyourgadget.gadgetbridge.externalevents;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -41,6 +43,18 @@ public class SMSReceiver extends BroadcastReceiver {
notificationSpec.body = message.getDisplayMessageBody(); notificationSpec.body = message.getDisplayMessageBody();
notificationSpec.phoneNumber = message.getOriginatingAddress(); notificationSpec.phoneNumber = message.getOriginatingAddress();
if (notificationSpec.phoneNumber != null) { if (notificationSpec.phoneNumber != null) {
switch (GBApplication.getGrantedInterruptionFilter()) {
case NotificationManager.INTERRUPTION_FILTER_ALL:
break;
case NotificationManager.INTERRUPTION_FILTER_ALARMS:
case NotificationManager.INTERRUPTION_FILTER_NONE:
return;
case NotificationManager.INTERRUPTION_FILTER_PRIORITY:
if (GBApplication.isPriorityNumber(Policy.PRIORITY_CATEGORY_MESSAGES, notificationSpec.phoneNumber)) {
break;
}
return;
}
GBApplication.deviceService().onNotification(notificationSpec); GBApplication.deviceService().onNotification(notificationSpec);
} }
} }

View File

@ -12,6 +12,7 @@ public class GBDeviceApp {
private final UUID uuid; private final UUID uuid;
private final Type type; private final Type type;
private final boolean inCache; private final boolean inCache;
private boolean isOnDevice;
private final boolean configurable; private final boolean configurable;
public GBDeviceApp(UUID uuid, String name, String creator, String version, Type type) { public GBDeviceApp(UUID uuid, String name, String creator, String version, Type type) {
@ -23,6 +24,7 @@ public class GBDeviceApp {
//FIXME: do not assume //FIXME: do not assume
this.inCache = false; this.inCache = false;
this.configurable = false; this.configurable = false;
this.isOnDevice = false;
} }
public GBDeviceApp(JSONObject json, boolean configurable) { public GBDeviceApp(JSONObject json, boolean configurable) {
@ -52,10 +54,18 @@ public class GBDeviceApp {
this.configurable = configurable; this.configurable = configurable;
} }
public void setOnDevice(boolean isOnDevice) {
this.isOnDevice = isOnDevice;
}
public boolean isInCache() { public boolean isInCache() {
return inCache; return inCache;
} }
public boolean isOnDevice() {
return isOnDevice;
}
public String getName() { public String getName() {
return name; return name;
} }

View File

@ -2,6 +2,7 @@ package nodomain.freeyourgadget.gadgetbridge.service;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.Service; import android.app.Service;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -24,6 +25,7 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.K9Receiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.K9Receiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.PebbleReceiver; import nodomain.freeyourgadget.gadgetbridge.externalevents.PebbleReceiver;
@ -105,6 +107,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
private PebbleReceiver mPebbleReceiver = null; private PebbleReceiver mPebbleReceiver = null;
private MusicPlaybackReceiver mMusicPlaybackReceiver = null; private MusicPlaybackReceiver mMusicPlaybackReceiver = null;
private TimeChangeReceiver mTimeChangeReceiver = null; private TimeChangeReceiver mTimeChangeReceiver = null;
private BluetoothConnectReceiver mBlueToothConnectReceiver = null;
private Random mRandom = new Random(); private Random mRandom = new Random();
@ -279,6 +282,11 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
} }
case ACTION_DISCONNECT: { case ACTION_DISCONNECT: {
mDeviceSupport.dispose(); mDeviceSupport.dispose();
if (mGBDevice != null && mGBDevice.getState() == GBDevice.State.WAITING_FOR_RECONNECT) {
setReceiversEnableState(false);
mGBDevice.setState(GBDevice.State.NOT_CONNECTED);
mGBDevice.sendDeviceUpdateIntent(this);
}
mDeviceSupport = null; mDeviceSupport = null;
break; break;
} }
@ -457,6 +465,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
filter.addAction("android.intent.action.TIMEZONE_CHANGED"); filter.addAction("android.intent.action.TIMEZONE_CHANGED");
registerReceiver(mTimeChangeReceiver, filter); registerReceiver(mTimeChangeReceiver, filter);
} }
if (mBlueToothConnectReceiver == null) {
mBlueToothConnectReceiver = new BluetoothConnectReceiver(this);
registerReceiver(mBlueToothConnectReceiver, new IntentFilter(BluetoothDevice.ACTION_ACL_CONNECTED));
}
} else { } else {
if (mPhoneCallReceiver != null) { if (mPhoneCallReceiver != null) {
unregisterReceiver(mPhoneCallReceiver); unregisterReceiver(mPhoneCallReceiver);
@ -482,6 +494,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
unregisterReceiver(mTimeChangeReceiver); unregisterReceiver(mTimeChangeReceiver);
mTimeChangeReceiver = null; mTimeChangeReceiver = null;
} }
if (mBlueToothConnectReceiver != null) {
unregisterReceiver(mBlueToothConnectReceiver);
mBlueToothConnectReceiver = null;
}
} }
} }
@ -549,4 +565,8 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
public GBPrefs getGBPrefs() { public GBPrefs getGBPrefs() {
return GBApplication.getGBPrefs(); return GBApplication.getGBPrefs();
} }
public GBDevice getGBDevice() {
return mGBDevice;
}
} }

View File

@ -0,0 +1,99 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.HealthSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
class DatalogSessionHealthOverlayData extends DatalogSession {
private static final Logger LOG = LoggerFactory.getLogger(DatalogSessionHealthOverlayData.class);
public DatalogSessionHealthOverlayData(byte id, UUID uuid, int tag, byte item_type, short item_size) {
super(id, uuid, tag, item_type, item_size);
taginfo = "(health - overlay data " + tag + " )";
}
@Override
public boolean handleMessage(ByteBuffer datalogMessage, int length) {
LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length));
int initialPosition = datalogMessage.position();
int beginOfRecordPosition;
short recordVersion; //probably
short recordType; //probably: 1=sleep, 2=deep sleep, 5=??run??ignored for now
if (0 != (length % itemSize))
return false;//malformed message?
int recordCount = length / itemSize;
OverlayRecord[] overlayRecords = new OverlayRecord[recordCount];
for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) {
beginOfRecordPosition = initialPosition + recordIdx * itemSize;
datalogMessage.position(beginOfRecordPosition);//we may not consume all the bytes of a record
recordVersion = datalogMessage.getShort();
if ((recordVersion != 1) && (recordVersion != 3))
return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it
datalogMessage.getShort();//throwaway, unknown
recordType = datalogMessage.getShort();
overlayRecords[recordIdx] = new OverlayRecord(recordType, datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt());
}
return store(overlayRecords);//NACK if we cannot store the data yet, the watch will send the overlay records again.
}
private boolean store(OverlayRecord[] overlayRecords) {
DBHandler dbHandler = null;
SampleProvider sampleProvider = new HealthSampleProvider();
try {
dbHandler = GBApplication.acquireDB();
int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider);
for (OverlayRecord overlayRecord : overlayRecords) {
if (latestTimestamp < (overlayRecord.timestampStart + overlayRecord.durationSeconds))
return false;
switch (overlayRecord.type) {
case 1:
dbHandler.changeStoredSamplesType(overlayRecord.timestampStart, (overlayRecord.timestampStart + overlayRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider);
break;
case 2:
dbHandler.changeStoredSamplesType(overlayRecord.timestampStart, (overlayRecord.timestampStart + overlayRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP), sampleProvider);
break;
default:
//TODO: other values refer to unknown activity types.
}
}
} catch (Exception ex) {
LOG.debug(ex.getMessage());
} finally {
if (dbHandler != null) {
dbHandler.release();
}
}
return true;
}
private class OverlayRecord {
int type; //1=sleep, 2=deep sleep
int offsetUTC; //probably
int timestampStart;
int durationSeconds;
public OverlayRecord(int type, int offsetUTC, int timestampStart, int durationSeconds) {
this.type = type;
this.offsetUTC = offsetUTC;
this.timestampStart = timestampStart;
this.durationSeconds = durationSeconds;
}
}
}

View File

@ -1,7 +1,5 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble; package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
import android.widget.Toast;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -27,71 +25,6 @@ class DatalogSessionHealthSleep extends DatalogSession {
@Override @Override
public boolean handleMessage(ByteBuffer datalogMessage, int length) { public boolean handleMessage(ByteBuffer datalogMessage, int length) {
LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length)); LOG.info("DATALOG " + taginfo + GB.hexdump(datalogMessage.array(), datalogMessage.position(), length));
switch (this.tag) {
case 83:
return handleMessage83(datalogMessage, length);
case 84:
return handleMessage84(datalogMessage, length);
default:
return false;
}
}
private boolean handleMessage84(ByteBuffer datalogMessage, int length) {
int initialPosition = datalogMessage.position();
int beginOfRecordPosition;
short recordVersion; //probably
short recordType; //probably: 1=sleep, 2=deep sleep
if (0 != (length % itemSize))
return false;//malformed message?
int recordCount = length / itemSize;
SleepRecord84[] sleepRecords = new SleepRecord84[recordCount];
for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) {
beginOfRecordPosition = initialPosition + recordIdx * itemSize;
datalogMessage.position(beginOfRecordPosition);//we may not consume all the bytes of a record
recordVersion = datalogMessage.getShort();
if (recordVersion != 1)
return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it
datalogMessage.getShort();//throwaway, unknown
recordType = datalogMessage.getShort();
sleepRecords[recordIdx] = new SleepRecord84(recordType, datalogMessage.getInt(), datalogMessage.getInt(), datalogMessage.getInt());
}
return store84(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again.
}
private boolean store84(SleepRecord84[] sleepRecords) {
DBHandler dbHandler = null;
SampleProvider sampleProvider = new HealthSampleProvider();
try {
dbHandler = GBApplication.acquireDB();
int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider);
for (SleepRecord84 sleepRecord : sleepRecords) {
if (latestTimestamp < (sleepRecord.timestampStart + sleepRecord.durationSeconds))
return false;
if (sleepRecord.type == 2) {
dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_DEEP_SLEEP), sampleProvider);
} else {
dbHandler.changeStoredSamplesType(sleepRecord.timestampStart, (sleepRecord.timestampStart + sleepRecord.durationSeconds), sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider);
}
}
} catch (Exception ex) {
LOG.debug(ex.getMessage());
} finally {
if (dbHandler != null) {
dbHandler.release();
}
}
return true;
}
private boolean handleMessage83(ByteBuffer datalogMessage, int length) {
int initialPosition = datalogMessage.position(); int initialPosition = datalogMessage.position();
int beginOfRecordPosition; int beginOfRecordPosition;
short recordVersion; //probably short recordVersion; //probably
@ -100,7 +33,7 @@ class DatalogSessionHealthSleep extends DatalogSession {
return false;//malformed message? return false;//malformed message?
int recordCount = length / itemSize; int recordCount = length / itemSize;
SleepRecord83[] sleepRecords = new SleepRecord83[recordCount]; SleepRecord[] sleepRecords = new SleepRecord[recordCount];
for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) { for (int recordIdx = 0; recordIdx < recordCount; recordIdx++) {
beginOfRecordPosition = initialPosition + recordIdx * itemSize; beginOfRecordPosition = initialPosition + recordIdx * itemSize;
@ -109,23 +42,22 @@ class DatalogSessionHealthSleep extends DatalogSession {
if (recordVersion != 1) if (recordVersion != 1)
return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it return false;//we don't know how to deal with the data TODO: this is not ideal because we will get the same message again and again since we NACK it
sleepRecords[recordIdx] = new SleepRecord83(datalogMessage.getInt(), sleepRecords[recordIdx] = new SleepRecord(datalogMessage.getInt(),
datalogMessage.getInt(), datalogMessage.getInt(),
datalogMessage.getInt(), datalogMessage.getInt(),
datalogMessage.getInt()); datalogMessage.getInt());
} }
return store83(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again. return store(sleepRecords);//NACK if we cannot store the data yet, the watch will send the sleep records again.
} }
private boolean store83(SleepRecord83[] sleepRecords) { private boolean store(SleepRecord[] sleepRecords) {
DBHandler dbHandler = null; DBHandler dbHandler = null;
SampleProvider sampleProvider = new HealthSampleProvider(); SampleProvider sampleProvider = new HealthSampleProvider();
GB.toast("Deep sleep is supported only from firmware 3.11 onwards.", Toast.LENGTH_LONG, GB.INFO);
try { try {
dbHandler = GBApplication.acquireDB(); dbHandler = GBApplication.acquireDB();
int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider); int latestTimestamp = dbHandler.fetchLatestTimestamp(sampleProvider);
for (SleepRecord83 sleepRecord : sleepRecords) { for (SleepRecord sleepRecord : sleepRecords) {
if (latestTimestamp < sleepRecord.bedTimeEnd) if (latestTimestamp < sleepRecord.bedTimeEnd)
return false; return false;
dbHandler.changeStoredSamplesType(sleepRecord.bedTimeStart, sleepRecord.bedTimeEnd, sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider); dbHandler.changeStoredSamplesType(sleepRecord.bedTimeStart, sleepRecord.bedTimeEnd, sampleProvider.toRawActivityKind(ActivityKind.TYPE_ACTIVITY), sampleProvider.toRawActivityKind(ActivityKind.TYPE_LIGHT_SLEEP), sampleProvider);
@ -140,13 +72,13 @@ class DatalogSessionHealthSleep extends DatalogSession {
return true; return true;
} }
private class SleepRecord83 { private class SleepRecord {
int offsetUTC; //probably int offsetUTC; //probably
int bedTimeStart; int bedTimeStart;
int bedTimeEnd; int bedTimeEnd;
int deepSleepSeconds; int deepSleepSeconds;
public SleepRecord83(int offsetUTC, int bedTimeStart, int bedTimeEnd, int deepSleepSeconds) { public SleepRecord(int offsetUTC, int bedTimeStart, int bedTimeEnd, int deepSleepSeconds) {
this.offsetUTC = offsetUTC; this.offsetUTC = offsetUTC;
this.bedTimeStart = bedTimeStart; this.bedTimeStart = bedTimeStart;
this.bedTimeEnd = bedTimeEnd; this.bedTimeEnd = bedTimeEnd;
@ -154,17 +86,4 @@ class DatalogSessionHealthSleep extends DatalogSession {
} }
} }
private class SleepRecord84 {
int type; //1=sleep, 2=deep sleep
int offsetUTC; //probably
int timestampStart;
int durationSeconds;
public SleepRecord84(int type, int offsetUTC, int timestampStart, int durationSeconds) {
this.type = type;
this.offsetUTC = offsetUTC;
this.timestampStart = timestampStart;
this.durationSeconds = durationSeconds;
}
}
} }

View File

@ -2,7 +2,6 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.pebble;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothSocket;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
@ -48,9 +47,6 @@ import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class PebbleIoThread extends GBDeviceIoThread { public class PebbleIoThread extends GBDeviceIoThread {
private static final Logger LOG = LoggerFactory.getLogger(PebbleIoThread.class); private static final Logger LOG = LoggerFactory.getLogger(PebbleIoThread.class);
private static final UUID PEBBLE_UUID_RECONNECT = UUID.fromString("00000000-deca-fade-deca-deafdecacafe");
private static final UUID PEBBLE_UUID_RECONNECT3X = UUID.fromString("a924496e-cc7c-4dff-8a9f-9a76cc2e9d50");
public static final String PEBBLEKIT_ACTION_PEBBLE_CONNECTED = "com.getpebble.action.PEBBLE_CONNECTED"; 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_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_ACK = "com.getpebble.action.app.ACK";
@ -71,7 +67,6 @@ public class PebbleIoThread extends GBDeviceIoThread {
private boolean mIsTCP = false; private boolean mIsTCP = false;
private BluetoothAdapter mBtAdapter = null; private BluetoothAdapter mBtAdapter = null;
private BluetoothSocket mBtSocket = null; private BluetoothSocket mBtSocket = null;
private BluetoothServerSocket mBtServerSocket = null;
private Socket mTCPSocket = null; // for emulator private Socket mTCPSocket = null; // for emulator
private InputStream mInStream = null; private InputStream mInStream = null;
private OutputStream mOutStream = null; private OutputStream mOutStream = null;
@ -365,7 +360,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
LOG.info(e.getMessage()); LOG.info(e.getMessage());
mIsConnected = false; mIsConnected = false;
int reconnectAttempts = prefs.getInt("pebble_reconnect_attempts", 10); int reconnectAttempts = prefs.getInt("pebble_reconnect_attempts", 10);
if (GBApplication.getGBPrefs().getAutoReconnect() && reconnectAttempts > 0) { if (!mQuit && GBApplication.getGBPrefs().getAutoReconnect() && reconnectAttempts > 0) {
gbDevice.setState(GBDevice.State.CONNECTING); gbDevice.setState(GBDevice.State.CONNECTING);
gbDevice.sendDeviceUpdateIntent(getContext()); gbDevice.sendDeviceUpdateIntent(getContext());
int delaySeconds = 1; int delaySeconds = 1;
@ -383,33 +378,10 @@ public class PebbleIoThread extends GBDeviceIoThread {
} }
} }
} }
if (!mIsConnected && !mQuit) {
try {
gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT);
gbDevice.sendDeviceUpdateIntent(getContext());
UUID reconnectUUID = mPebbleProtocol.isFw3x ? PEBBLE_UUID_RECONNECT3X : PEBBLE_UUID_RECONNECT;
mBtServerSocket = mBtAdapter.listenUsingRfcommWithServiceRecord("PebbleReconnectListener", reconnectUUID);
mBtSocket = mBtServerSocket.accept();
LOG.info("incoming connection on reconnect uuid (" + reconnectUUID + "), will connect actively");
mBtSocket.close();
mIsConnected = connect(gbDevice.getAddress());
} catch (IOException ex) {
ex.printStackTrace();
LOG.info("error while reconnecting");
} finally {
try {
if (mBtServerSocket != null) {
mBtServerSocket.close();
mBtServerSocket = null;
}
} catch (IOException ignore) {
}
}
}
if (!mIsConnected) { if (!mIsConnected) {
mBtSocket = null; mBtSocket = null;
LOG.info("Bluetooth socket closed, will quit IO Thread"); LOG.info("Bluetooth socket closed, will quit IO Thread");
mQuit = true; break;
} }
} }
} }
@ -421,10 +393,16 @@ public class PebbleIoThread extends GBDeviceIoThread {
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
mBtSocket = null;
} }
enablePebbleKitReceiver(false); enablePebbleKitReceiver(false);
mBtSocket = null;
gbDevice.setState(GBDevice.State.NOT_CONNECTED); if (mQuit) {
gbDevice.setState(GBDevice.State.NOT_CONNECTED);
} else {
gbDevice.setState(GBDevice.State.WAITING_FOR_RECONNECT);
}
gbDevice.sendDeviceUpdateIntent(getContext()); gbDevice.sendDeviceUpdateIntent(getContext());
} }
@ -700,13 +678,6 @@ public class PebbleIoThread extends GBDeviceIoThread {
e.printStackTrace(); e.printStackTrace();
} }
} }
if (mBtServerSocket != null) {
try {
mBtServerSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (mTCPSocket != null) { if (mTCPSocket != null) {
try { try {
mTCPSocket.close(); mTCPSocket.close();

View File

@ -1883,8 +1883,10 @@ public class PebbleProtocol extends GBDeviceProtocol {
if (!mDatalogSessions.containsKey(id)) { if (!mDatalogSessions.containsKey(id)) {
if (uuid.equals(UUID_ZERO) && log_tag == 81) { if (uuid.equals(UUID_ZERO) && log_tag == 81) {
mDatalogSessions.put(id, new DatalogSessionHealthSteps(id, uuid, log_tag, item_type, item_size)); mDatalogSessions.put(id, new DatalogSessionHealthSteps(id, uuid, log_tag, item_type, item_size));
} else if (uuid.equals(UUID_ZERO) && (log_tag == 83 || log_tag == 84)) { } else if (uuid.equals(UUID_ZERO) && log_tag == 83) {
mDatalogSessions.put(id, new DatalogSessionHealthSleep(id, uuid, log_tag, item_type, item_size)); mDatalogSessions.put(id, new DatalogSessionHealthSleep(id, uuid, log_tag, item_type, item_size));
} else if (uuid.equals(UUID_ZERO) && log_tag == 84) {
mDatalogSessions.put(id, new DatalogSessionHealthOverlayData(id, uuid, log_tag, item_type, item_size));
} else { } else {
mDatalogSessions.put(id, new DatalogSession(id, uuid, log_tag, item_type, item_size)); mDatalogSessions.put(id, new DatalogSession(id, uuid, log_tag, item_type, item_size));
} }

View File

@ -78,6 +78,7 @@ public class PebbleSupport extends AbstractSerialDeviceSupport {
private boolean reconnect() { private boolean reconnect() {
if (!isConnected() && useAutoConnect()) { if (!isConnected() && useAutoConnect()) {
if (getDevice().getState() == GBDevice.State.WAITING_FOR_RECONNECT) { if (getDevice().getState() == GBDevice.State.WAITING_FOR_RECONNECT) {
gbDeviceIOThread.quit();
gbDeviceIOThread.interrupt(); gbDeviceIOThread.interrupt();
gbDeviceIOThread = null; gbDeviceIOThread = null;
if (!connect()) { if (!connect()) {

View File

@ -6,6 +6,9 @@
<item <item
android:id="@+id/appmanager_app_delete" android:id="@+id/appmanager_app_delete"
android:title="@string/appmananger_app_delete"/> android:title="@string/appmananger_app_delete"/>
<item
android:id="@+id/appmanager_app_delete_cache"
android:title="@string/appmananger_app_delete_cache"/>
<item <item
android:id="@+id/appmanager_health_activate" android:id="@+id/appmanager_health_activate"
android:title="@string/appmanager_health_activate"/> android:title="@string/appmanager_health_activate"/>

View File

@ -14,6 +14,7 @@
<!--Strings related to AppManager--> <!--Strings related to AppManager-->
<string name="title_activity_appmanager">App Manager</string> <string name="title_activity_appmanager">App Manager</string>
<string name="appmananger_app_delete">Löschen</string> <string name="appmananger_app_delete">Löschen</string>
<string name="appmananger_app_delete_cache">Löschen und aus dem Zwischenspeicher entfernen</string>
<!--Strings related to AppBlacklist--> <!--Strings related to AppBlacklist-->
<string name="title_activity_appblacklist">Sperre für Benachrichtigungen</string> <string name="title_activity_appblacklist">Sperre für Benachrichtigungen</string>
<!--Strings related to FwAppInstaller--> <!--Strings related to FwAppInstaller-->
@ -44,6 +45,8 @@
<string name="pref_summary_notifications_pebblemsg">Unterstützung für Anwendungen, die Benachrichtigungen per Intent an die Pebble schicken. Kann für Conversations verwendet werden.</string> <string name="pref_summary_notifications_pebblemsg">Unterstützung für Anwendungen, die Benachrichtigungen per Intent an die Pebble schicken. Kann für Conversations verwendet werden.</string>
<string name="pref_title_notifications_generic">Andere Benachrichtigungen</string> <string name="pref_title_notifications_generic">Andere Benachrichtigungen</string>
<string name="pref_title_whenscreenon">… auch wenn der Bildschirm an ist</string> <string name="pref_title_whenscreenon">… auch wenn der Bildschirm an ist</string>
<string name="pref_title_notification_filter">Bitte nicht stören</string>
<string name="pref_summary_notification_filter">Stoppe unerwünschte Nachrichten, wenn im \"Nicht Stören\"-Modus</string>
<string name="always">immer</string> <string name="always">immer</string>
<string name="when_screen_off">wenn der Bildschirm aus ist</string> <string name="when_screen_off">wenn der Bildschirm aus ist</string>
<string name="never">niemals</string> <string name="never">niemals</string>
@ -202,8 +205,9 @@
<string name="pref_title_keep_data_on_device">Aktivitätsdaten auf dem Gerät lassen</string> <string name="pref_title_keep_data_on_device">Aktivitätsdaten auf dem Gerät lassen</string>
<string name="miband_fwinstaller_incompatible_version">Inkompatible Firmware</string> <string name="miband_fwinstaller_incompatible_version">Inkompatible Firmware</string>
<string name="fwinstaller_firmware_not_compatible_to_device">Diese Firmware ist nicht mit dem Gerät kompatibel</string> <string name="fwinstaller_firmware_not_compatible_to_device">Diese Firmware ist nicht mit dem Gerät kompatibel</string>
<string name="miband_prefs_reserve_alarm_calendar">Wecker für zukünftige Ereignisse vormerken</string>
<string name="miband_prefs_hr_sleep_detection">Verwende den Herzfrequenzsensor um die Schlaferkennung zu verbessern</string> <string name="miband_prefs_hr_sleep_detection">Verwende den Herzfrequenzsensor um die Schlaferkennung zu verbessern</string>
<string name="waiting_for_reconnect">warte auf eingehende Verbindung</string> <string name="waiting_for_reconnect">warte auf Verbindung</string>
<string name="appmananger_app_reinstall">Erneut installieren</string> <string name="appmananger_app_reinstall">Erneut installieren</string>
<string name="activity_prefs_about_you">Über Dich</string> <string name="activity_prefs_about_you">Über Dich</string>
<string name="activity_prefs_year_birth">Geburtsjahr</string> <string name="activity_prefs_year_birth">Geburtsjahr</string>
@ -214,6 +218,7 @@
<string name="appmanager_health_deactivate">deaktivieren</string> <string name="appmanager_health_deactivate">deaktivieren</string>
<string name="authenticating">Authentifiziere</string> <string name="authenticating">Authentifiziere</string>
<string name="authentication_required">Authentifizierung erforderlich</string> <string name="authentication_required">Authentifizierung erforderlich</string>
<string name="app_configure">Konfigurieren</string>
<string name="appwidget_text">Zzz</string> <string name="appwidget_text">Zzz</string>
<string name="add_widget">Widget hinzufügen</string> <string name="add_widget">Widget hinzufügen</string>
<string name="activity_prefs_sleep_duration">Gewünschte Schlafdauer in Stunden</string> <string name="activity_prefs_sleep_duration">Gewünschte Schlafdauer in Stunden</string>

View File

@ -69,8 +69,6 @@
<string name="this_is_a_test_notification_from_gadgetbridge">Notificación de prueba desde Gadgetbridge</string> <string name="this_is_a_test_notification_from_gadgetbridge">Notificación de prueba desde Gadgetbridge</string>
<string name="bluetooth_is_not_supported_">Bluetooth no está soportado.</string> <string name="bluetooth_is_not_supported_">Bluetooth no está soportado.</string>
<string name="bluetooth_is_disabled_">Bluetooth está desactivado.</string> <string name="bluetooth_is_disabled_">Bluetooth está desactivado.</string>
<string name="tap_connected_device_for_app_mananger">pulsa el dispositivo conectado para el Gestor de App</string>
<string name="tap_a_device_to_connect">pulsa un dispositivo para conectar</string>
<string name="cannot_connect_bt_address_invalid_">No se puede conectar. ¿Dirección BT incorrecta?</string> <string name="cannot_connect_bt_address_invalid_">No se puede conectar. ¿Dirección BT incorrecta?</string>
<string name="gadgetbridge_running">Gadgetbridge funcionando</string> <string name="gadgetbridge_running">Gadgetbridge funcionando</string>
<string name="installing_binary_d_d">instalando binario %1$d/%2$d</string> <string name="installing_binary_d_d">instalando binario %1$d/%2$d</string>
@ -101,13 +99,11 @@
<string name="miband_pairing_using_dummy_userdata">No se han proporcionado datos de usuario válidos, se usarán datos de usuario por defecto.</string> <string name="miband_pairing_using_dummy_userdata">No se han proporcionado datos de usuario válidos, se usarán datos de usuario por defecto.</string>
<string name="miband_pairing_tap_hint">Cuando tu MiBand vibre y parpadee, púlsala repetidas veces.</string> <string name="miband_pairing_tap_hint">Cuando tu MiBand vibre y parpadee, púlsala repetidas veces.</string>
<string name="appinstaller_install">Instalar</string> <string name="appinstaller_install">Instalar</string>
<string name="discovery_connected_devices_hint">Haz visible tu dispositivo. No es probable que se detecten los dispositivos que ya están conectados.</string>
<string name="discovery_note">Nota:</string> <string name="discovery_note">Nota:</string>
<string name="candidate_item_device_image">Imagen del dispositivo</string> <string name="candidate_item_device_image">Imagen del dispositivo</string>
<string name="miband_prefs_alias">Nombre/Apodo</string> <string name="miband_prefs_alias">Nombre/Apodo</string>
<string name="pref_header_vibration_count">Número de vibraciones</string> <string name="pref_header_vibration_count">Número de vibraciones</string>
<string name="title_activity_sleepmonitor">Monitor de sueño</string> <string name="title_activity_sleepmonitor">Monitor de sueño</string>
<string name="pref_write_logfiles">Guardar logs</string>
<string name="initializing">iniciando</string> <string name="initializing">iniciando</string>
<string name="busy_task_fetch_activity_data">Recuperando datos de actividad</string> <string name="busy_task_fetch_activity_data">Recuperando datos de actividad</string>
<string name="sleep_activity_date_range">Desde %1$s a %2$s</string> <string name="sleep_activity_date_range">Desde %1$s a %2$s</string>
@ -178,9 +174,9 @@
<string name="chart_steps">Pasos</string> <string name="chart_steps">Pasos</string>
<string name="liveactivity_live_activity">Actividad</string> <string name="liveactivity_live_activity">Actividad</string>
<string name="weeksteps_today_steps_description">Pasos hoy, objetivo: %1$s</string> <string name="weeksteps_today_steps_description">Pasos hoy, objetivo: %1$s</string>
<string name="pref_title_dont_ack_transfer">No confirmar transferencia</string>
<string name="pref_summary_dont_ack_transfers">Si los datos no son marcados como descargados, no serán borrados de tu MiBand. Útil si Gadgetbridge se usa conjuntamente con otras apps.</string> <string name="pref_summary_dont_ack_transfers">Si los datos no son marcados como descargados, no serán borrados de tu MiBand. Útil si Gadgetbridge se usa conjuntamente con otras apps.</string>
<string name="pref_summary_keep_data_on_device">Mantendrá los datos de actividad en la MiBand incluso después de la sincronización. Útil si GB se usa junto con otras apps.</string> <string name="pref_summary_keep_data_on_device">Mantendrá los datos de actividad en la MiBand incluso después de la sincronización. Útil si GB se usa junto con otras apps.</string>
<string name="pref_title_dont_ack_transfer">No confirmar transferencia</string>
<string name="live_activity_steps_history">Historial de pasos</string> <string name="live_activity_steps_history">Historial de pasos</string>
<string name="live_activity_current_steps_per_minute">Pasos/min actuales</string> <string name="live_activity_current_steps_per_minute">Pasos/min actuales</string>
<string name="live_activity_total_steps">Pasos totales</string> <string name="live_activity_total_steps">Pasos totales</string>

View File

@ -178,9 +178,9 @@
<string name="chart_steps">Pas</string> <string name="chart_steps">Pas</string>
<string name="liveactivity_live_activity">Activité en direct</string> <string name="liveactivity_live_activity">Activité en direct</string>
<string name="weeksteps_today_steps_description">Nombre de pas aujourd\'hui, objectif: %1$s</string> <string name="weeksteps_today_steps_description">Nombre de pas aujourd\'hui, objectif: %1$s</string>
<string name="pref_title_dont_ack_transfer">Ne pas confirmer le transfert de données d\'activités</string>
<string name="pref_summary_dont_ack_transfers">Les données d\'activités ne seront pas effacées du bracelet si elles ne sont pas confirmées. Utile si GB est utilisé avec d\'autres applications.</string> <string name="pref_summary_dont_ack_transfers">Les données d\'activités ne seront pas effacées du bracelet si elles ne sont pas confirmées. Utile si GB est utilisé avec d\'autres applications.</string>
<string name="pref_summary_keep_data_on_device">Les données d\'activités seront conservées sur le Mi Band après la synchronisation. Utile si GB est utilisé avec d\'autres applications.</string> <string name="pref_summary_keep_data_on_device">Les données d\'activités seront conservées sur le Mi Band après la synchronisation. Utile si GB est utilisé avec d\'autres applications.</string>
<string name="pref_title_dont_ack_transfer">Ne pas confirmer le transfert de données d\'activités</string>
<string name="live_activity_steps_history">Historique de pas</string> <string name="live_activity_steps_history">Historique de pas</string>
<string name="live_activity_current_steps_per_minute">Pas/minute actuel</string> <string name="live_activity_current_steps_per_minute">Pas/minute actuel</string>
<string name="live_activity_total_steps">Nombre total de pas</string> <string name="live_activity_total_steps">Nombre total de pas</string>

View File

@ -70,8 +70,6 @@
<string name="this_is_a_test_notification_from_gadgetbridge">Notifica di prova creata da Gadgetbridge</string> <string name="this_is_a_test_notification_from_gadgetbridge">Notifica di prova creata da Gadgetbridge</string>
<string name="bluetooth_is_not_supported_">Bluetooth non supportato.</string> <string name="bluetooth_is_not_supported_">Bluetooth non supportato.</string>
<string name="bluetooth_is_disabled_">Bluetooth disabilitato.</string> <string name="bluetooth_is_disabled_">Bluetooth disabilitato.</string>
<string name="tap_connected_device_for_app_mananger">tocca il dispositivo connesso per gestire le App</string>
<string name="tap_a_device_to_connect">tocca il dispositivo da connettere</string>
<string name="cannot_connect_bt_address_invalid_">Impossibile connettersi. Indirizzo BT non valido?</string> <string name="cannot_connect_bt_address_invalid_">Impossibile connettersi. Indirizzo BT non valido?</string>
<string name="gadgetbridge_running">Gadgetbridge in esecuzione</string> <string name="gadgetbridge_running">Gadgetbridge in esecuzione</string>
<string name="installing_binary_d_d">installazione del binario %1$d/%2$d</string> <string name="installing_binary_d_d">installazione del binario %1$d/%2$d</string>
@ -102,13 +100,11 @@
<string name="miband_pairing_using_dummy_userdata">Dati dell\'utente non inseriti, vengono usati dati d\'esempio.</string> <string name="miband_pairing_using_dummy_userdata">Dati dell\'utente non inseriti, vengono usati dati d\'esempio.</string>
<string name="miband_pairing_tap_hint">Quando la Mi Band vibra e lampeggia, dalle qualche leggero colpetto.</string> <string name="miband_pairing_tap_hint">Quando la Mi Band vibra e lampeggia, dalle qualche leggero colpetto.</string>
<string name="appinstaller_install">Installa</string> <string name="appinstaller_install">Installa</string>
<string name="discovery_connected_devices_hint">Imposta il tuo dispositivo perchè sia rilevabile. I dispositivi attualmente connessi non saranno probabilmente rilevati.</string>
<string name="discovery_note">Nota:</string> <string name="discovery_note">Nota:</string>
<string name="candidate_item_device_image">Immagine dispositivo</string> <string name="candidate_item_device_image">Immagine dispositivo</string>
<string name="miband_prefs_alias">Nome / Soprannome</string> <string name="miband_prefs_alias">Nome / Soprannome</string>
<string name="pref_header_vibration_count">Numero vibrazioni</string> <string name="pref_header_vibration_count">Numero vibrazioni</string>
<string name="title_activity_sleepmonitor">Monitoraggio del sonno</string> <string name="title_activity_sleepmonitor">Monitoraggio del sonno</string>
<string name="pref_write_logfiles">Salva il log su file</string>
<string name="initializing">inizializzazione in corso</string> <string name="initializing">inizializzazione in corso</string>
<string name="busy_task_fetch_activity_data">Recupero dati attività</string> <string name="busy_task_fetch_activity_data">Recupero dati attività</string>
<string name="sleep_activity_date_range">Da %1$s a %2$s</string> <string name="sleep_activity_date_range">Da %1$s a %2$s</string>
@ -179,9 +175,9 @@
<string name="chart_steps">Passi</string> <string name="chart_steps">Passi</string>
<string name="liveactivity_live_activity">Attività in tempo reale</string> <string name="liveactivity_live_activity">Attività in tempo reale</string>
<string name="weeksteps_today_steps_description">Passi di oggi, traguardo: %1$s</string> <string name="weeksteps_today_steps_description">Passi di oggi, traguardo: %1$s</string>
<string name="pref_title_dont_ack_transfer">Non confermare il trasferimento dati</string>
<string name="pref_summary_dont_ack_transfers">Se il trasferimento non viene confermato, i dati rimangono memorizzati sulla Mi Band. Utile se GB è usato insieme ad altre app.</string> <string name="pref_summary_dont_ack_transfers">Se il trasferimento non viene confermato, i dati rimangono memorizzati sulla Mi Band. Utile se GB è usato insieme ad altre app.</string>
<string name="pref_summary_keep_data_on_device">Conserva i dati delle attività sulla Mi Band anche dopo averli sincronizzati. Utile se GB è usato insieme ad altre app.</string> <string name="pref_summary_keep_data_on_device">Conserva i dati delle attività sulla Mi Band anche dopo averli sincronizzati. Utile se GB è usato insieme ad altre app.</string>
<string name="pref_title_dont_ack_transfer">Non confermare il trasferimento dati</string>
<string name="live_activity_steps_history">Storico dei passi</string> <string name="live_activity_steps_history">Storico dei passi</string>
<string name="live_activity_current_steps_per_minute">Passi/minuto</string> <string name="live_activity_current_steps_per_minute">Passi/minuto</string>
<string name="live_activity_total_steps">Passi totali</string> <string name="live_activity_total_steps">Passi totali</string>

View File

@ -14,6 +14,7 @@
<!--Strings related to AppManager--> <!--Strings related to AppManager-->
<string name="title_activity_appmanager">アプリ管理画面</string> <string name="title_activity_appmanager">アプリ管理画面</string>
<string name="appmananger_app_delete">削除</string> <string name="appmananger_app_delete">削除</string>
<string name="appmananger_app_delete_cache">キャッシュから削除</string>
<!--Strings related to AppBlacklist--> <!--Strings related to AppBlacklist-->
<string name="title_activity_appblacklist">ステータス通知ブラックリスト</string> <string name="title_activity_appblacklist">ステータス通知ブラックリスト</string>
<!--Strings related to FwAppInstaller--> <!--Strings related to FwAppInstaller-->
@ -44,6 +45,8 @@
<string name="pref_summary_notifications_pebblemsg">インテント経由でPebbleに通知を送信するアプリケーションをサポートします。Conversationsに使用することができます。</string> <string name="pref_summary_notifications_pebblemsg">インテント経由でPebbleに通知を送信するアプリケーションをサポートします。Conversationsに使用することができます。</string>
<string name="pref_title_notifications_generic">一般ステータス通知対応</string> <string name="pref_title_notifications_generic">一般ステータス通知対応</string>
<string name="pref_title_whenscreenon">… スクリーンがオンのときにも</string> <string name="pref_title_whenscreenon">… スクリーンがオンのときにも</string>
<string name="pref_title_notification_filter">サイレント</string>
<string name="pref_summary_notification_filter">サイレントモードに基づいて、送信される不要な通知を停止します。</string>
<string name="always">いつも</string> <string name="always">いつも</string>
<string name="when_screen_off">スクリーンがオフのとき</string> <string name="when_screen_off">スクリーンがオフのとき</string>
<string name="never">なし</string> <string name="never">なし</string>

View File

@ -181,9 +181,9 @@
<string name="chart_steps">걸음 수</string> <string name="chart_steps">걸음 수</string>
<string name="liveactivity_live_activity">실시간 활동</string> <string name="liveactivity_live_activity">실시간 활동</string>
<string name="weeksteps_today_steps_description">오늘 걸음 수, 목표: %1$s</string> <string name="weeksteps_today_steps_description">오늘 걸음 수, 목표: %1$s</string>
<string name="pref_title_dont_ack_transfer">활동 데이터 전송을 확인하지 않음</string>
<string name="pref_summary_dont_ack_transfers">만약 활동 데이터가 밴드에 확인되지 않았다면, 지워지지 않을 것입니다. 가젯브릿지가 다른 앱들과 같이 사용될 때 유용합니다.</string> <string name="pref_summary_dont_ack_transfers">만약 활동 데이터가 밴드에 확인되지 않았다면, 지워지지 않을 것입니다. 가젯브릿지가 다른 앱들과 같이 사용될 때 유용합니다.</string>
<string name="pref_summary_keep_data_on_device">동기화 이후에도 Mi Band의 활동 데이터가 유지될 것입니다. 가젯브릿지가 다른 앱들과 같이 사용될 때 유용합니다.</string> <string name="pref_summary_keep_data_on_device">동기화 이후에도 Mi Band의 활동 데이터가 유지될 것입니다. 가젯브릿지가 다른 앱들과 같이 사용될 때 유용합니다.</string>
<string name="pref_title_dont_ack_transfer">활동 데이터 전송을 확인하지 않음</string>
<string name="live_activity_steps_history">걸음 수 기록</string> <string name="live_activity_steps_history">걸음 수 기록</string>
<string name="live_activity_current_steps_per_minute">현재의 분당 걸음 수</string> <string name="live_activity_current_steps_per_minute">현재의 분당 걸음 수</string>
<string name="live_activity_total_steps">전체 걸음 수</string> <string name="live_activity_total_steps">전체 걸음 수</string>
@ -224,4 +224,5 @@
<string name="updatefirmwareoperation_firmware_not_sent">펌웨어가 전송되지 않음</string> <string name="updatefirmwareoperation_firmware_not_sent">펌웨어가 전송되지 않음</string>
<string name="charts_legend_heartrate">심박수</string> <string name="charts_legend_heartrate">심박수</string>
<string name="live_activity_heart_rate">심박수</string> <string name="live_activity_heart_rate">심박수</string>
<string name="pref_title_general_autocreonnect">자동으로 재연결</string>
</resources> </resources>

View File

@ -67,8 +67,6 @@
<string name="this_is_a_test_notification_from_gadgetbridge">To jest testowe powiadomienie z Gadgetbridge</string> <string name="this_is_a_test_notification_from_gadgetbridge">To jest testowe powiadomienie z Gadgetbridge</string>
<string name="bluetooth_is_not_supported_">Bluetooth nie jest obsługiwane</string> <string name="bluetooth_is_not_supported_">Bluetooth nie jest obsługiwane</string>
<string name="bluetooth_is_disabled_">Bluetooth jest wyłączone</string> <string name="bluetooth_is_disabled_">Bluetooth jest wyłączone</string>
<string name="tap_connected_device_for_app_mananger">Kliknij podłączone urządzenia dla zarządzania aplikacjami</string>
<string name="tap_a_device_to_connect">kliknij urządzenie by połączyć</string>
<string name="cannot_connect_bt_address_invalid_">Nie można połączyć. Adres BT nieprawidłowy?</string> <string name="cannot_connect_bt_address_invalid_">Nie można połączyć. Adres BT nieprawidłowy?</string>
<string name="gadgetbridge_running">Gadgetbridge działa</string> <string name="gadgetbridge_running">Gadgetbridge działa</string>
<string name="installing_binary_d_d">Instalowanie binarki %1$d/%2$d</string> <string name="installing_binary_d_d">Instalowanie binarki %1$d/%2$d</string>
@ -99,13 +97,11 @@
<string name="miband_pairing_using_dummy_userdata">Brak prawidłowych danych użytkownika, używam danych zastępczych na ten moment.</string> <string name="miband_pairing_using_dummy_userdata">Brak prawidłowych danych użytkownika, używam danych zastępczych na ten moment.</string>
<string name="miband_pairing_tap_hint">Gdy twój Mi Band wibruje i błyska, stuknij go kilka razy pod rząd.</string> <string name="miband_pairing_tap_hint">Gdy twój Mi Band wibruje i błyska, stuknij go kilka razy pod rząd.</string>
<string name="appinstaller_install">instaluj</string> <string name="appinstaller_install">instaluj</string>
<string name="discovery_connected_devices_hint">Uwidocznij swoje urządzenie. Aktualnie połączone urządzenia prawdopodobnie nie będą znalezione.</string>
<string name="discovery_note">Uwaga</string> <string name="discovery_note">Uwaga</string>
<string name="candidate_item_device_image">Obraz urządzenia</string> <string name="candidate_item_device_image">Obraz urządzenia</string>
<string name="miband_prefs_alias">Nazwisko/Pseudonim</string> <string name="miband_prefs_alias">Nazwisko/Pseudonim</string>
<string name="pref_header_vibration_count">Liczba wibracji</string> <string name="pref_header_vibration_count">Liczba wibracji</string>
<string name="title_activity_sleepmonitor">Monitor snu</string> <string name="title_activity_sleepmonitor">Monitor snu</string>
<string name="pref_write_logfiles">Zapisuj logi</string>
<string name="initializing">Uruchamianie</string> <string name="initializing">Uruchamianie</string>
<string name="busy_task_fetch_activity_data">Pobieranie danych aktywności</string> <string name="busy_task_fetch_activity_data">Pobieranie danych aktywności</string>
<string name="sleep_activity_date_range">Od %1$s do %2$s</string> <string name="sleep_activity_date_range">Od %1$s do %2$s</string>
@ -176,9 +172,9 @@
<string name="chart_steps">Kroki</string> <string name="chart_steps">Kroki</string>
<string name="liveactivity_live_activity">Ostatnia aktywność</string> <string name="liveactivity_live_activity">Ostatnia aktywność</string>
<string name="weeksteps_today_steps_description">Kroków dziś, cel: %1$s</string> <string name="weeksteps_today_steps_description">Kroków dziś, cel: %1$s</string>
<string name="pref_title_dont_ack_transfer">Nie wysyłaj danych aktywności</string>
<string name="pref_summary_dont_ack_transfers">Gdy dane aktywności nie są przesłane na opaskę, wtedy nie będą usuwane. Przydatne gdy Gadgetbridge jest używany wraz z innymi aplikacjami</string> <string name="pref_summary_dont_ack_transfers">Gdy dane aktywności nie są przesłane na opaskę, wtedy nie będą usuwane. Przydatne gdy Gadgetbridge jest używany wraz z innymi aplikacjami</string>
<string name="pref_summary_keep_data_on_device">Dane aktywności będą zachowane na Mi Band nawet po synchronizacji. Przydatne gdy Gadgetbridge jest używany z innymi aplikacjami.</string> <string name="pref_summary_keep_data_on_device">Dane aktywności będą zachowane na Mi Band nawet po synchronizacji. Przydatne gdy Gadgetbridge jest używany z innymi aplikacjami.</string>
<string name="pref_title_dont_ack_transfer">Nie wysyłaj danych aktywności</string>
<string name="live_activity_steps_history">Historia kroków</string> <string name="live_activity_steps_history">Historia kroków</string>
<string name="live_activity_current_steps_per_minute">Aktualnie kroków/min</string> <string name="live_activity_current_steps_per_minute">Aktualnie kroków/min</string>
<string name="live_activity_total_steps">Kroków łącznie</string> <string name="live_activity_total_steps">Kroków łącznie</string>

View File

@ -68,8 +68,6 @@
<string name="this_is_a_test_notification_from_gadgetbridge">Это тестовое уведомление от Gadgetbridge</string> <string name="this_is_a_test_notification_from_gadgetbridge">Это тестовое уведомление от Gadgetbridge</string>
<string name="bluetooth_is_not_supported_">Bluetooth не поддерживается.</string> <string name="bluetooth_is_not_supported_">Bluetooth не поддерживается.</string>
<string name="bluetooth_is_disabled_">Bluetooth отключён.</string> <string name="bluetooth_is_disabled_">Bluetooth отключён.</string>
<string name="tap_connected_device_for_app_mananger">нажмите на подключённое устройство для App Manager</string>
<string name="tap_a_device_to_connect">нажмите на устройство для соединения</string>
<string name="cannot_connect_bt_address_invalid_">Не удалось соединиться. Неверен адрес BT?</string> <string name="cannot_connect_bt_address_invalid_">Не удалось соединиться. Неверен адрес BT?</string>
<string name="gadgetbridge_running">Gadgetbridge запущен</string> <string name="gadgetbridge_running">Gadgetbridge запущен</string>
<string name="installing_binary_d_d">установки бинарного файла %1$d/%2$d</string> <string name="installing_binary_d_d">установки бинарного файла %1$d/%2$d</string>
@ -100,13 +98,11 @@
<string name="miband_pairing_using_dummy_userdata">Не предоставлено действительных данных пользователя. Используются данные по-умолчанию.</string> <string name="miband_pairing_using_dummy_userdata">Не предоставлено действительных данных пользователя. Используются данные по-умолчанию.</string>
<string name="miband_pairing_tap_hint">Когда ваш Mi Band вибрирует и мигает, постучите по нему несколько раз.</string> <string name="miband_pairing_tap_hint">Когда ваш Mi Band вибрирует и мигает, постучите по нему несколько раз.</string>
<string name="appinstaller_install">Установить</string> <string name="appinstaller_install">Установить</string>
<string name="discovery_connected_devices_hint">Подключённые в настоящее время устройства, скорее всего, не будут обнаружены.</string>
<string name="discovery_note">Заметка:</string> <string name="discovery_note">Заметка:</string>
<string name="candidate_item_device_image">Изображение устройства</string> <string name="candidate_item_device_image">Изображение устройства</string>
<string name="miband_prefs_alias">Имя/псевдоним</string> <string name="miband_prefs_alias">Имя/псевдоним</string>
<string name="pref_header_vibration_count">Количество вибраций</string> <string name="pref_header_vibration_count">Количество вибраций</string>
<string name="title_activity_sleepmonitor">Анализ сна</string> <string name="title_activity_sleepmonitor">Анализ сна</string>
<string name="pref_write_logfiles">Записывать файлы журнала</string>
<string name="initializing">Инициализация</string> <string name="initializing">Инициализация</string>
<string name="busy_task_fetch_activity_data">Получение данных активности</string> <string name="busy_task_fetch_activity_data">Получение данных активности</string>
<string name="sleep_activity_date_range">От %1$s до %2$s</string> <string name="sleep_activity_date_range">От %1$s до %2$s</string>
@ -177,9 +173,9 @@
<string name="chart_steps">Шаги</string> <string name="chart_steps">Шаги</string>
<string name="liveactivity_live_activity">Жизненная активность</string> <string name="liveactivity_live_activity">Жизненная активность</string>
<string name="weeksteps_today_steps_description">Шагов сегодня, цель: %1$s</string> <string name="weeksteps_today_steps_description">Шагов сегодня, цель: %1$s</string>
<string name="pref_title_dont_ack_transfer">Не передавать данные об активности</string>
<string name="pref_summary_dont_ack_transfers">Если данные об активности не будут переданы на устройство, оно не будет очищено. Полезно, если GB используется с другими приложениями.</string> <string name="pref_summary_dont_ack_transfers">Если данные об активности не будут переданы на устройство, оно не будет очищено. Полезно, если GB используется с другими приложениями.</string>
<string name="pref_summary_keep_data_on_device">Хранить данные о деятельности на Mi Band, даже после синхронизации. Полезно, если Mi Band используется совместно с другими приложениями.</string> <string name="pref_summary_keep_data_on_device">Хранить данные о деятельности на Mi Band, даже после синхронизации. Полезно, если Mi Band используется совместно с другими приложениями.</string>
<string name="pref_title_dont_ack_transfer">Не передавать данные об активности</string>
<string name="live_activity_steps_history">История шагов</string> <string name="live_activity_steps_history">История шагов</string>
<string name="live_activity_current_steps_per_minute">Текущие шаги в минуту</string> <string name="live_activity_current_steps_per_minute">Текущие шаги в минуту</string>
<string name="live_activity_total_steps">Всего шагов</string> <string name="live_activity_total_steps">Всего шагов</string>

View File

@ -31,6 +31,9 @@
<string name="pref_header_datetime">Дата і час</string> <string name="pref_header_datetime">Дата і час</string>
<string name="pref_title_datetime_syctimeonconnect">Синхронізувати час під час з\'єднання</string> <string name="pref_title_datetime_syctimeonconnect">Синхронізувати час під час з\'єднання</string>
<string name="pref_summary_datetime_syctimeonconnect">Синхронізувати час під час з\'єднання з пристроєм, а також під час зміни часу чи часової зони в системі</string> <string name="pref_summary_datetime_syctimeonconnect">Синхронізувати час під час з\'єднання з пристроєм, а також під час зміни часу чи часової зони в системі</string>
<string name="pref_title_theme">Тема</string>
<string name="pref_theme_light">Світла</string>
<string name="pref_theme_dark">Темна</string>
<string name="pref_header_notifications">Сповіщення</string> <string name="pref_header_notifications">Сповіщення</string>
<string name="pref_title_notifications_repetitions">Повтори</string> <string name="pref_title_notifications_repetitions">Повтори</string>
<string name="pref_title_notifications_call">Виклики</string> <string name="pref_title_notifications_call">Виклики</string>
@ -67,8 +70,6 @@
<string name="this_is_a_test_notification_from_gadgetbridge">Це тестове сповіщення від Gadgetbridge</string> <string name="this_is_a_test_notification_from_gadgetbridge">Це тестове сповіщення від Gadgetbridge</string>
<string name="bluetooth_is_not_supported_">Bluetooth не підтримується.</string> <string name="bluetooth_is_not_supported_">Bluetooth не підтримується.</string>
<string name="bluetooth_is_disabled_">Bluetooth вимкнуто.</string> <string name="bluetooth_is_disabled_">Bluetooth вимкнуто.</string>
<string name="tap_connected_device_for_app_mananger">натисніть на під\'єднаний пристрій для App Manager</string>
<string name="tap_a_device_to_connect">натисніть на пристрій для з\'єднання</string>
<string name="cannot_connect_bt_address_invalid_">Не вдалося з\'єднатися. Можливо помилкова адреса BT?</string> <string name="cannot_connect_bt_address_invalid_">Не вдалося з\'єднатися. Можливо помилкова адреса BT?</string>
<string name="gadgetbridge_running">Gadgetbridge запущено</string> <string name="gadgetbridge_running">Gadgetbridge запущено</string>
<string name="installing_binary_d_d">встановлення бінарного файлу %1$d/%2$d</string> <string name="installing_binary_d_d">встановлення бінарного файлу %1$d/%2$d</string>
@ -99,13 +100,11 @@
<string name="miband_pairing_using_dummy_userdata">Не отримано дійсних даних користувача. Використовуються типові дані.</string> <string name="miband_pairing_using_dummy_userdata">Не отримано дійсних даних користувача. Використовуються типові дані.</string>
<string name="miband_pairing_tap_hint">Коли ваш Mi—Band вібрує та блимає, постукайте по ньому кілька раз.</string> <string name="miband_pairing_tap_hint">Коли ваш Mi—Band вібрує та блимає, постукайте по ньому кілька раз.</string>
<string name="appinstaller_install">Встановити</string> <string name="appinstaller_install">Встановити</string>
<string name="discovery_connected_devices_hint">Під\'єднані на даний момент пристрої, скоріш за все не будуть виявлені.</string>
<string name="discovery_note">Замітка:</string> <string name="discovery_note">Замітка:</string>
<string name="candidate_item_device_image">Зображення пристрою</string> <string name="candidate_item_device_image">Зображення пристрою</string>
<string name="miband_prefs_alias">Ім\'я/нік</string> <string name="miband_prefs_alias">Ім\'я/нік</string>
<string name="pref_header_vibration_count">Кількість вібрацій</string> <string name="pref_header_vibration_count">Кількість вібрацій</string>
<string name="title_activity_sleepmonitor">Аналіз сну</string> <string name="title_activity_sleepmonitor">Аналіз сну</string>
<string name="pref_write_logfiles">Записувати файли звіту</string>
<string name="initializing">Ініціалізація…</string> <string name="initializing">Ініціалізація…</string>
<string name="busy_task_fetch_activity_data">Отримання даних активності</string> <string name="busy_task_fetch_activity_data">Отримання даних активності</string>
<string name="sleep_activity_date_range">Від %1$s до %2$s</string> <string name="sleep_activity_date_range">Від %1$s до %2$s</string>
@ -176,9 +175,9 @@
<string name="chart_steps">Кроки</string> <string name="chart_steps">Кроки</string>
<string name="liveactivity_live_activity">Життєва активність</string> <string name="liveactivity_live_activity">Життєва активність</string>
<string name="weeksteps_today_steps_description">Кроків сьогодні, мета: %1$s</string> <string name="weeksteps_today_steps_description">Кроків сьогодні, мета: %1$s</string>
<string name="pref_title_dont_ack_transfer">Не передавати дані про активність</string>
<string name="pref_summary_dont_ack_transfers">Якщо дані не будуть передані на пристрій, пристрій не буде очищений. Корисно, якщо Gadgetbridge використовується разом з іншими додатками.</string> <string name="pref_summary_dont_ack_transfers">Якщо дані не будуть передані на пристрій, пристрій не буде очищений. Корисно, якщо Gadgetbridge використовується разом з іншими додатками.</string>
<string name="pref_summary_keep_data_on_device">Дозволяє лишити дані на Mi-браслеті після синхронізації. Зазвичай використовується, якщо GB працює ще з іншими додатками.</string> <string name="pref_summary_keep_data_on_device">Дозволяє лишити дані на Mi-браслеті після синхронізації. Зазвичай використовується, якщо GB працює ще з іншими додатками.</string>
<string name="pref_title_dont_ack_transfer">Не передавати дані про активність</string>
<string name="live_activity_steps_history">Історія кроків</string> <string name="live_activity_steps_history">Історія кроків</string>
<string name="live_activity_current_steps_per_minute">Поточні кроки/хв</string> <string name="live_activity_current_steps_per_minute">Поточні кроки/хв</string>
<string name="live_activity_total_steps">Загалом кроків</string> <string name="live_activity_total_steps">Загалом кроків</string>

View File

@ -52,8 +52,6 @@
<string name="this_is_a_test_notification_from_gadgetbridge">Đây là một kiểm tra thông báo từ Gadgetbridge</string> <string name="this_is_a_test_notification_from_gadgetbridge">Đây là một kiểm tra thông báo từ Gadgetbridge</string>
<string name="bluetooth_is_not_supported_">Không hỗ trợ Bluetooth.</string> <string name="bluetooth_is_not_supported_">Không hỗ trợ Bluetooth.</string>
<string name="bluetooth_is_disabled_">Đã tắt Bluetooth.</string> <string name="bluetooth_is_disabled_">Đã tắt Bluetooth.</string>
<string name="tap_connected_device_for_app_mananger">chạm vào thiết bị đã kết nối để chạy Trình quản lý ứng dụng</string>
<string name="tap_a_device_to_connect">chạm vào một thiết bị để kết nối</string>
<string name="cannot_connect_bt_address_invalid_">Không thể kết nối. Địa chỉ BT không hợp lệ?</string> <string name="cannot_connect_bt_address_invalid_">Không thể kết nối. Địa chỉ BT không hợp lệ?</string>
<string name="gadgetbridge_running">Gadgetbridge đang chạy</string> <string name="gadgetbridge_running">Gadgetbridge đang chạy</string>
<string name="installing_binary_d_d">đang cài phần mềm chạy %1$d/%2$d</string> <string name="installing_binary_d_d">đang cài phần mềm chạy %1$d/%2$d</string>
@ -83,7 +81,6 @@
<string name="candidate_item_device_image">Ảnh thiết bị</string> <string name="candidate_item_device_image">Ảnh thiết bị</string>
<string name="miband_prefs_alias">Tên/Bí danh</string> <string name="miband_prefs_alias">Tên/Bí danh</string>
<string name="title_activity_sleepmonitor">Trình giám sát giấc ngủ</string> <string name="title_activity_sleepmonitor">Trình giám sát giấc ngủ</string>
<string name="pref_write_logfiles">Ghi tập tin nhật ký</string>
<string name="initializing">đang khởi chạy</string> <string name="initializing">đang khởi chạy</string>
<string name="sleep_activity_date_range">Từ %1$s đến %2$s</string> <string name="sleep_activity_date_range">Từ %1$s đến %2$s</string>
<string name="miband_prefs_wearside">Đeo bên trái hay phải?</string> <string name="miband_prefs_wearside">Đeo bên trái hay phải?</string>

View File

@ -17,6 +17,7 @@
<!-- Strings related to AppManager --> <!-- Strings related to AppManager -->
<string name="title_activity_appmanager">App Manager</string> <string name="title_activity_appmanager">App Manager</string>
<string name="appmananger_app_delete">Delete</string> <string name="appmananger_app_delete">Delete</string>
<string name="appmananger_app_delete_cache">Delete and remove from cache</string>
<!-- Strings related to AppBlacklist --> <!-- Strings related to AppBlacklist -->
<string name="title_activity_appblacklist">Notification Blacklist</string> <string name="title_activity_appblacklist">Notification Blacklist</string>
@ -52,6 +53,8 @@
<string name="pref_summary_notifications_pebblemsg">Support for applications which send Notifications to the Pebble via Intent. Can be used for Conversations.</string> <string name="pref_summary_notifications_pebblemsg">Support for applications which send Notifications to the Pebble via Intent. Can be used for Conversations.</string>
<string name="pref_title_notifications_generic">Generic notification support</string> <string name="pref_title_notifications_generic">Generic notification support</string>
<string name="pref_title_whenscreenon">… also when screen is on</string> <string name="pref_title_whenscreenon">… also when screen is on</string>
<string name="pref_title_notification_filter">Do Not Disturb</string>
<string name="pref_summary_notification_filter">Stop unwanted Notifications from being sent based on the Do Not Disturb mode.</string>
<string name="always">always</string> <string name="always">always</string>
<string name="when_screen_off">when screen is off</string> <string name="when_screen_off">when screen is off</string>
@ -249,5 +252,4 @@
<string name="charts_legend_heartrate">Heart Rate</string> <string name="charts_legend_heartrate">Heart Rate</string>
<string name="live_activity_heart_rate">Heart Rate</string> <string name="live_activity_heart_rate">Heart Rate</string>
<string name="pref_title_general_autocreonnect">Reconnect automatically</string> <string name="pref_title_general_autocreonnect">Reconnect automatically</string>
</resources> </resources>

View File

@ -1,5 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<changelog> <changelog>
<release version="0.9.8" versioncode="52">
<change>Pebble: fix more reconnnect issues</change>
<change>Pebble: fix deep sleep not being detected with Firmware 3.12 when using Pebble Health</change>
<change>Pebble: option in AppManager to delete files from cache</change>
<change>Pebble: enable pbw cache and watchface configuration for Firmware 2.x</change>
<change>Pebble: allow enabling of Pebble Health without "untested features" being enabled</change>
<change>Honour "Do Not Disturb" for phone calls and SMS</change>
</release>
<release version="0.9.7" versioncode="51"> <release version="0.9.7" versioncode="51">
<change>Pebble: hopefully fix some reconnect issues</change> <change>Pebble: hopefully fix some reconnect issues</change>
<change>Mi Band: fix live activity monitoring running forever if back button pressed</change> <change>Mi Band: fix live activity monitoring running forever if back button pressed</change>

View File

@ -77,6 +77,13 @@
android:defaultValue="false" android:defaultValue="false"
android:key="notifications_generic_whenscreenon" android:key="notifications_generic_whenscreenon"
android:title="@string/pref_title_whenscreenon" /> android:title="@string/pref_title_whenscreenon" />
<CheckBoxPreference
android:defaultValue="false"
android:key="notification_filter"
android:summary="@string/pref_summary_notification_filter"
android:title="@string/pref_title_notification_filter" />
<Preference <Preference
android:key="pref_key_blacklist" android:key="pref_key_blacklist"
android:title="@string/pref_blacklist" /> android:title="@string/pref_blacklist" />