1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-23 18:36:50 +01:00

Various changes to Service, Activity and Notification handling

- Bluetooth connection is now established in BtSocketIOThread
- Service is now started as soon as the main activity is started
- changed "start service" button to "connect" button
- quit button in service notification now also quits the main activity
- Service notification now displays "Gadgetbride started",
  "connected to Pebble XXXXX" and "not connected" depending on connection state
This commit is contained in:
Andreas Shimokawa 2015-02-06 13:55:44 +01:00
parent ab233279e1
commit 243b9f0a88
4 changed files with 155 additions and 61 deletions

View File

@ -1,6 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge; package nodomain.freeyourgadget.gadgetbridge;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.app.Service; import android.app.Service;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
@ -8,6 +9,7 @@ import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket; import android.bluetooth.BluetoothSocket;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.database.Cursor; import android.database.Cursor;
@ -25,13 +27,15 @@ import java.io.OutputStream;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.Set; import java.util.Set;
import java.util.UUID;
public class BluetoothCommunicationService extends Service { public class BluetoothCommunicationService extends Service {
private static final String TAG = "BluetoothCommunicationService"; private static final String TAG = "BluetoothCommunicationService";
private static final int NOTIFICATION_ID = 1;
public static final String ACTION_START public static final String ACTION_START
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.start"; = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.start";
public static final String ACTION_CONNECT
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.connect";
public static final String ACTION_NOTIFICATION_GENERIC public static final String ACTION_NOTIFICATION_GENERIC
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.notification_generic"; = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.notification_generic";
public static final String ACTION_NOTIFICATION_SMS public static final String ACTION_NOTIFICATION_SMS
@ -44,10 +48,10 @@ public class BluetoothCommunicationService extends Service {
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.settime"; = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.settime";
private BluetoothAdapter mBtAdapter = null; private BluetoothAdapter mBtAdapter = null;
private String mBtDeviceAddress = null;
private BluetoothSocket mBtSocket = null; private BluetoothSocket mBtSocket = null;
private BtSocketIoThread mBtSocketIoThread = null; private BtSocketIoThread mBtSocketIoThread = null;
private static final UUID PEBBLE_UUID = UUID.fromString("00000000-deca-fade-deca-deafdecacafe");
private boolean mStarted = false;
private void setReceiversEnableState(boolean enable) { private void setReceiversEnableState(boolean enable) {
final Class[] receiverClasses = { final Class[] receiverClasses = {
@ -78,33 +82,57 @@ public class BluetoothCommunicationService extends Service {
super.onCreate(); super.onCreate();
} }
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);
Intent stopIntent = new Intent(this, StopServiceReceiver.class);
PendingIntent pendingIntentStop = PendingIntent.getBroadcast(this, 0, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT);
return new NotificationCompat.Builder(this)
.setContentTitle("Gadgetbridge")
.setTicker(text)
.setContentText(text)
.setSmallIcon(R.drawable.ic_launcher)
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "Quit", pendingIntentStop)
.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);
}
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
if (!intent.getAction().equals(ACTION_START) && mBtSocketIoThread == null) { String action = intent.getAction();
if (!mStarted && !action.equals(ACTION_START)) {
// using the service before issuing ACTION_START
return START_NOT_STICKY;
}
if (mStarted && action.equals(ACTION_START)) {
// using ACTION_START when the service has already been started
return START_STICKY; return START_STICKY;
} }
if (intent.getAction().equals(ACTION_START)) { if (!action.equals(ACTION_START) && !action.equals(ACTION_CONNECT) && mBtSocket == null) {
Intent notificationIntent = new Intent(this, ControlCenter.class); // trying to send notification without valid Blutooth socket
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK return START_STICKY;
| Intent.FLAG_ACTIVITY_CLEAR_TASK); }
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
Intent stopIntent = new Intent(this, StopServiceReceiver.class);
PendingIntent pendingIntentStop = PendingIntent.getBroadcast(this, 0, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle("Gadgetbridge")
.setTicker("Gadgetbridge Running")
.setContentText("Gadgetbrige Running")
.setSmallIcon(R.drawable.ic_launcher)
.addAction(android.R.drawable.ic_menu_close_clear_cancel, "Quit", pendingIntentStop)
.setContentIntent(pendingIntent)
.setOngoing(true).build();
if (intent.getAction().equals(ACTION_CONNECT)) {
//Check the system status //Check the system status
mBtAdapter = BluetoothAdapter.getDefaultAdapter(); mBtAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBtAdapter == null) { if (mBtAdapter == null) {
@ -112,30 +140,28 @@ public class BluetoothCommunicationService extends Service {
} else if (!mBtAdapter.isEnabled()) { } else if (!mBtAdapter.isEnabled()) {
Toast.makeText(this, "Bluetooth is disabled.", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "Bluetooth is disabled.", Toast.LENGTH_SHORT).show();
} else { } else {
String btDeviceAddress = null;
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices(); Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
for (BluetoothDevice device : pairedDevices) { for (BluetoothDevice device : pairedDevices) {
if (device.getName().indexOf("Pebble") == 0) { if (device.getName().indexOf("Pebble") == 0) {
// Matching device found // Matching device found
mBtDeviceAddress = device.getAddress(); btDeviceAddress = device.getAddress();
} }
} }
try { if (mBtSocket == null || !mBtSocket.isConnected()) {
if (mBtSocket == null || !mBtSocket.isConnected()) { // currently only one thread allowed
BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(mBtDeviceAddress); if (mBtSocketIoThread != null) {
ParcelUuid uuids[] = btDevice.getUuids(); mBtSocketIoThread.quit();
mBtSocket = btDevice.createRfcommSocketToServiceRecord(uuids[0].getUuid()); try {
mBtSocket.connect(); mBtSocketIoThread.join();
mBtSocketIoThread = new BtSocketIoThread(mBtSocket.getInputStream(), mBtSocket.getOutputStream()); } catch (InterruptedException e) {
mBtSocketIoThread.start(); e.printStackTrace();
}
setReceiversEnableState(true); // enable BroadcastReceivers
} }
mBtSocketIoThread = new BtSocketIoThread(btDeviceAddress);
} catch (IOException e) { mBtSocketIoThread.start();
e.printStackTrace();
} }
startForeground(1, notification); //FIXME: don't hardcode id
} }
} else if (intent.getAction().equals(ACTION_NOTIFICATION_GENERIC)) { } else if (intent.getAction().equals(ACTION_NOTIFICATION_GENERIC)) {
String title = intent.getStringExtra("notification_title"); String title = intent.getStringExtra("notification_title");
@ -163,7 +189,11 @@ public class BluetoothCommunicationService extends Service {
} else if (intent.getAction().equals(ACTION_SETTIME)) { } else if (intent.getAction().equals(ACTION_SETTIME)) {
byte[] msg = PebbleProtocol.encodeSetTime(-1); byte[] msg = PebbleProtocol.encodeSetTime(-1);
mBtSocketIoThread.write(msg); mBtSocketIoThread.write(msg);
} else if (intent.getAction().equals(ACTION_START)) {
startForeground(NOTIFICATION_ID, createNotification("Gadgetbridge running"));
mStarted = true;
} }
return START_STICKY; return START_STICKY;
} }
@ -181,13 +211,8 @@ public class BluetoothCommunicationService extends Service {
e.printStackTrace(); e.printStackTrace();
} }
} }
if (mBtSocket != null) { NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
try { nm.cancel(NOTIFICATION_ID); // need to do this because the updated notification wont be cancelled when service stops
mBtSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
@Override @Override
@ -223,16 +248,40 @@ public class BluetoothCommunicationService extends Service {
private class BtSocketIoThread extends Thread { private class BtSocketIoThread extends Thread {
private final InputStream mmInStream; private InputStream mmInStream = null;
private final OutputStream mmOutStream; private OutputStream mmOutStream = null;
private final String mmBtDeviceAddress;
private boolean mQuit = false; private boolean mQuit = false;
private boolean mmIsConnected = false;
public BtSocketIoThread(InputStream instream, OutputStream outstream) { public BtSocketIoThread(String btDeviceAddress) {
mmInStream = instream; mmBtDeviceAddress = btDeviceAddress;
mmOutStream = outstream; }
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;
}
updateNotification("connected to " + btDevice.getName());
return true;
} }
public void run() { public void run() {
mmIsConnected = connect(mmBtDeviceAddress);
setReceiversEnableState(mmIsConnected); // enable/disable BroadcastReceivers
mQuit = !mmIsConnected; // quit if not connected
byte[] buffer = new byte[8192]; byte[] buffer = new byte[8192];
int bytes; int bytes;
@ -286,18 +335,37 @@ public class BluetoothCommunicationService extends Service {
} }
} }
} }
mmIsConnected = false;
if (mBtSocket != null) {
try {
mBtSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
mBtSocket = null;
updateNotification("not connected");
} }
synchronized public void write(byte[] bytes) { synchronized public void write(byte[] bytes) {
try { if (mmIsConnected) {
mmOutStream.write(bytes); try {
mmOutStream.flush(); mmOutStream.write(bytes);
} catch (IOException e) { mmOutStream.flush();
} catch (IOException e) {
}
} }
} }
public void quit() { public void quit() {
mQuit = true; mQuit = true;
if (mBtSocket != null) {
try {
mBtSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
} }
} }

