mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-08-26 17:21:31 +02:00
Merge branch 'master' of https://github.com/Freeyourgadget/Gadgetbridge into feature-weather
This commit is contained in:
commit
4bb78722b5
@ -29,7 +29,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceService;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.IDSenderLookup;
|
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||||
|
|
||||||
//import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver;
|
//import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver;
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ public class GBApplication extends Application {
|
|||||||
private static final Lock dbLock = new ReentrantLock();
|
private static final Lock dbLock = new ReentrantLock();
|
||||||
private static DeviceService deviceService;
|
private static DeviceService deviceService;
|
||||||
private static SharedPreferences sharedPrefs;
|
private static SharedPreferences sharedPrefs;
|
||||||
private static IDSenderLookup mIDSenderLookup = new IDSenderLookup();
|
private static LimitedQueue mIDSenderLookup = new LimitedQueue(16);
|
||||||
|
|
||||||
public static final String ACTION_QUIT
|
public static final String ACTION_QUIT
|
||||||
= "nodomain.freeyourgadget.gadgetbridge.gbapplication.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() {
|
private void quit() {
|
||||||
//unregisterSystemBTReceiver();
|
|
||||||
GB.removeAllNotifications(this);
|
GB.removeAllNotifications(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,25 +100,11 @@ 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);
|
||||||
|
|
||||||
//registerSystemBTReceiver();
|
|
||||||
// for testing DB stuff
|
// for testing DB stuff
|
||||||
// SQLiteDatabase db = mActivityDatabaseHandler.getWritableDatabase();
|
// SQLiteDatabase db = mActivityDatabaseHandler.getWritableDatabase();
|
||||||
// db.close();
|
// 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() {
|
private void setupExceptionHandler() {
|
||||||
LoggingExceptionHandler handler = new LoggingExceptionHandler(Thread.getDefaultUncaughtExceptionHandler());
|
LoggingExceptionHandler handler = new LoggingExceptionHandler(Thread.getDefaultUncaughtExceptionHandler());
|
||||||
Thread.setDefaultUncaughtExceptionHandler(handler);
|
Thread.setDefaultUncaughtExceptionHandler(handler);
|
||||||
@ -259,7 +242,7 @@ public class GBApplication extends Application {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IDSenderLookup getIDSenderLookup() {
|
public static LimitedQueue getIDSenderLookup() {
|
||||||
return mIDSenderLookup;
|
return mIDSenderLookup;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import android.database.sqlite.SQLiteOpenHelper;
|
|||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.v4.app.NavUtils;
|
import android.support.v4.app.NavUtils;
|
||||||
import android.support.v4.app.NotificationCompat;
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.support.v4.app.RemoteInput;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
@ -38,6 +39,10 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
|||||||
public class DebugActivity extends Activity {
|
public class DebugActivity extends Activity {
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(DebugActivity.class);
|
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 sendSMSButton;
|
||||||
private Button sendEmailButton;
|
private Button sendEmailButton;
|
||||||
private Button incomingCallButton;
|
private Button incomingCallButton;
|
||||||
@ -56,8 +61,16 @@ public class DebugActivity extends Activity {
|
|||||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (intent.getAction().equals(GBApplication.ACTION_QUIT)) {
|
switch (intent.getAction()) {
|
||||||
|
case GBApplication.ACTION_QUIT:
|
||||||
finish();
|
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);
|
setContentView(R.layout.activity_debug);
|
||||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
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);
|
editContent = (EditText) findViewById(R.id.editContent);
|
||||||
sendSMSButton = (Button) findViewById(R.id.sendSMSButton);
|
sendSMSButton = (Button) findViewById(R.id.sendSMSButton);
|
||||||
@ -216,27 +232,42 @@ public class DebugActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void importDB() {
|
private void importDB() {
|
||||||
|
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;
|
DBHandler dbHandler = null;
|
||||||
try {
|
try {
|
||||||
dbHandler = GBApplication.acquireDB();
|
dbHandler = GBApplication.acquireDB();
|
||||||
DBHelper helper = new DBHelper(this);
|
DBHelper helper = new DBHelper(DebugActivity.this);
|
||||||
File dir = FileUtils.getExternalFilesDir();
|
File dir = FileUtils.getExternalFilesDir();
|
||||||
SQLiteOpenHelper sqLiteOpenHelper = dbHandler.getHelper();
|
SQLiteOpenHelper sqLiteOpenHelper = dbHandler.getHelper();
|
||||||
File sourceFile = new File(dir, sqLiteOpenHelper.getDatabaseName());
|
File sourceFile = new File(dir, sqLiteOpenHelper.getDatabaseName());
|
||||||
helper.importDB(sqLiteOpenHelper, sourceFile);
|
helper.importDB(sqLiteOpenHelper, sourceFile);
|
||||||
helper.validateDB(sqLiteOpenHelper);
|
helper.validateDB(sqLiteOpenHelper);
|
||||||
GB.toast(this, "Import successful.", Toast.LENGTH_LONG, GB.INFO);
|
GB.toast(DebugActivity.this, "Import successful.", Toast.LENGTH_LONG, GB.INFO);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
GB.toast(this, "Error importing DB: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
|
GB.toast(DebugActivity.this, "Error importing DB: " + ex.getMessage(), Toast.LENGTH_LONG, GB.ERROR, ex);
|
||||||
} finally {
|
} finally {
|
||||||
if (dbHandler != null) {
|
if (dbHandler != null) {
|
||||||
dbHandler.release();
|
dbHandler.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
private void deleteActivityDatabase() {
|
private void deleteActivityDatabase() {
|
||||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
.setTitle("Delete Activity Data?")
|
.setTitle("Delete Activity Data?")
|
||||||
.setMessage("Really delete the entire activity database? All your activity data will be lost.")
|
.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);
|
notificationIntent, 0);
|
||||||
|
|
||||||
NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||||
NotificationCompat.Builder ncomp = new NotificationCompat.Builder(this);
|
|
||||||
ncomp.setContentTitle(getString(R.string.test_notification));
|
RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_REPLY)
|
||||||
ncomp.setContentText(getString(R.string.this_is_a_test_notification_from_gadgetbridge));
|
.build();
|
||||||
ncomp.setTicker(getString(R.string.this_is_a_test_notification_from_gadgetbridge));
|
|
||||||
ncomp.setSmallIcon(R.drawable.ic_notification);
|
Intent replyIntent = new Intent(ACTION_REPLY);
|
||||||
ncomp.setAutoCancel(true);
|
|
||||||
ncomp.setContentIntent(pendingIntent);
|
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());
|
nManager.notify((int) System.currentTimeMillis(), ncomp.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,9 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean supports(GBDeviceCandidate candidate) {
|
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
|
@Override
|
||||||
@ -74,7 +76,7 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasValidUserInfo() {
|
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 {
|
try {
|
||||||
UserInfo userInfo = getConfiguredUserInfo(dummyMacAddress);
|
UserInfo userInfo = getConfiguredUserInfo(dummyMacAddress);
|
||||||
return true;
|
return true;
|
||||||
|
@ -1,15 +1,18 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.devices.miband;
|
package nodomain.freeyourgadget.gadgetbridge.devices.miband;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
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;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
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 int REQ_CODE_USER_SETTINGS = 52;
|
||||||
private static final String STATE_MIBAND_ADDRESS = "mibandMacAddress";
|
private static final String STATE_MIBAND_ADDRESS = "mibandMacAddress";
|
||||||
|
private static final long DELAY_AFTER_BONDING = 1000; // 1s
|
||||||
private TextView message;
|
private TextView message;
|
||||||
private boolean isPairing;
|
private boolean isPairing;
|
||||||
private String macAddress;
|
private String macAddress;
|
||||||
|
private String bondingMacAddress;
|
||||||
|
|
||||||
private final BroadcastReceiver mPairingReceiver = new BroadcastReceiver() {
|
private final BroadcastReceiver mPairingReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
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
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -99,7 +128,13 @@ public class MiBandPairingActivity extends Activity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
|
try {
|
||||||
|
// just to be sure, remove the receivers -- might actually be already unregistered
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mPairingReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(mPairingReceiver);
|
||||||
|
unregisterReceiver(mBondingReceiver);
|
||||||
|
} catch (IllegalArgumentException ex) {
|
||||||
|
// already unregistered, ignore
|
||||||
|
}
|
||||||
if (isPairing) {
|
if (isPairing) {
|
||||||
stopPairing();
|
stopPairing();
|
||||||
}
|
}
|
||||||
@ -109,15 +144,24 @@ public class MiBandPairingActivity extends Activity {
|
|||||||
private void startPairing() {
|
private void startPairing() {
|
||||||
isPairing = true;
|
isPairing = true;
|
||||||
message.setText(getString(R.string.miband_pairing, macAddress));
|
message.setText(getString(R.string.miband_pairing, macAddress));
|
||||||
|
|
||||||
IntentFilter filter = new IntentFilter(GBDevice.ACTION_DEVICE_CHANGED);
|
IntentFilter filter = new IntentFilter(GBDevice.ACTION_DEVICE_CHANGED);
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mPairingReceiver, filter);
|
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) {
|
private void pairingFinished(boolean pairedSuccessfully) {
|
||||||
isPairing = false;
|
isPairing = false;
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mPairingReceiver);
|
LocalBroadcastManager.getInstance(this).unregisterReceiver(mPairingReceiver);
|
||||||
|
unregisterReceiver(mBondingReceiver);
|
||||||
|
|
||||||
if (pairedSuccessfully) {
|
if (pairedSuccessfully) {
|
||||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
@ -133,4 +177,27 @@ public class MiBandPairingActivity extends Activity {
|
|||||||
// TODO
|
// TODO
|
||||||
isPairing = false;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,8 @@ import static nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDevi
|
|||||||
public class MiBandService {
|
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"));
|
public static final UUID UUID_SERVICE_MIBAND_SERVICE = UUID.fromString(String.format(BASE_UUID, "FEE0"));
|
||||||
|
|
||||||
|
@ -16,15 +16,20 @@ import android.os.PowerManager;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.service.notification.NotificationListenerService;
|
import android.service.notification.NotificationListenerService;
|
||||||
import android.service.notification.StatusBarNotification;
|
import android.service.notification.StatusBarNotification;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.support.v4.app.RemoteInput;
|
||||||
import android.support.v4.content.LocalBroadcastManager;
|
import android.support.v4.content.LocalBroadcastManager;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
|
import nodomain.freeyourgadget.gadgetbridge.service.DeviceCommunicationService;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||||
|
|
||||||
public class NotificationListener extends NotificationListenerService {
|
public class NotificationListener extends NotificationListenerService {
|
||||||
|
|
||||||
@ -38,6 +43,10 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.open";
|
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.action.open";
|
||||||
public static final String ACTION_MUTE
|
public static final String ACTION_MUTE
|
||||||
= "nodomain.freeyourgadget.gadgetbridge.notificationlistener.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() {
|
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
@ -90,6 +99,28 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
case ACTION_DISMISS_ALL:
|
case ACTION_DISMISS_ALL:
|
||||||
NotificationListener.this.cancelAllNotifications();
|
NotificationListener.this.cancelAllNotifications();
|
||||||
break;
|
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);
|
||||||
filterLocal.addAction(ACTION_DISMISS_ALL);
|
filterLocal.addAction(ACTION_DISMISS_ALL);
|
||||||
filterLocal.addAction(ACTION_MUTE);
|
filterLocal.addAction(ACTION_MUTE);
|
||||||
|
filterLocal.addAction(ACTION_REPLY);
|
||||||
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
|
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,6 +254,18 @@ public class NotificationListener extends NotificationListenerService {
|
|||||||
|
|
||||||
dissectNotificationTo(notification, notificationSpec);
|
dissectNotificationTo(notification, notificationSpec);
|
||||||
notificationSpec.id = (int) sbn.getPostTime(); //FIMXE: a truly unique id would be better
|
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);
|
GBApplication.deviceService().onNotification(notificationSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,6 +89,7 @@ public class GBDeviceService implements DeviceService {
|
|||||||
@Override
|
@Override
|
||||||
public void onNotification(NotificationSpec notificationSpec) {
|
public void onNotification(NotificationSpec notificationSpec) {
|
||||||
Intent intent = createIntent().setAction(ACTION_NOTIFICATION)
|
Intent intent = createIntent().setAction(ACTION_NOTIFICATION)
|
||||||
|
.putExtra(EXTRA_NOTIFICATION_FLAGS, notificationSpec.flags)
|
||||||
.putExtra(EXTRA_NOTIFICATION_PHONENUMBER, notificationSpec.phoneNumber)
|
.putExtra(EXTRA_NOTIFICATION_PHONENUMBER, notificationSpec.phoneNumber)
|
||||||
.putExtra(EXTRA_NOTIFICATION_SENDER, notificationSpec.sender)
|
.putExtra(EXTRA_NOTIFICATION_SENDER, notificationSpec.sender)
|
||||||
.putExtra(EXTRA_NOTIFICATION_SUBJECT, notificationSpec.subject)
|
.putExtra(EXTRA_NOTIFICATION_SUBJECT, notificationSpec.subject)
|
||||||
|
@ -35,6 +35,7 @@ public interface DeviceService extends EventHandler {
|
|||||||
|
|
||||||
String EXTRA_DEVICE_ADDRESS = "device_address";
|
String EXTRA_DEVICE_ADDRESS = "device_address";
|
||||||
String EXTRA_NOTIFICATION_BODY = "notification_body";
|
String EXTRA_NOTIFICATION_BODY = "notification_body";
|
||||||
|
String EXTRA_NOTIFICATION_FLAGS = "notification_flags";
|
||||||
String EXTRA_NOTIFICATION_ID = "notification_id";
|
String EXTRA_NOTIFICATION_ID = "notification_id";
|
||||||
String EXTRA_NOTIFICATION_PHONENUMBER = "notification_phonenumber";
|
String EXTRA_NOTIFICATION_PHONENUMBER = "notification_phonenumber";
|
||||||
String EXTRA_NOTIFICATION_SENDER = "notification_sender";
|
String EXTRA_NOTIFICATION_SENDER = "notification_sender";
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package nodomain.freeyourgadget.gadgetbridge.model;
|
package nodomain.freeyourgadget.gadgetbridge.model;
|
||||||
|
|
||||||
public class NotificationSpec {
|
public class NotificationSpec {
|
||||||
|
public static final int FLAG_WEARABLE_REPLY = 0x00000001;
|
||||||
|
|
||||||
|
public int flags;
|
||||||
public int id;
|
public int id;
|
||||||
public String sender;
|
public String sender;
|
||||||
public String phoneNumber;
|
public String phoneNumber;
|
||||||
|
@ -229,16 +229,22 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
|
|||||||
action = NotificationListener.ACTION_MUTE;
|
action = NotificationListener.ACTION_MUTE;
|
||||||
break;
|
break;
|
||||||
case REPLY:
|
case REPLY:
|
||||||
String phoneNumber = GBApplication.getIDSenderLookup().lookup(deviceEvent.handle);
|
String phoneNumber = (String) GBApplication.getIDSenderLookup().lookup(deviceEvent.handle);
|
||||||
if (phoneNumber != null) {
|
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);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
if (action != null) {
|
if (action != null) {
|
||||||
Intent notificationListenerIntent = new Intent(action);
|
Intent notificationListenerIntent = new Intent(action);
|
||||||
notificationListenerIntent.putExtra("handle", deviceEvent.handle);
|
notificationListenerIntent.putExtra("handle", deviceEvent.handle);
|
||||||
|
if (deviceEvent.reply != null) {
|
||||||
|
notificationListenerIntent.putExtra("reply", deviceEvent.reply);
|
||||||
|
}
|
||||||
LocalBroadcastManager.getInstance(context).sendBroadcast(notificationListenerIntent);
|
LocalBroadcastManager.getInstance(context).sendBroadcast(notificationListenerIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,6 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand;
|
import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
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_CALLSTATE;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT;
|
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_ARTIST;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_MUSIC_TRACK;
|
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_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_ID;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_PHONENUMBER;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_PHONENUMBER;
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_SENDER;
|
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_SENDER;
|
||||||
@ -219,13 +219,16 @@ public class DeviceCommunicationService extends Service {
|
|||||||
notificationSpec.body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY);
|
notificationSpec.body = intent.getStringExtra(EXTRA_NOTIFICATION_BODY);
|
||||||
notificationSpec.type = (NotificationType) intent.getSerializableExtra(EXTRA_NOTIFICATION_TYPE);
|
notificationSpec.type = (NotificationType) intent.getSerializableExtra(EXTRA_NOTIFICATION_TYPE);
|
||||||
notificationSpec.id = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
|
notificationSpec.id = intent.getIntExtra(EXTRA_NOTIFICATION_ID, -1);
|
||||||
|
notificationSpec.flags = intent.getIntExtra(EXTRA_NOTIFICATION_FLAGS, 0);
|
||||||
notificationSpec.sourceName = intent.getStringExtra(EXTRA_NOTIFICATION_SOURCENAME);
|
notificationSpec.sourceName = intent.getStringExtra(EXTRA_NOTIFICATION_SOURCENAME);
|
||||||
if (notificationSpec.type == NotificationType.SMS && notificationSpec.phoneNumber != null) {
|
if (notificationSpec.type == NotificationType.SMS && notificationSpec.phoneNumber != null) {
|
||||||
notificationSpec.sender = getContactDisplayNameByNumber(notificationSpec.phoneNumber);
|
notificationSpec.sender = getContactDisplayNameByNumber(notificationSpec.phoneNumber);
|
||||||
|
|
||||||
notificationSpec.id = mRandom.nextInt(); // FIXME: add this in external SMS Receiver?
|
notificationSpec.id = mRandom.nextInt(); // FIXME: add this in external SMS Receiver?
|
||||||
GBApplication.getIDSenderLookup().add(notificationSpec.id, notificationSpec.phoneNumber);
|
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
|
// NOTE: maybe not where it belongs
|
||||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
if (sharedPrefs.getBoolean("pebble_force_untested", false)) {
|
if (sharedPrefs.getBoolean("pebble_force_untested", false)) {
|
||||||
|
@ -9,6 +9,7 @@ import java.io.IOException;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
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
|
* 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 {
|
public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport> implements GattCallback, BTLEOperation {
|
||||||
private final T mSupport;
|
private final T mSupport;
|
||||||
|
protected OperationStatus operationStatus = OperationStatus.INITIAL;
|
||||||
|
|
||||||
protected AbstractBTLEOperation(T support) {
|
protected AbstractBTLEOperation(T support) {
|
||||||
mSupport = support;
|
mSupport = support;
|
||||||
@ -38,7 +40,9 @@ public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport>
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final void perform() throws IOException {
|
public final void perform() throws IOException {
|
||||||
|
operationStatus = OperationStatus.STARTED;
|
||||||
prePerform();
|
prePerform();
|
||||||
|
operationStatus = OperationStatus.RUNNING;
|
||||||
doPerform();
|
doPerform();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,6 +105,10 @@ public abstract class AbstractBTLEOperation<T extends AbstractBTLEDeviceSupport>
|
|||||||
getDevice().sendDeviceUpdateIntent(getContext());
|
getDevice().sendDeviceUpdateIntent(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isOperationRunning() {
|
||||||
|
return operationStatus == OperationStatus.RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
public T getSupport() {
|
public T getSupport() {
|
||||||
return mSupport;
|
return mSupport;
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ public abstract class AbstractMiBandOperation extends AbstractBTLEOperation<MiBa
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void operationFinished() {
|
protected void operationFinished() {
|
||||||
|
operationStatus = OperationStatus.FINISHED;
|
||||||
if (getDevice() != null && getDevice().isConnected()) {
|
if (getDevice() != null && getDevice().isConnected()) {
|
||||||
try {
|
try {
|
||||||
TransactionBuilder builder = performInitialized("reenabling disabled notifications");
|
TransactionBuilder builder = performInitialized("reenabling disabled notifications");
|
||||||
|
@ -174,6 +174,12 @@ public class FetchActivityOperation extends AbstractMiBandOperation {
|
|||||||
* @see #bufferActivityData(byte[])
|
* @see #bufferActivityData(byte[])
|
||||||
*/
|
*/
|
||||||
private void handleActivityNotif(byte[] value) {
|
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) {
|
if (value.length == activityMetadataLength) {
|
||||||
handleActivityMetadata(value);
|
handleActivityMetadata(value);
|
||||||
} else {
|
} else {
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge.service.devices.miband.operations;
|
||||||
|
|
||||||
|
public enum OperationStatus {
|
||||||
|
INITIAL,
|
||||||
|
STARTED,
|
||||||
|
RUNNING,
|
||||||
|
FINISHED
|
||||||
|
}
|
@ -1590,14 +1590,14 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
byte[] reply = new byte[length];
|
byte[] reply = new byte[length];
|
||||||
buf.get(reply);
|
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
|
// 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);
|
String phoneNumber = (String) GBApplication.getIDSenderLookup().lookup(id);
|
||||||
if (phoneNumber != null) {
|
//if (phoneNumber != null) {
|
||||||
devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.REPLY;
|
devEvtNotificationControl.event = GBDeviceEventNotificationControl.Event.REPLY;
|
||||||
devEvtNotificationControl.reply = new String(reply);
|
devEvtNotificationControl.reply = new String(reply);
|
||||||
caption = "SENT";
|
caption = "SENT";
|
||||||
icon_id = PebbleIconID.RESULT_SENT;
|
icon_id = PebbleIconID.RESULT_SENT;
|
||||||
failed = false;
|
failed = false;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (failed) {
|
if (failed) {
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
204
app/src/main/res/values-ja/strings.xml
Normal file
204
app/src/main/res/values-ja/strings.xml
Normal 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>
|
Loading…
Reference in New Issue
Block a user