2015-01-12 00:35:15 +01:00
|
|
|
package nodomain.freeyourgadget.gadgetbridge;
|
|
|
|
|
|
|
|
import android.app.Notification;
|
2015-02-06 13:55:44 +01:00
|
|
|
import android.app.NotificationManager;
|
2015-01-12 00:35:15 +01:00
|
|
|
import android.app.PendingIntent;
|
|
|
|
import android.app.Service;
|
|
|
|
import android.bluetooth.BluetoothAdapter;
|
|
|
|
import android.bluetooth.BluetoothDevice;
|
|
|
|
import android.bluetooth.BluetoothSocket;
|
2015-02-02 21:16:42 +01:00
|
|
|
import android.content.ComponentName;
|
2015-01-23 11:32:58 +01:00
|
|
|
import android.content.ContentResolver;
|
2015-02-06 13:55:44 +01:00
|
|
|
import android.content.Context;
|
2015-01-12 00:35:15 +01:00
|
|
|
import android.content.Intent;
|
2015-03-21 18:18:07 +01:00
|
|
|
import android.content.SharedPreferences;
|
2015-02-02 21:16:42 +01:00
|
|
|
import android.content.pm.PackageManager;
|
2015-01-23 11:32:58 +01:00
|
|
|
import android.database.Cursor;
|
|
|
|
import android.net.Uri;
|
2015-01-12 00:35:15 +01:00
|
|
|
import android.os.IBinder;
|
|
|
|
import android.os.ParcelUuid;
|
2015-03-21 18:18:07 +01:00
|
|
|
import android.preference.PreferenceManager;
|
2015-01-23 11:32:58 +01:00
|
|
|
import android.provider.ContactsContract;
|
2015-01-12 00:35:15 +01:00
|
|
|
import android.support.v4.app.NotificationCompat;
|
2015-03-27 10:56:08 +01:00
|
|
|
import android.support.v4.content.LocalBroadcastManager;
|
2015-01-12 00:35:15 +01:00
|
|
|
import android.util.Log;
|
|
|
|
import android.widget.Toast;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
2015-01-20 23:51:55 +01:00
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
import java.nio.ByteOrder;
|
2015-01-12 00:35:15 +01:00
|
|
|
|
2015-03-26 12:06:26 +01:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommand;
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandAppInfo;
|
2015-03-26 18:11:47 +01:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandAppManagementResult;
|
2015-03-26 12:06:26 +01:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandCallControl;
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandMusicControl;
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandVersionInfo;
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.protocol.PebbleProtocol;
|
|
|
|
|
2015-01-12 00:35:15 +01:00
|
|
|
public class BluetoothCommunicationService extends Service {
|
2015-01-18 01:10:44 +01:00
|
|
|
public static final String ACTION_START
|
2015-01-12 00:35:15 +01:00
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.start";
|
2015-02-06 13:55:44 +01:00
|
|
|
public static final String ACTION_CONNECT
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.connect";
|
2015-01-24 12:21:15 +01:00
|
|
|
public static final String ACTION_NOTIFICATION_GENERIC
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.notification_generic";
|
|
|
|
public static final String ACTION_NOTIFICATION_SMS
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.notification_sms";
|
2015-01-26 18:52:19 +01:00
|
|
|
public static final String ACTION_NOTIFICATION_EMAIL
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.notification_email";
|
2015-02-07 12:58:18 +01:00
|
|
|
public static final String ACTION_CALLSTATE
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.callstate";
|
2015-01-18 01:10:44 +01:00
|
|
|
public static final String ACTION_SETTIME
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.settime";
|
2015-02-08 23:53:40 +01:00
|
|
|
public static final String ACTION_SETMUSICINFO
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.setmusicinfo";
|
2015-03-22 00:34:54 +01:00
|
|
|
public static final String ACTION_REQUEST_VERSIONINFO
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.request_versioninfo";
|
2015-03-25 22:23:45 +01:00
|
|
|
public static final String ACTION_REQUEST_APPINFO
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.request_appinfo";
|
2015-03-26 18:11:47 +01:00
|
|
|
public static final String ACTION_DELETEAPP
|
|
|
|
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.deleteapp";
|
2015-03-25 22:23:45 +01:00
|
|
|
|
2015-02-08 23:53:40 +01:00
|
|
|
private static final String TAG = "BluetoothCommunicationService";
|
|
|
|
private static final int NOTIFICATION_ID = 1;
|
2015-01-12 00:35:15 +01:00
|
|
|
private BluetoothAdapter mBtAdapter = null;
|
|
|
|
private BluetoothSocket mBtSocket = null;
|
|
|
|
private BtSocketIoThread mBtSocketIoThread = null;
|
2015-02-06 13:55:44 +01:00
|
|
|
|
|
|
|
private boolean mStarted = false;
|
2015-03-22 23:38:51 +01:00
|
|
|
|
|
|
|
private GBDevice gbdevice = null;
|
2015-01-12 00:35:15 +01:00
|
|
|
|
2015-02-02 21:16:42 +01:00
|
|
|
private void setReceiversEnableState(boolean enable) {
|
|
|
|
final Class[] receiverClasses = {
|
|
|
|
PhoneCallReceiver.class,
|
|
|
|
SMSReceiver.class,
|
|
|
|
K9Receiver.class,
|
2015-02-08 23:53:40 +01:00
|
|
|
MusicPlaybackReceiver.class,
|
2015-02-07 13:20:38 +01:00
|
|
|
//NotificationListener.class, // disabling this leads to loss of permission to read notifications
|
2015-02-02 21:16:42 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
int newState;
|
|
|
|
|
|
|
|
if (enable) {
|
|
|
|
newState = PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
|
|
|
|
} else {
|
|
|
|
newState = PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
PackageManager pm = getPackageManager();
|
|
|
|
|
|
|
|
for (Class receiverClass : receiverClasses) {
|
|
|
|
ComponentName compName = new ComponentName(getApplicationContext(), receiverClass);
|
|
|
|
|
|
|
|
pm.setComponentEnabledSetting(compName, newState, PackageManager.DONT_KILL_APP);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-12 00:35:15 +01:00
|
|
|
@Override
|
|
|
|
public void onCreate() {
|
|
|
|
super.onCreate();
|
|
|
|
}
|
|
|
|
|
2015-02-06 13:55:44 +01:00
|
|
|
|
|
|
|
private Notification createNotification(String text) {
|
|
|
|
Intent notificationIntent = new Intent(this, ControlCenter.class);
|
|
|
|
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
|
|
|
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
|
|
|
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
|
|
|
|
notificationIntent, 0);
|
|
|
|
|
|
|
|
return new NotificationCompat.Builder(this)
|
|
|
|
.setContentTitle("Gadgetbridge")
|
|
|
|
.setTicker(text)
|
|
|
|
.setContentText(text)
|
2015-02-24 12:36:38 +01:00
|
|
|
.setSmallIcon(R.drawable.ic_notification)
|
2015-02-06 13:55:44 +01:00
|
|
|
.setContentIntent(pendingIntent)
|
|
|
|
.setOngoing(true).build();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void updateNotification(String text) {
|
|
|
|
|
|
|
|
Notification notification = createNotification(text);
|
|
|
|
|
|
|
|
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
|
|
|
nm.notify(NOTIFICATION_ID, notification);
|
|
|
|
}
|
|
|
|
|
2015-03-26 12:06:26 +01:00
|
|
|
private void evaluateGBCommandBundle(GBDeviceCommand deviceCmd) {
|
|
|
|
switch (deviceCmd.commandClass) {
|
2015-02-12 16:00:45 +01:00
|
|
|
case MUSIC_CONTROL:
|
|
|
|
Log.i(TAG, "Got command for MUSIC_CONTROL");
|
2015-03-26 18:11:47 +01:00
|
|
|
GBDeviceCommandMusicControl musicCmd = (GBDeviceCommandMusicControl) deviceCmd;
|
2015-03-22 00:34:54 +01:00
|
|
|
Intent musicIntent = new Intent(GBMusicControlReceiver.ACTION_MUSICCONTROL);
|
2015-03-26 12:06:26 +01:00
|
|
|
musicIntent.putExtra("command", musicCmd.command.ordinal());
|
2015-03-27 12:13:19 +01:00
|
|
|
musicIntent.setPackage(this.getPackageName());
|
2015-03-22 00:34:54 +01:00
|
|
|
sendBroadcast(musicIntent);
|
2015-02-12 16:00:45 +01:00
|
|
|
break;
|
|
|
|
case CALL_CONTROL:
|
|
|
|
Log.i(TAG, "Got command for CALL_CONTROL");
|
2015-03-26 18:11:47 +01:00
|
|
|
GBDeviceCommandCallControl callCmd = (GBDeviceCommandCallControl) deviceCmd;
|
2015-03-22 00:34:54 +01:00
|
|
|
Intent callIntent = new Intent(GBCallControlReceiver.ACTION_CALLCONTROL);
|
2015-03-26 12:06:26 +01:00
|
|
|
callIntent.putExtra("command", callCmd.command.ordinal());
|
2015-03-27 12:13:19 +01:00
|
|
|
callIntent.setPackage(this.getPackageName());
|
2015-03-22 00:34:54 +01:00
|
|
|
sendBroadcast(callIntent);
|
2015-02-12 16:00:45 +01:00
|
|
|
break;
|
2015-03-22 00:34:54 +01:00
|
|
|
case VERSION_INFO:
|
2015-03-25 22:23:45 +01:00
|
|
|
Log.i(TAG, "Got command for VERSION_INFO");
|
2015-03-22 23:38:51 +01:00
|
|
|
if (gbdevice == null) {
|
|
|
|
return;
|
|
|
|
}
|
2015-03-26 18:11:47 +01:00
|
|
|
GBDeviceCommandVersionInfo infoCmd = (GBDeviceCommandVersionInfo) deviceCmd;
|
2015-03-26 12:06:26 +01:00
|
|
|
gbdevice.setFirmwareVersion(infoCmd.fwVersion);
|
2015-03-22 23:38:51 +01:00
|
|
|
sendDeviceUpdateIntent();
|
2015-03-25 22:23:45 +01:00
|
|
|
break;
|
|
|
|
case APP_INFO:
|
|
|
|
Log.i(TAG, "Got command for APP_INFO");
|
2015-03-26 18:11:47 +01:00
|
|
|
GBDeviceCommandAppInfo appInfoCmd = (GBDeviceCommandAppInfo) deviceCmd;
|
2015-03-25 22:23:45 +01:00
|
|
|
Intent appInfoIntent = new Intent(AppManagerActivity.ACTION_REFRESH_APPLIST);
|
2015-03-26 12:06:26 +01:00
|
|
|
int appCount = appInfoCmd.apps.length;
|
2015-03-25 22:23:45 +01:00
|
|
|
appInfoIntent.putExtra("app_count", appCount);
|
|
|
|
for (Integer i = 0; i < appCount; i++) {
|
2015-03-26 12:06:26 +01:00
|
|
|
appInfoIntent.putExtra("app_name" + i.toString(), appInfoCmd.apps[i].getName());
|
|
|
|
appInfoIntent.putExtra("app_creator" + i.toString(), appInfoCmd.apps[i].getCreator());
|
2015-03-26 18:11:47 +01:00
|
|
|
appInfoIntent.putExtra("app_id" + i.toString(), appInfoCmd.apps[i].getId());
|
|
|
|
appInfoIntent.putExtra("app_index" + i.toString(), appInfoCmd.apps[i].getIndex());
|
2015-03-25 22:23:45 +01:00
|
|
|
}
|
2015-03-27 10:56:08 +01:00
|
|
|
LocalBroadcastManager.getInstance(this).sendBroadcast(appInfoIntent);
|
2015-03-25 22:23:45 +01:00
|
|
|
break;
|
2015-03-26 18:11:47 +01:00
|
|
|
case APP_MANAGEMENT_RES:
|
|
|
|
GBDeviceCommandAppManagementResult appMgmtRes = (GBDeviceCommandAppManagementResult) deviceCmd;
|
|
|
|
switch (appMgmtRes.type) {
|
|
|
|
case DELETE:
|
|
|
|
switch (appMgmtRes.result) {
|
|
|
|
case FAILURE:
|
|
|
|
Log.i(TAG, "failure removing app"); // TODO: report to AppManager
|
|
|
|
break;
|
|
|
|
case SUCCESS:
|
|
|
|
// refresh app list
|
|
|
|
mBtSocketIoThread.write(PebbleProtocol.encodeAppInfoReq());
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2015-02-12 16:00:45 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2015-03-22 23:38:51 +01:00
|
|
|
}
|
2015-02-12 16:00:45 +01:00
|
|
|
|
2015-03-22 23:38:51 +01:00
|
|
|
private void sendDeviceUpdateIntent() {
|
|
|
|
Intent deviceUpdateIntent = new Intent(ControlCenter.ACTION_REFRESH_DEVICELIST);
|
|
|
|
deviceUpdateIntent.putExtra("device_address", gbdevice.getAddress());
|
|
|
|
deviceUpdateIntent.putExtra("device_state", gbdevice.getState().ordinal());
|
|
|
|
deviceUpdateIntent.putExtra("firmware_version", gbdevice.getFirmwareVersion());
|
2015-03-27 10:56:08 +01:00
|
|
|
|
|
|
|
LocalBroadcastManager.getInstance(this).sendBroadcast(deviceUpdateIntent);
|
2015-02-12 16:00:45 +01:00
|
|
|
}
|
|
|
|
|
2015-01-12 00:35:15 +01:00
|
|
|
@Override
|
|
|
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
2015-01-26 18:52:19 +01:00
|
|
|
|
2015-02-06 13:55:44 +01:00
|
|
|
String action = intent.getAction();
|
2015-03-17 21:41:58 +01:00
|
|
|
if (action == null) {
|
|
|
|
Log.i(TAG, "no action");
|
|
|
|
return START_NOT_STICKY;
|
|
|
|
}
|
2015-01-12 00:35:15 +01:00
|
|
|
|
2015-02-06 13:55:44 +01:00
|
|
|
if (!mStarted && !action.equals(ACTION_START)) {
|
|
|
|
// using the service before issuing ACTION_START
|
|
|
|
return START_NOT_STICKY;
|
|
|
|
}
|
2015-01-30 11:59:36 +01:00
|
|
|
|
2015-02-06 13:55:44 +01:00
|
|
|
if (mStarted && action.equals(ACTION_START)) {
|
|
|
|
// using ACTION_START when the service has already been started
|
|
|
|
return START_STICKY;
|
|
|
|
}
|
2015-01-12 00:35:15 +01:00
|
|
|
|
2015-02-06 13:55:44 +01:00
|
|
|
if (!action.equals(ACTION_START) && !action.equals(ACTION_CONNECT) && mBtSocket == null) {
|
|
|
|
// trying to send notification without valid Blutooth socket
|
|
|
|
return START_STICKY;
|
|
|
|
}
|
2015-01-12 00:35:15 +01:00
|
|
|
|
2015-03-22 12:46:28 +01:00
|
|
|
if (action.equals(ACTION_CONNECT)) {
|
2015-01-12 00:35:15 +01:00
|
|
|
//Check the system status
|
|
|
|
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
|
|
|
|
if (mBtAdapter == null) {
|
|
|
|
Toast.makeText(this, "Bluetooth is not supported.", Toast.LENGTH_SHORT).show();
|
|
|
|
} else if (!mBtAdapter.isEnabled()) {
|
|
|
|
Toast.makeText(this, "Bluetooth is disabled.", Toast.LENGTH_SHORT).show();
|
|
|
|
} else {
|
2015-03-22 23:38:51 +01:00
|
|
|
String btDeviceAddress = intent.getStringExtra("device_address");
|
2015-03-21 18:18:07 +01:00
|
|
|
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
2015-03-22 23:38:51 +01:00
|
|
|
sharedPrefs.edit().putString("last_device_address", btDeviceAddress).commit();
|
2015-03-21 18:18:07 +01:00
|
|
|
|
2015-03-22 23:38:51 +01:00
|
|
|
if (btDeviceAddress != null && (mBtSocket == null || !mBtSocket.isConnected())) {
|
2015-02-06 13:55:44 +01:00
|
|
|
// currently only one thread allowed
|
|
|
|
if (mBtSocketIoThread != null) {
|
|
|
|
mBtSocketIoThread.quit();
|
|
|
|
try {
|
|
|
|
mBtSocketIoThread.join();
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2015-03-22 23:38:51 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(btDeviceAddress);
|
|
|
|
if (btDevice != null) {
|
|
|
|
gbdevice = new GBDevice(btDeviceAddress, btDevice.getName());
|
|
|
|
gbdevice.setState(GBDevice.State.CONNECTING);
|
|
|
|
sendDeviceUpdateIntent();
|
|
|
|
|
|
|
|
mBtSocketIoThread = new BtSocketIoThread(btDeviceAddress);
|
|
|
|
mBtSocketIoThread.start();
|
2015-01-12 00:35:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-03-22 12:46:28 +01:00
|
|
|
} else if (action.equals(ACTION_NOTIFICATION_GENERIC)) {
|
2015-01-12 00:35:15 +01:00
|
|
|
String title = intent.getStringExtra("notification_title");
|
2015-01-24 12:21:15 +01:00
|
|
|
String body = intent.getStringExtra("notification_body");
|
2015-01-26 18:52:19 +01:00
|
|
|
byte[] msg = PebbleProtocol.encodeSMS(title, body);
|
|
|
|
mBtSocketIoThread.write(msg);
|
2015-03-22 12:46:28 +01:00
|
|
|
} else if (action.equals(ACTION_NOTIFICATION_SMS)) {
|
2015-01-24 12:21:15 +01:00
|
|
|
String sender = intent.getStringExtra("notification_sender");
|
|
|
|
String body = intent.getStringExtra("notification_body");
|
|
|
|
String senderName = getContactDisplayNameByNumber(sender);
|
2015-01-26 18:52:19 +01:00
|
|
|
byte[] msg = PebbleProtocol.encodeSMS(senderName, body);
|
|
|
|
mBtSocketIoThread.write(msg);
|
2015-03-22 12:46:28 +01:00
|
|
|
} else if (action.equals(ACTION_NOTIFICATION_EMAIL)) {
|
2015-01-26 18:52:19 +01:00
|
|
|
String sender = intent.getStringExtra("notification_sender");
|
|
|
|
String subject = intent.getStringExtra("notification_subject");
|
|
|
|
String body = intent.getStringExtra("notification_body");
|
|
|
|
byte[] msg = PebbleProtocol.encodeEmail(sender, subject, body);
|
|
|
|
mBtSocketIoThread.write(msg);
|
2015-03-22 12:46:28 +01:00
|
|
|
} else if (action.equals(ACTION_CALLSTATE)) {
|
2015-02-12 16:00:45 +01:00
|
|
|
GBCommand command = GBCommand.values()[intent.getIntExtra("call_command", 0)]; // UGLY
|
2015-02-08 23:53:40 +01:00
|
|
|
String phoneNumber = intent.getStringExtra("call_phonenumber");
|
2015-02-07 12:58:18 +01:00
|
|
|
String callerName = null;
|
|
|
|
if (phoneNumber != null) {
|
|
|
|
callerName = getContactDisplayNameByNumber(phoneNumber);
|
|
|
|
}
|
2015-02-12 16:00:45 +01:00
|
|
|
byte[] msg = PebbleProtocol.encodeSetCallState(phoneNumber, callerName, command);
|
2015-01-26 18:52:19 +01:00
|
|
|
mBtSocketIoThread.write(msg);
|
2015-03-22 12:46:28 +01:00
|
|
|
} else if (action.equals(ACTION_SETTIME)) {
|
2015-01-26 18:52:19 +01:00
|
|
|
byte[] msg = PebbleProtocol.encodeSetTime(-1);
|
|
|
|
mBtSocketIoThread.write(msg);
|
2015-03-22 12:46:28 +01:00
|
|
|
} else if (action.equals(ACTION_SETMUSICINFO)) {
|
2015-02-08 23:53:40 +01:00
|
|
|
String artist = intent.getStringExtra("music_artist");
|
|
|
|
String album = intent.getStringExtra("music_album");
|
|
|
|
String track = intent.getStringExtra("music_track");
|
|
|
|
byte[] msg = PebbleProtocol.encodeSetMusicInfo(artist, album, track);
|
|
|
|
mBtSocketIoThread.write(msg);
|
2015-03-22 12:46:28 +01:00
|
|
|
} else if (action.equals(ACTION_REQUEST_VERSIONINFO)) {
|
2015-03-22 23:38:51 +01:00
|
|
|
if (gbdevice != null && gbdevice.getFirmwareVersion() == null) {
|
|
|
|
byte[] msg = PebbleProtocol.encodeFirmwareVersionReq();
|
|
|
|
mBtSocketIoThread.write(msg);
|
|
|
|
} else {
|
|
|
|
sendDeviceUpdateIntent();
|
|
|
|
}
|
2015-03-25 22:23:45 +01:00
|
|
|
} else if (action.equals(ACTION_REQUEST_APPINFO)) {
|
|
|
|
mBtSocketIoThread.write(PebbleProtocol.encodeAppInfoReq());
|
2015-03-26 18:11:47 +01:00
|
|
|
} else if (action.equals(ACTION_DELETEAPP)) {
|
|
|
|
int id = intent.getIntExtra("app_id", -1);
|
|
|
|
int index = intent.getIntExtra("app_index", -1);
|
|
|
|
mBtSocketIoThread.write(PebbleProtocol.encodeAppDelete(id, index));
|
2015-03-22 12:46:28 +01:00
|
|
|
} else if (action.equals(ACTION_START)) {
|
2015-02-06 13:55:44 +01:00
|
|
|
startForeground(NOTIFICATION_ID, createNotification("Gadgetbridge running"));
|
|
|
|
mStarted = true;
|
2015-01-12 00:35:15 +01:00
|
|
|
}
|
2015-02-06 13:55:44 +01:00
|
|
|
|
2015-01-12 00:35:15 +01:00
|
|
|
return START_STICKY;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onDestroy() {
|
|
|
|
super.onDestroy();
|
2015-02-02 21:16:42 +01:00
|
|
|
|
|
|
|
setReceiversEnableState(false); // disable BroadcastReceivers
|
|
|
|
|
2015-01-30 11:59:36 +01:00
|
|
|
if (mBtSocketIoThread != null) {
|
|
|
|
try {
|
2015-01-31 11:49:46 +01:00
|
|
|
mBtSocketIoThread.quit();
|
2015-01-30 11:59:36 +01:00
|
|
|
mBtSocketIoThread.join();
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
2015-02-06 13:55:44 +01:00
|
|
|
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
|
|
|
nm.cancel(NOTIFICATION_ID); // need to do this because the updated notification wont be cancelled when service stops
|
2015-01-12 00:35:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public IBinder onBind(Intent intent) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2015-01-23 11:32:58 +01:00
|
|
|
|
|
|
|
private String getContactDisplayNameByNumber(String number) {
|
|
|
|
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
|
2015-01-31 11:49:46 +01:00
|
|
|
String name = number;
|
2015-01-23 11:32:58 +01:00
|
|
|
|
|
|
|
if (number == null || number.equals("")) {
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
ContentResolver contentResolver = getContentResolver();
|
|
|
|
Cursor contactLookup = contentResolver.query(uri, null, null, null, null);
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (contactLookup != null && contactLookup.getCount() > 0) {
|
|
|
|
contactLookup.moveToNext();
|
|
|
|
name = contactLookup.getString(contactLookup.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
|
|
|
|
}
|
|
|
|
} finally {
|
|
|
|
if (contactLookup != null) {
|
|
|
|
contactLookup.close();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-01-12 00:35:15 +01:00
|
|
|
private class BtSocketIoThread extends Thread {
|
2015-02-08 23:53:40 +01:00
|
|
|
private final String mmBtDeviceAddress;
|
2015-02-06 13:55:44 +01:00
|
|
|
private InputStream mmInStream = null;
|
|
|
|
private OutputStream mmOutStream = null;
|
2015-01-31 11:49:46 +01:00
|
|
|
private boolean mQuit = false;
|
2015-02-06 13:55:44 +01:00
|
|
|
private boolean mmIsConnected = false;
|
2015-03-18 12:29:10 +01:00
|
|
|
private int mmConnectionAttempts = 0;
|
2015-02-06 13:55:44 +01:00
|
|
|
|
|
|
|
public BtSocketIoThread(String btDeviceAddress) {
|
|
|
|
mmBtDeviceAddress = btDeviceAddress;
|
|
|
|
}
|
2015-01-12 00:35:15 +01:00
|
|
|
|
2015-02-06 13:55:44 +01:00
|
|
|
private boolean connect(String btDeviceAddress) {
|
|
|
|
BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(btDeviceAddress);
|
|
|
|
ParcelUuid uuids[] = btDevice.getUuids();
|
|
|
|
try {
|
|
|
|
mBtSocket = btDevice.createRfcommSocketToServiceRecord(uuids[0].getUuid());
|
|
|
|
mBtSocket.connect();
|
|
|
|
mmInStream = mBtSocket.getInputStream();
|
|
|
|
mmOutStream = mBtSocket.getOutputStream();
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
mmInStream = null;
|
|
|
|
mmOutStream = null;
|
|
|
|
mBtSocket = null;
|
|
|
|
return false;
|
|
|
|
}
|
2015-03-22 23:38:51 +01:00
|
|
|
gbdevice.setState(GBDevice.State.CONNECTED);
|
|
|
|
sendDeviceUpdateIntent();
|
2015-02-06 13:55:44 +01:00
|
|
|
updateNotification("connected to " + btDevice.getName());
|
|
|
|
return true;
|
2015-01-12 00:35:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public void run() {
|
2015-02-06 13:55:44 +01:00
|
|
|
mmIsConnected = connect(mmBtDeviceAddress);
|
|
|
|
setReceiversEnableState(mmIsConnected); // enable/disable BroadcastReceivers
|
|
|
|
mQuit = !mmIsConnected; // quit if not connected
|
|
|
|
|
2015-01-20 23:51:55 +01:00
|
|
|
byte[] buffer = new byte[8192];
|
|
|
|
int bytes;
|
2015-01-12 00:35:15 +01:00
|
|
|
|
2015-01-31 11:49:46 +01:00
|
|
|
while (!mQuit) {
|
2015-01-12 00:35:15 +01:00
|
|
|
try {
|
2015-01-20 23:51:55 +01:00
|
|
|
bytes = mmInStream.read(buffer, 0, 4);
|
|
|
|
if (bytes < 4)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ByteBuffer buf = ByteBuffer.wrap(buffer);
|
|
|
|
buf.order(ByteOrder.BIG_ENDIAN);
|
|
|
|
short length = buf.getShort();
|
|
|
|
short endpoint = buf.getShort();
|
|
|
|
if (length < 0 || length > 8192) {
|
|
|
|
Log.i(TAG, "invalid length " + length);
|
|
|
|
while (mmInStream.available() > 0) {
|
|
|
|
mmInStream.read(buffer); // read all
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bytes = mmInStream.read(buffer, 4, length);
|
|
|
|
if (bytes < length) {
|
|
|
|
try {
|
|
|
|
Thread.sleep(100);
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
Log.i(TAG, "Read " + bytes + ", expected " + length + " reading remaining " + (length - bytes));
|
|
|
|
int bytes_rest = mmInStream.read(buffer, 4 + bytes, length - bytes);
|
|
|
|
bytes += bytes_rest;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (length == 1 && endpoint == PebbleProtocol.ENDPOINT_PHONEVERSION) {
|
|
|
|
Log.i(TAG, "Pebble asked for Phone/App Version - repLYING!");
|
|
|
|
write(PebbleProtocol.encodePhoneVersion(PebbleProtocol.PHONEVERSION_REMOTE_OS_ANDROID));
|
2015-03-22 00:34:54 +01:00
|
|
|
write(PebbleProtocol.encodeFirmwareVersionReq());
|
2015-01-22 22:49:50 +01:00
|
|
|
} else if (endpoint != PebbleProtocol.ENDPOINT_DATALOG) {
|
2015-03-26 12:06:26 +01:00
|
|
|
GBDeviceCommand deviceCmd = PebbleProtocol.decodeResponse(buffer);
|
|
|
|
if (deviceCmd == null) {
|
2015-02-12 16:00:45 +01:00
|
|
|
Log.i(TAG, "unhandled message to endpoint " + endpoint + " (" + bytes + " bytes)");
|
|
|
|
} else {
|
2015-03-26 12:06:26 +01:00
|
|
|
evaluateGBCommandBundle(deviceCmd);
|
2015-02-12 16:00:45 +01:00
|
|
|
}
|
2015-01-20 23:51:55 +01:00
|
|
|
}
|
|
|
|
try {
|
|
|
|
Thread.sleep(100);
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
2015-01-12 00:35:15 +01:00
|
|
|
} catch (IOException e) {
|
2015-02-01 00:34:12 +01:00
|
|
|
if (e.getMessage().contains("socket closed")) { //FIXME: this does not feel right
|
2015-03-22 23:38:51 +01:00
|
|
|
gbdevice.setState(GBDevice.State.CONNECTING);
|
|
|
|
sendDeviceUpdateIntent();
|
2015-03-18 12:29:10 +01:00
|
|
|
updateNotification("connection lost, trying to reconnect");
|
|
|
|
|
|
|
|
while (mmConnectionAttempts++ < 10) {
|
|
|
|
Log.i(TAG, "Trying to reconnect (attempt " + mmConnectionAttempts + ")");
|
|
|
|
mmIsConnected = connect(mmBtDeviceAddress);
|
|
|
|
if (mmIsConnected)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
mmConnectionAttempts = 0;
|
|
|
|
if (!mmIsConnected) {
|
|
|
|
mBtSocket = null;
|
|
|
|
setReceiversEnableState(false);
|
|
|
|
Log.i(TAG, "Bluetooth socket closed, will quit IO Thread");
|
|
|
|
mQuit = true;
|
|
|
|
}
|
2015-02-01 00:34:12 +01:00
|
|
|
}
|
2015-01-12 00:35:15 +01:00
|
|
|
}
|
|
|
|
}
|
2015-02-06 13:55:44 +01:00
|
|
|
mmIsConnected = false;
|
|
|
|
if (mBtSocket != null) {
|
|
|
|
try {
|
|
|
|
mBtSocket.close();
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mBtSocket = null;
|
|
|
|
updateNotification("not connected");
|
2015-03-22 23:38:51 +01:00
|
|
|
gbdevice.setState(GBDevice.State.NOT_CONNECTED);
|
|
|
|
sendDeviceUpdateIntent();
|
2015-01-12 00:35:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
synchronized public void write(byte[] bytes) {
|
2015-02-06 13:55:44 +01:00
|
|
|
if (mmIsConnected) {
|
|
|
|
try {
|
|
|
|
mmOutStream.write(bytes);
|
|
|
|
mmOutStream.flush();
|
|
|
|
} catch (IOException e) {
|
|
|
|
}
|
2015-01-12 00:35:15 +01:00
|
|
|
}
|
|
|
|
}
|
2015-01-31 11:49:46 +01:00
|
|
|
|
|
|
|
public void quit() {
|
|
|
|
mQuit = true;
|
2015-02-06 13:55:44 +01:00
|
|
|
if (mBtSocket != null) {
|
|
|
|
try {
|
|
|
|
mBtSocket.close();
|
|
|
|
} catch (IOException e) {
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
2015-01-31 11:49:46 +01:00
|
|
|
}
|
2015-01-12 00:35:15 +01:00
|
|
|
}
|
2015-01-30 11:59:36 +01:00
|
|
|
}
|