View File

@ -1,7 +1,10 @@
package nodomain.freeyourgadget.gadgetbridge; package nodomain.freeyourgadget.gadgetbridge;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
@ -13,11 +16,10 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import java.util.UUID;
public class ControlCenter extends ActionBarActivity { public class ControlCenter extends ActionBarActivity {
// SPP Serial Device UUID
private static final UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb"); public static final String ACTION_QUIT
= "nodomain.freeyourgadget.gadgetbride.controlcenter.action.quit";
Button sendButton; Button sendButton;
Button testNotificationButton; Button testNotificationButton;
@ -26,11 +28,21 @@ public class ControlCenter extends ActionBarActivity {
EditText editTitle; EditText editTitle;
EditText editContent; EditText editContent;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_QUIT)) {
finish();
}
}
};
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_controlcenter); setContentView(R.layout.activity_controlcenter);
registerReceiver(mReceiver, new IntentFilter(ACTION_QUIT));
editTitle = (EditText) findViewById(R.id.editTitle); editTitle = (EditText) findViewById(R.id.editTitle);
editContent = (EditText) findViewById(R.id.editContent); editContent = (EditText) findViewById(R.id.editContent);
@ -39,7 +51,7 @@ public class ControlCenter extends ActionBarActivity {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
Intent startIntent = new Intent(ControlCenter.this, BluetoothCommunicationService.class); Intent startIntent = new Intent(ControlCenter.this, BluetoothCommunicationService.class);
startIntent.setAction(BluetoothCommunicationService.ACTION_START); startIntent.setAction(BluetoothCommunicationService.ACTION_CONNECT);
startService(startIntent); startService(startIntent);
} }
}); });
@ -82,6 +94,10 @@ public class ControlCenter extends ActionBarActivity {
Intent enableIntent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"); Intent enableIntent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
startActivity(enableIntent); startActivity(enableIntent);
} }
Intent startIntent = new Intent(ControlCenter.this, BluetoothCommunicationService.class);
startIntent.setAction(BluetoothCommunicationService.ACTION_START);
startService(startIntent);
} }
private void testNotification() { private void testNotification() {
@ -118,4 +134,10 @@ public class ControlCenter extends ActionBarActivity {
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
} @Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
}

View File

@ -9,5 +9,9 @@ public class StopServiceReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
Intent stopIntent = new Intent(context, BluetoothCommunicationService.class); Intent stopIntent = new Intent(context, BluetoothCommunicationService.class);
context.stopService(stopIntent); context.stopService(stopIntent);
Intent quitIntent = new Intent();
quitIntent.setAction(ControlCenter.ACTION_QUIT);
context.sendBroadcast(quitIntent);
} }
} }

View File

@ -55,7 +55,7 @@
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="start service" android:text="connect"
android:id="@+id/startServiceButton" android:id="@+id/startServiceButton"
android:layout_above="@+id/setTimeButton" android:layout_above="@+id/setTimeButton"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"