Merge branch 'master' of https://github.com/Freeyourgadget/Gadgetbridge into feature-weather

here
danielegobbetti 2016-01-09 18:48:39 +01:00
commit 4bb78722b5
19 changed files with 487 additions and 87 deletions

View File

@ -29,7 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceService;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.IDSenderLookup;
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
//import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver;
@ -45,7 +45,7 @@ public class GBApplication extends Application {
private static final Lock dbLock = new ReentrantLock();
private static DeviceService deviceService;
private static SharedPreferences sharedPrefs;
private static IDSenderLookup mIDSenderLookup = new IDSenderLookup();
private static LimitedQueue mIDSenderLookup = new LimitedQueue(16);
public static final String ACTION_QUIT
= "nodomain.freeyourgadget.gadgetbridge.gbapplication.action.quit";
@ -61,10 +61,7 @@ public class GBApplication extends Application {
}
};
//private BluetoothConnectReceiver systemBTReceiver = new BluetoothConnectReceiver();
private void quit() {
//unregisterSystemBTReceiver();
GB.removeAllNotifications(this);
}
@ -103,25 +100,11 @@ public class GBApplication extends Application {
filterLocal.addAction(ACTION_QUIT);
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
//registerSystemBTReceiver();
// for testing DB stuff
// SQLiteDatabase db = mActivityDatabaseHandler.getWritableDatabase();
// db.close();
}
/*
private void registerSystemBTReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction("android.bluetooth.device.action.ACL_CONNECTED");
filter.addAction("android.bluetooth.device.action.ACL_CONNECTED");
registerReceiver(systemBTReceiver, filter);
}
private void unregisterSystemBTReceiver() {
unregisterReceiver(systemBTReceiver);
}
*/
private void setupExceptionHandler() {
LoggingExceptionHandler handler = new LoggingExceptionHandler(Thread.getDefaultUncaughtExceptionHandler());
Thread.setDefaultUncaughtExceptionHandler(handler);
@ -259,7 +242,7 @@ public class GBApplication extends Application {
return result;
}
public static IDSenderLookup getIDSenderLookup() {
public static LimitedQueue getIDSenderLookup() {
return mIDSenderLookup;
}
}

View File

@ -13,6 +13,7 @@ import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.RemoteInput;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
@ -38,6 +39,10 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class DebugActivity extends Activity {
private static final Logger LOG = LoggerFactory.getLogger(DebugActivity.class);
private static final String EXTRA_REPLY = "reply";
private static final String ACTION_REPLY
= "nodomain.freeyourgadget.gadgetbridge.DebugActivity.action.reply";
private Button sendSMSButton;
private Button sendEmailButton;
private Button incomingCallButton;
@ -56,8 +61,16 @@ public class DebugActivity extends Activity {
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(GBApplication.ACTION_QUIT)) {
finish();
switch (intent.getAction()) {
case GBApplication.ACTION_QUIT:
finish();
break;
case ACTION_REPLY:
Bundle remoteInput = RemoteInput.getResultsFromIntent(intent);
CharSequence reply = remoteInput.getCharSequence(EXTRA_REPLY);
LOG.info("got wearable reply: " + reply);
GB.toast(context, "got wearable reply: " + reply, Toast.LENGTH_SHORT, GB.INFO);
break;
}
}
};
@ -68,7 +81,10 @@ public class DebugActivity extends Activity {
setContentView(R.layout.activity_debug);
getActionBar().setDisplayHomeAsUpEnabled(true);
registerReceiver(mReceiver, new IntentFilter(GBApplication.ACTION_QUIT));
IntentFilter filter = new IntentFilter();
filter.addAction(GBApplication.ACTION_QUIT);
filter.addAction(ACTION_REPLY);
registerReceiver(mReceiver, filter);
editContent = (EditText) findViewById(R.id.editContent);
sendSMSButton = (Button) findViewById(R.id.sendSMSButton);
@ -216,27 +232,42 @@ public class DebugActivity extends Activity {
}
private void importDB() {
DBHandler dbHandler = null;
try {
dbHandler = GBApplication.acquireDB();
DBHelper helper = new DBHelper(this);
File dir = FileUtils.getExternalFilesDir();
SQLiteOpenHelper sqLiteOpenHelper = dbHandler.getHelper();
File sourceFile = new File(dir, sqLiteOpenHelper.getDatabaseName());
helper.importDB(sqLiteOpenHelper, sourceFile);
helper.validateDB(sqLiteOpenHelper);
GB.toast(this, "Import successful.", Toast.LENGTH_LONG, GB.INFO);
} catch (Exception ex) {
GB.toast(this, "Error importing DB: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
} finally {
if (dbHandler != null) {
dbHandler.release();
}
}
new AlertDialog.Builder(this)
.setCancelable(true)
.setTitle("Import Activity Data?")
.setMessage("Really overwrite the current activity database? All your activity data (if any) will be lost.")
.setPositiveButton("Overwrite", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
DBHandler dbHandler = null;
try {
dbHandler = GBApplication.acquireDB();
DBHelper helper = new DBHelper(DebugActivity.this);
File dir = FileUtils.getExternalFilesDir();
SQLiteOpenHelper sqLiteOpenHelper = dbHandler.getHelper();
File sourceFile = new File(dir, sqLiteOpenHelper.getDatabaseName());
helper.importDB(sqLiteOpenHelper, sourceFile);
helper.validateDB(sqLiteOpenHelper);
GB.toast(DebugActivity.this, "Import successful.", Toast.LENGTH_LONG, GB.INFO);
} catch (Exception ex) {
GB.toast(DebugActivity.this, "Error importing DB: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
} finally {
if (dbHandler != null) {
dbHandler.release();
}
}
}
})
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.show();
}
private void deleteActivityDatabase() {
AlertDialog dialog = new AlertDialog.Builder(this)
new AlertDialog.Builder(this)
.setCancelable(true)
.setTitle("Delete Activity Data?")
.setMessage("Really delete the entire activity database? All your activity data will be lost.")
@ -266,13 +297,30 @@ public class DebugActivity extends Activity {
notificationIntent, 0);
NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationCompat.Builder ncomp = new NotificationCompat.Builder(this);
ncomp.setContentTitle(getString(R.string.test_notification));
ncomp.setContentText(getString(R.string.this_is_a_test_notification_from_gadgetbridge));
ncomp.setTicker(getString(R.string.this_is_a_test_notification_from_gadgetbridge));
ncomp.setSmallIcon(R.drawable.ic_notification);
ncomp.setAutoCancel(true);
ncomp.setContentIntent(pendingIntent);
RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_REPLY)
.build();
Intent replyIntent = new Intent(ACTION_REPLY);
PendingIntent replyPendingIntent = PendingIntent.getBroadcast(this, 0, replyIntent, 0);
NotificationCompat.Action action =
new NotificationCompat.Action.Builder(android.R.drawable.ic_input_add, "Reply", replyPendingIntent)
.addRemoteInput(remoteInput)
.build();
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender().addAction(action);
NotificationCompat.Builder ncomp = new NotificationCompat.Builder(this)
.setContentTitle(getString(R.string.test_notification))
.setContentText(getString(R.string.this_is_a_test_notification_from_gadgetbridge))
.setTicker(getString(R.string.this_is_a_test_notification_from_gadgetbridge))
.setSmallIcon(R.drawable.ic_notification)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.extend(wearableExtender);
nManager.notify((int) System.currentTimeMillis(), ncomp.build());
}

View File

@ -30,7 +30,9 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator {
@Override
public boolean supports(GBDeviceCandidate candidate) {
return candidate.getMacAddress().toUpperCase().startsWith(MiBandService.MAC_ADDRESS_FILTER);
String macAddress = candidate.getMacAddress().toUpperCase();
return macAddress.startsWith(MiBandService.MAC_ADDRESS_FILTER_1_1A)
|| macAddress.startsWith(MiBandService.MAC_ADDRESS_FILTER_1S);
}
@Override
@ -74,7 +76,7 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator {
}
public static boolean hasValidUserInfo() {
String dummyMacAddress = MiBandService.MAC_ADDRESS_FILTER + ":00:00:00";
String dummyMacAddress = MiBandService.MAC_ADDRESS_FILTER_1_1A + ":00:00:00";
try {
UserInfo userInfo = getConfiguredUserInfo(dummyMacAddress);
return true;

View File

@ -1,15 +1,18 @@
package nodomain.freeyourgadget.gadgetbridge.devices.miband;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
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.os.Handler;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
@ -29,9 +32,12 @@ public class MiBandPairingActivity extends Activity {
private static final int REQ_CODE_USER_SETTINGS = 52;
private static final String STATE_MIBAND_ADDRESS = "mibandMacAddress";
private static final long DELAY_AFTER_BONDING = 1000; // 1s
private TextView message;
private boolean isPairing;
private String macAddress;
private String bondingMacAddress;
private final BroadcastReceiver mPairingReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@ -45,6 +51,29 @@ public class MiBandPairingActivity extends Activity {
}
};
private final BroadcastReceiver mBondingReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (BluetoothDevice.ACTION_BOND_STATE_CHANGED.equals(intent.getAction())) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (bondingMacAddress != null && bondingMacAddress.equals(device.getAddress())) {
int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.BOND_NONE);
if (bondState == BluetoothDevice.BOND_BONDED) {
LOG.info("Bonded with " + device.getAddress());
bondingMacAddress = null;
Looper mainLooper = Looper.getMainLooper();
new Handler(mainLooper).postDelayed(new Runnable() {
@Override
public void run() {
performPair();
}
}, DELAY_AFTER_BONDING);
}
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -99,7 +128,13 @@ public class MiBandPairingActivity extends Activity {
@Override
protected void onDestroy() {
LocalBroadcastManager.getInstance(this).unregisterReceiver(mPairingReceiver);
try {
// just to be sure, remove the receivers -- might actually be already unregistered
LocalBroadcastManager.getInstance(this).unregisterReceiver(mPairingReceiver);
unregisterReceiver(mBondingReceiver);
} catch (IllegalArgumentException ex) {
// already unregistered, ignore
}
if (isPairing) {
stopPairing();
}
@ -109,15 +144,24 @@ public class MiBandPairingActivity extends Activity {
private void startPairing() {
isPairing = true;
message.setText(getString(R.string.miband_pairing, macAddress));
IntentFilter filter = new IntentFilter(GBDevice.ACTION_DEVICE_CHANGED);
LocalBroadcastManager.getInstance(this).registerReceiver(mPairingReceiver, filter);
filter = new IntentFilter(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
registerReceiver(mBondingReceiver, filter);
GBApplication.deviceService().connect(macAddress, true);
BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(macAddress);
if (device != null) {
performBluetoothPair(device);
} else {
GB.toast(this, "No such Bluetooth Device: " + macAddress, Toast.LENGTH_LONG, GB.ERROR);
}
}
private void pairingFinished(boolean pairedSuccessfully) {
isPairing = false;
LocalBroadcastManager.getInstance(this).unregisterReceiver(mPairingReceiver);
unregisterReceiver(mBondingReceiver);
if (pairedSuccessfully) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
@ -133,4 +177,27 @@ public class MiBandPairingActivity extends Activity {
// TODO
isPairing = false;
}
protected void performBluetoothPair(BluetoothDevice device) {
int bondState = device.getBondState();
if (bondState == BluetoothDevice.BOND_BONDED) {
LOG.info("Already bonded: " + device.getAddress());
performPair();
return;
}
bondingMacAddress = device.getAddress();
if (bondState == BluetoothDevice.BOND_BONDING) {
LOG.info("Bonding in progress: " + device.getAddress());
return;
}
if (!device.createBond()) {
GB.toast(this, "Unable to pair with " + device.getAddress(), Toast.LENGTH_LONG, GB.ERROR);
}
}
private void performPair() {
GBApplication.deviceService().connect(macAddress, true);
}
}

View File

@ -9,7 +9,8 @@ import static nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDevi
public class MiBandService {
public static final String MAC_ADDRESS_FILTER = "88:0F:10";
public static final String MAC_ADDRESS_FILTER_1_1A = "88:0F:10";
public static final String MAC_ADDRESS_FILTER_1S = "C8:0F:10";
public static final UUID UUID_SERVICE_MIBAND_SERVICE = UUID.fromString(String.format(BASE_UUID, "FEE0"));

View File

@ -16,15 +16,20 @@ import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.RemoteInput;
import android.support.v4.content.LocalBroadcastManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
public class NotificationListener extends NotificationListenerService {
@ -38,6 +43,10 @@ public class NotificationListener extends NotificationListenerService {
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.open";
public static final String ACTION_MUTE
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.mute";
public static final String ACTION_REPLY
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.reply";
private LimitedQueue mActionLookup = new LimitedQueue(16);
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@SuppressLint("NewApi")
@ -90,6 +99,28 @@ public class NotificationListener extends NotificationListenerService {
case ACTION_DISMISS_ALL:
NotificationListener.this.cancelAllNotifications();
break;
case ACTION_REPLY:
int id = intent.getIntExtra("handle", -1);
String reply = intent.getStringExtra("reply");
NotificationCompat.Action replyAction = (NotificationCompat.Action) mActionLookup.lookup(id);
if (replyAction != null && replyAction.getRemoteInputs() != null) {
RemoteInput[] remoteInputs = replyAction.getRemoteInputs();
PendingIntent actionIntent = replyAction.getActionIntent();
Intent localIntent = new Intent();
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Bundle extras = new Bundle();
extras.putCharSequence(remoteInputs[0].getResultKey(), reply);
RemoteInput.addResultsToIntent(remoteInputs, localIntent, extras);
try {
LOG.info("will send reply intent to remote application");
actionIntent.send(context, 0, localIntent);
mActionLookup.remove(id);
} catch (PendingIntent.CanceledException e) {
LOG.warn("replyToLastNotification error: " + e.getLocalizedMessage());
}
}
break;
}
}
@ -103,6 +134,7 @@ public class NotificationListener extends NotificationListenerService {
filterLocal.addAction(ACTION_DISMISS);
filterLocal.addAction(ACTION_DISMISS_ALL);
filterLocal.addAction(ACTION_MUTE);
filterLocal.addAction(ACTION_REPLY);
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
}
@ -222,6 +254,18 @@ public class NotificationListener extends NotificationListenerService {
dissectNotificationTo(notification, notificationSpec);
notificationSpec.id = (int) sbn.getPostTime(); //FIMXE: a truly unique id would be better
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender(notification);
List<NotificationCompat.Action> actions = wearableExtender.getActions();
for (NotificationCompat.Action act : actions) {
if (act != null && act.getRemoteInputs() != null) {
LOG.info("found wearable action: " + act.getTitle() + " " + sbn.getTag());
mActionLookup.add(notificationSpec.id, act);
notificationSpec.flags |= NotificationSpec.FLAG_WEARABLE_REPLY;
break;
}
}
GBApplication.deviceService().onNotification(notificationSpec);
}

View File

@ -89,6 +89,7 @@ public class GBDeviceService implements DeviceService {
@Override
public void onNotification(NotificationSpec notificationSpec) {
Intent intent = createIntent().setAction(ACTION_NOTIFICATION)
.putExtra(EXTRA_NOTIFICATION_FLAGS, notificationSpec.flags)
.putExtra(EXTRA_NOTIFICATION_PHONENUMBER, notificationSpec.phoneNumber)
.putExtra(EXTRA_NOTIFICATION_SENDER, notificationSpec.sender)
.putExtra(EXTRA_NOTIFICATION_SUBJECT, notificationSpec.subject)

View File

@ -35,6 +35,7 @@ public interface DeviceService extends EventHandler {
String EXTRA_DEVICE_ADDRESS = "device_address";
String EXTRA_NOTIFICATION_BODY = "notification_body";
String EXTRA_NOTIFICATION_FLAGS = "notification_flags";
String EXTRA_NOTIFICATION_ID = "notification_id";
String EXTRA_NOTIFICATION_PHONENUMBER = "notification_phonenumber";
String EXTRA_NOTIFICATION_SENDER = "notification_sender";

View File

@ -1,6 +1,9 @@
package nodomain.freeyourgadget.gadgetbridge.model;
public class NotificationSpec {
public static final int FLAG_WEARABLE_REPLY = 0x00000001;
public int flags;
public int id;
public String sender;
public String phoneNumber;

View File

@ -229,16 +229,22 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
action = NotificationListener.ACTION_MUTE;
break;
case REPLY:
String phoneNumber = GBApplication.getIDSenderLookup().lookup(deviceEvent.handle);
String phoneNumber = (String) GBApplication.getIDSenderLookup().lookup(deviceEvent.handle);
if (phoneNumber != null) {
LOG.info("got notfication reply for " + phoneNumber + " : " + deviceEvent.reply);
LOG.info("got notfication reply for SMS from " + phoneNumber + " : " + deviceEvent.reply);
SmsManager.getDefault().sendTextMessage(phoneNumber, null, deviceEvent.reply, null, null);
} else {
LOG.info("got notfication reply for notification id " + deviceEvent.handle + " : " + deviceEvent.reply);
action = NotificationListener.ACTION_REPLY;
}
break;
}
if (action != null) {
Intent notificationListenerIntent = new Intent(action);
notificationListenerIntent.putExtra("handle", deviceEvent.handle);
if (deviceEvent.reply != null) {
notificationListenerIntent.putExtra("reply", deviceEvent.reply);
}
LocalBroadcastManager.getInstance(context).sendBroadcast(notificationListenerIntent);
}
}

View File

@ -39,7 +39,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.IDSenderLookup;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CALLSTATE;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT;
@ -71,6 +70,7 @@ 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_FLAGS;
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;
@ -219,13 +219,16 @@ public class DeviceCommunicationService extends Service {
notificationSpec.body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY);
notificationSpec.type = (NotificationType) intent.getSerializableExtra(EXTRA_NOTIFICATION_TYPE);
notificationSpec.id = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
notificationSpec.flags = intent.getIntExtra(EXTRA_NOTIFICATION_FLAGS, 0);
notificationSpec.sourceName = intent.getStringExtra(EXTRA_NOTIFICATION_SOURCENAME);
if (notificationSpec.type == NotificationType.SMS && notificationSpec.phoneNumber != null) {
notificationSpec.sender = getContactDisplayNameByNumber(notificationSpec.phoneNumber);
notificationSpec.id = mRandom.nextInt(); // FIXME: add this in external SMS Receiver?
GBApplication.getIDSenderLookup().add(notificationSpec.id, notificationSpec.phoneNumber);
}
if (((notificationSpec.flags & NotificationSpec.FLAG_WEARABLE_REPLY) > 0)
|| (notificationSpec.type == NotificationType.SMS && notificationSpec.phoneNumber != null)) {
// NOTE: maybe not where it belongs
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
if (sharedPrefs.getBoolean("pebble_force_untested", false)) {

View File

@ -9,6 +9,7 @@ import java.io.IOException;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations.OperationStatus;
/**
* Abstract base class for a BTLEOperation, i.e. an operation that does more than
@ -25,6 +26,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
*/
public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport> implements GattCallback, BTLEOperation {
private final T mSupport;
protected OperationStatus operationStatus = OperationStatus.INITIAL;
protected AbstractBTLEOperation(T support) {
mSupport = support;
@ -38,7 +40,9 @@ public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport>
*/
@Override
public final void perform() throws IOException {
operationStatus = OperationStatus.STARTED;
prePerform();
operationStatus = OperationStatus.RUNNING;
doPerform();
}
@ -101,6 +105,10 @@ public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport>
getDevice().sendDeviceUpdateIntent(getContext());
}
public boolean isOperationRunning() {
return operationStatus == OperationStatus.RUNNING;
}
public T getSupport() {
return mSupport;
}

View File

@ -25,6 +25,7 @@ public abstract class AbstractMiBandOperation extends AbstractBTLEOperation<MiBa
@Override
protected void operationFinished() {
operationStatus = OperationStatus.FINISHED;
if (getDevice() != null && getDevice().isConnected()) {
try {
TransactionBuilder builder = performInitialized("reenabling disabled notifications");

View File

@ -174,6 +174,12 @@ public class FetchActivityOperation extends AbstractMiBandOperation {
* @see #bufferActivityData(byte[])
*/
private void handleActivityNotif(byte[] value) {
if (!isOperationRunning()) {
LOG.error("ignoring activity data notification because operation is not running. Data length: " + value.length);
getSupport().logMessageContent(value);
return;
}
if (value.length == activityMetadataLength) {
handleActivityMetadata(value);
} else {

View File

@ -0,0 +1,8 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations;
public enum OperationStatus {
INITIAL,
STARTED,
RUNNING,
FINISHED
}

View File

@ -1590,14 +1590,14 @@ public class PebbleProtocol extends GBDeviceProtocol {
byte[] reply = new byte[length];
buf.get(reply);
// FIXME: this does not belong here, but we want at least check if there is no chance at all to send out the SMS later before we report success
String phoneNumber = GBApplication.getIDSenderLookup().lookup(id);
if (phoneNumber != null) {
String phoneNumber = (String) GBApplication.getIDSenderLookup().lookup(id);
//if (phoneNumber != null) {
devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.REPLY;
devEvtNotificationControl.reply = new String(reply);
caption = "SENT";
icon_id = PebbleIconID.RESULT_SENT;
failed = false;
}
//}
}
}
if (failed) {

View File

@ -1,26 +0,0 @@
package nodomain.freeyourgadget.gadgetbridge.util;
import android.util.Pair;
import java.util.LinkedList;
public class IDSenderLookup {
private static final int LIMIT = 16;
private LinkedList<Pair> list = new LinkedList<>();
public void add(int id, String sender) {
if (list.size() > LIMIT - 1) {
list.removeFirst();
}
list.add(new Pair<>(id, sender));
}
public String lookup(int id) {
for (Pair entry : list) {
if (id == (Integer) entry.first) {
return (String) entry.second;
}
}
return null;
}
}

View File

@ -0,0 +1,40 @@
package nodomain.freeyourgadget.gadgetbridge.util;
import android.util.Pair;
import java.util.Iterator;
import java.util.LinkedList;
public class LimitedQueue {
private final int limit;
private LinkedList<Pair> list = new LinkedList<>();
public LimitedQueue(int limit) {
this.limit = limit;
}
public void add(int id, Object obj) {
if (list.size() > limit - 1) {
list.removeFirst();
}
list.add(new Pair<>(id, obj));
}
public void remove(int id) {
for (Iterator<Pair> iter = list.iterator(); iter.hasNext(); ) {
Pair pair = iter.next();
if (pair.first == id) {
iter.remove();
}
}
}
public Object lookup(int id) {
for (Pair entry : list) {
if (id == (Integer) entry.first) {
return entry.second;
}
}
return null;
}
}

View File

@ -0,0 +1,204 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<string name="app_name">ガジェットブリッジ</string>
<string name="title_activity_controlcenter">ガジェットブリッジ</string>
<string name="action_settings">設定</string>
<string name="action_debug">デバッグ</string>
<string name="action_quit">終了</string>
<string name="controlcenter_fetch_activity_data">同期</string>
<string name="controlcenter_start_sleepmonitor">睡眠観測(アルファ)</string>
<string name="controlcenter_find_device">デバイスをバイブさせる</string>
<string name="controlcenter_take_screenshot">スクリーンショットを撮る</string>
<string name="controlcenter_disconnect">切断</string>
<string name="title_activity_debug">デバッグ</string>
<!--Strings related to AppManager-->
<string name="title_activity_appmanager">アプリ管理画面</string>
<string name="appmananger_app_delete">削除</string>
<!--Strings related to AppBlacklist-->
<string name="title_activity_appblacklist">ステータス通知ブラックリスト</string>
<!--Strings related to FwAppInstaller-->
<string name="title_activity_fw_app_insaller">ファームウェア・アプリのインストール</string>
<string name="fw_upgrade_notice">お使いのMi Bandに、現在のファームウェアの代わりに%sをインストールしようとしています。</string>
<string name="miband_firmware_known">このファームウェアはテスト済で、ガジェットブリッジと互換性があることがわかっています。</string>
<string name="miband_firmware_unknown_warning">このファームウェアは未テストで、ガジェットブリッジと互換性がない可能性があります。\n\nお使いのMi Bandにフラッシュすることは奨励されていません!</string>
<string name="miband_firmware_suggest_whitelist">それでも続行して、その後正しく作業を続ける場合は、ガジェットブリッジ開発者にホワイトリスト ファームウェア バージョンを教えてください: %s</string>
<!--Strings related to Settings-->
<string name="title_activity_settings">設定</string>
<string name="pref_header_general">一般設定</string>
<string name="pref_title_general_autoconnectonbluetooth">Bluetoothがオンになったときにデバイスに接続</string>
<string name="pref_title_audo_player">お好みのオーディオプレイヤー</string>
<string name="pref_default">デフォルト</string>
<string name="pref_header_datetime">日付と時刻</string>
<string name="pref_title_datetime_syctimeonconnect">時間を合わせる</string>
<string name="pref_summary_datetime_syctimeonconnect">接続したとき、Androidで時間またはタイムゾーンを変更したときに、デバイスに時間を同期</string>
<string name="pref_header_notifications">通知</string>
<string name="pref_title_notifications_repetitions">繰り返し</string>
<string name="pref_title_notifications_call">電話通知</string>
<string name="pref_title_notifications_sms">SMS</string>
<string name="pref_title_notifications_k9mail">K9メール</string>
<string name="pref_title_notifications_pebblemsg">Pebbleメッセージ</string>
<string name="pref_summary_notifications_pebblemsg">インテント経由でPebbleに通知を送信するアプリケーションをサポートします。Conversationsに使用することができます。</string>
<string name="pref_title_notifications_generic">一般ステータス通知対応</string>
<string name="pref_title_whenscreenon">… スクリーンがオンのときにも</string>
<string name="always">いつも</string>
<string name="when_screen_off">スクリーンがオフのとき</string>
<string name="never">なし</string>
<string name="pref_blacklist">アップのブラックリスト</string>
<string name="pref_title_canned_replies">定型の返信</string>
<string name="pref_header_development">開発者用設定</string>
<string name="pref_title_development_miaddr">Mi Bandのアドレス</string>
<string name="pref_title_pebble_settings">Pebbleの設定</string>
<string name="pref_title_enable_pebblekit">第三者のアンドロイドアップにアクセス権利を与える</string>
<string name="pref_summary_enable_pebblekit">PebbleKitを使用してAndroidアプリ用の実験的なサポートを有効にします</string>
<string name="pref_title_pebble_forceprotocol">通知プロトコルを強制する</string>
<string name="pref_summary_pebble_forceprotocol">このオプションを指定すると、ファームウェアのバージョンに応じて強制的に最新の通知プロトコルを使用します。何をしているかわかっている場合のみ有効にしてください!</string>
<string name="pref_title_pebble_forceuntested">未テストの機能を有効にする</string>
<string name="pref_summary_pebble_forceuntested">テストされていない機能を有効にします。何をしているかわかっている場合のみ有効にしてください!</string>
<string name="pref_title_pebble_reconnect_attempts">再接続の試行</string>
<string name="not_connected">非接続</string>
<string name="connecting">接続中</string>
<string name="connected">接続</string>
<string name="unknown_state">不明な状態</string>
<string name="connectionstate_hw_fw">HW: %1$s FW: %2$s</string>
<string name="connectionstate_fw">FW: %1$s</string>
<string name="_unknown_">(不明)</string>
<string name="test">テスト</string>
<string name="test_notification">通知のテスト</string>
<string name="this_is_a_test_notification_from_gadgetbridge">これはガジェットブリッジからのテスト通知です</string>
<string name="bluetooth_is_not_supported_">Bluetoothはサポートされていません。</string>
<string name="bluetooth_is_disabled_">Bluetoothは無効です。</string>
<string name="tap_connected_device_for_app_mananger">アプリマネージャーの接続されたデバイスをタップ</string>
<string name="tap_a_device_to_connect">接続するデバイスをタップ</string>
<string name="cannot_connect_bt_address_invalid_">接続できません。 BTアドレスが無効?</string>
<string name="gadgetbridge_running">ガジェットブリッジは実行中</string>
<string name="installing_binary_d_d">バイナリーのインストール中 %1$d/%2$d</string>
<string name="installation_failed_">インストールに失敗しました!</string>
<string name="installation_successful">インストールに成功しました</string>
<string name="firmware_install_warning">ファームウェアをインストールしようとしています。ご自身の責任で行って下さい。\n\n\n このファームウェアは次のHWリビジョン用: %s</string>
<string name="app_install_info">次のアプリをインストールしようとしています:\n\n\n%1$s バージョン %2$s 作成 %3$s\n</string>
<string name="n_a">N/A</string>
<string name="initialized">初期化しました</string>
<string name="appversion_by_creator">%1$s 作成 %2$s</string>
<string name="title_activity_discovery">デバイス探索</string>
<string name="discovery_stop_scanning">スキャンを停止</string>
<string name="discovery_start_scanning">探索を開始</string>
<string name="action_discover">新しいデバイスに接続</string>
<string name="device_with_rssi">%1$s (%2$s)</string>
<string name="title_activity_android_pairing">デバイスのペアリング</string>
<string name="android_pairing_hint">デバイスをペアリングするには、AndroidのBluetoothペアリングのダイアログを使用します。</string>
<string name="title_activity_mi_band_pairing">お使いのMi Bandをペアリング</string>
<string name="miband_pairing">%sとペアリング…</string>
<string name="message_cannot_pair_no_mac">MACアドレスが渡されませんでした。ペアリングできません。</string>
<string name="preferences_category_device_specific_settings">デバイス固有の設定</string>
<string name="preferences_miband_settings">Mi Bandの設定</string>
<string name="male">男性</string>
<string name="female">女性</string>
<string name="other">その他</string>
<string name="left"></string>
<string name="right"></string>
<string name="miband_pairing_using_dummy_userdata">有効なユーザーデータはありません。今のところ、ダミーのユーザーデータを使用します。</string>
<string name="miband_pairing_tap_hint">お使いのMi Bandが振動と点滅したとき、それを連続して数回タップしてください。</string>
<string name="appinstaller_install">インストール</string>
<string name="discovery_connected_devices_hint">お使いのデバイスを検出可能にしてください。現在、接続されたデバイスは、おそらく検出されません。</string>
<string name="discovery_note">注:</string>
<string name="candidate_item_device_image">デバイスイメージ</string>
<string name="miband_prefs_about_you">あなたについて</string>
<string name="miband_prefs_alias">名前/別名</string>
<string name="miband_prefs_year_birth">誕生年</string>
<string name="miband_prefs_gender">性別</string>
<string name="miband_prefs_height_cm">身長cm</string>
<string name="miband_prefs_weight_kg">体重kg</string>
<string name="pref_header_vibration_count">バイブレーション回数</string>
<string name="title_activity_sleepmonitor">睡眠観測</string>
<string name="pref_write_logfiles">ログファイルを出力 (再起動が必要)</string>
<string name="initializing">初期化中</string>
<string name="busy_task_fetch_activity_data">活動データを取得中</string>
<string name="sleep_activity_date_range">%1$sから%2$sまで</string>
<string name="miband_prefs_wearside">左または右に身に着けますか?</string>
<string name="pref_screen_vibration_profile">バイブレーション プロファイル</string>
<string name="vibration_profile_staccato">スタッカート</string>
<string name="vibration_profile_short">短い</string>
<string name="vibration_profile_medium">標準</string>
<string name="vibration_profile_long">長い</string>
<string name="vibration_profile_waterdrop">水滴</string>
<string name="vibration_profile_ring">鳴り響く</string>
<string name="vibration_profile_alarm_clock">目覚まし時計</string>
<string name="miband_prefs_vibration">バイブレーション</string>
<string name="pref_screen_notification_profile_sms">SMS通知</string>
<string name="pref_header_vibration_settings">バイブレーションの設定</string>
<string name="pref_screen_notification_profile_generic">全般通知</string>
<string name="pref_screen_notification_profile_pebblemsg">Pebble通知</string>
<string name="pref_screen_notification_profile_k9mail">K9 Mail 通知</string>
<string name="pref_screen_notification_profile_incoming_call">着信通知</string>
<string name="control_center_find_lost_device">なくしたデバイスを探す</string>
<string name="control_center_cancel_to_stop_vibration">キャンセルで振動を停止します。</string>
<string name="title_activity_charts">あなたの活動</string>
<string name="title_activity_set_alarm">アラームを設定</string>
<string name="controlcenter_start_configure_alarms">アラームを設定</string>
<string name="title_activity_alarm_details">アラームの詳細</string>
<string name="alarm_sun_short"></string>
<string name="alarm_mon_short"></string>
<string name="alarm_tue_short"></string>
<string name="alarm_wed_short"></string>
<string name="alarm_thu_short"></string>
<string name="alarm_fri_short"></string>
<string name="alarm_sat_short"></string>
<string name="alarm_smart_wakeup">スマート ウェイクアップ</string>
<string name="user_feedback_miband_set_alarms_failed">アラームの設定時にエラーが発生しました。もう一度試してください!</string>
<string name="user_feedback_miband_set_alarms_ok">アラームをデバイスに送信しました!</string>
<string name="chart_no_data_synchronize">データはありません。デバイスを同期しますか?</string>
<string name="user_feedback_miband_activity_data_transfer">%1$s のデータを %2$s から転送することについて</string>
<string name="miband_prefs_fitness_goal">毎日の目標ステップ</string>
<string name="dbaccess_error_executing">\'%1$s\' の実行エラー</string>
<string name="controlcenter_start_activitymonitor">あなたの活動 (アルファ版)</string>
<string name="cannot_connect">接続できません: %1$s</string>
<string name="installer_activity_unable_to_find_handler">このファイルをインストールするハンドラーを見つけることができません。</string>
<string name="pbw_install_handler_unable_to_install">指定されたファイルをインストールできません: %1$s</string>
<string name="pbw_install_handler_hw_revision_mismatch">指定されたファームウェアをインストールできません: Pebbleのハードウェアリビジョンと一致しません。</string>
<string name="installer_activity_wait_while_determining_status">インストールのステータスが決定するまでお待ちください…</string>
<string name="notif_battery_low_title">ガジェット バッテリー残量低!</string>
<string name="notif_battery_low_percent">%1$s バッテリー残: %2$s%%</string>
<string name="notif_battery_low_bigtext_last_charge_time">最後の充電: %s \n</string>
<string name="notif_battery_low_bigtext_number_of_charges">充電回数: %s</string>
<string name="sleepchart_your_sleep">あなたの睡眠</string>
<string name="weekstepschart_steps_a_week">週あたり歩数</string>
<string name="activity_sleepchart_activity_and_sleep">あなたの活動と睡眠</string>
<string name="updating_firmware">ファームウェアの更新中…</string>
<string name="fwapp_install_device_not_ready">ファイルをインストールできません。デバイスの準備ができていません。</string>
<string name="miband_installhandler_miband_firmware">Mi Band ファームウェア %1$s</string>
<string name="miband_fwinstaller_compatible_version">互換性のバージョン</string>
<string name="miband_fwinstaller_untested_version">テストされていないバージョン!</string>
<string name="fwappinstaller_connection_state">デバイスへの接続: %1$s</string>
<string name="pbw_installhandler_pebble_firmware">Pebble ファームウェア %1$s</string>
<string name="pbwinstallhandler_correct_hw_revision">ハードウェアリビジョンを修正</string>
<string name="pbwinstallhandler_incorrect_hw_revision">ハードウェアリビジョンが一致しません!</string>
<string name="pbwinstallhandler_app_item">%1$s (%2$s)</string>
<string name="updatefirmwareoperation_updateproblem_do_not_reboot">ファームウェアの転送で問題があります。お使いのMi Bandを再起動しないでください!</string>
<string name="updatefirmwareoperation_metadata_updateproblem">ファームウェアのメタデータ転送で問題があります</string>
<string name="updatefirmwareoperation_update_complete">ファームウェアのインストールが完了しました</string>
<string name="updatefirmwareoperation_update_complete_rebooting">ファームウェアのインストールが完了しました。デバイスを再起動します…</string>
<string name="updatefirmwareoperation_write_failed">ファームウェアの書き込みに失敗しました</string>
<string name="chart_steps">歩数</string>
<string name="liveactivity_live_activity">生活活動</string>
<string name="weeksteps_today_steps_description">今日の歩数、目標: %1$s</string>
<string name="pref_summary_dont_ack_transfers">活動データは、バンドが応答しない場合は、クリアされません。 GBを他のアプリと一緒に使用する場合に便利です。</string>
<string name="pref_summary_keep_data_on_device">同期後もMi Bandに活動データを保持します。 GBを他のアプリと一緒に使用する場合に便利です。</string>
<string name="pref_title_dont_ack_transfer">活動データ転送に応答しない</string>
<string name="live_activity_steps_history">歩数履歴</string>
<string name="live_activity_current_steps_per_minute">現在の歩数/分</string>
<string name="live_activity_total_steps">合計歩数</string>
<string name="live_activity_steps_per_minute_history">毎分の歩数履歴</string>
<string name="live_activity_start_your_activity">あなたの活動を開始</string>
<string name="abstract_chart_fragment_kind_activity">活動</string>
<string name="abstract_chart_fragment_kind_light_sleep">浅い睡眠</string>
<string name="abstract_chart_fragment_kind_deep_sleep">深い睡眠</string>
<string name="abstract_chart_fragment_kind_not_worn">非装着</string>
<string name="device_not_connected">接続されていません。</string>
<string name="user_feedback_all_alarms_disabled">すべてのアラームを無効にしました</string>
<string name="pref_title_keep_data_on_device">活動データをデバイスに保持</string>
<string name="miband_fwinstaller_incompatible_version">非互換性のファームウェア</string>
<string name="fwinstaller_firmware_not_compatible_to_device">このファームウェアは、デバイスと互換性がありません</string>
<string name="miband_prefs_reserve_alarm_calendar">今後のイベントのために予約するアラーム</string>
<string name="waiting_for_reconnect">再接続の待機中</string>
<string name="appmananger_app_reinstall">再インストール</string>
</resources>