package com.codegy.aerlink; import android.app.Notification; import android.app.NotificationManager; import android.app.Service; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothManager; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Binder; import android.os.IBinder; import android.util.Log; import com.codegy.aerlink.connection.*; import com.codegy.aerlink.connection.characteristic.CharacteristicIdentifier; import com.codegy.aerlink.connection.command.Command; import com.codegy.aerlink.utils.ServiceHandler; import com.codegy.aerlink.utils.ServiceObserver; import com.codegy.aerlink.utils.ServiceUtils; import java.util.ArrayList; import java.util.List; import java.util.Queue; public class MainService extends Service implements ServiceUtils, ConnectionManager.Callback, DiscoveryManager.Callback { private static final String LOG_TAG = MainService.class.getSimpleName(); private IBinder mBinder = new ServiceBinder(); private ConnectionState state = ConnectionState.Disconnected; private int mBondedDeviceFailedConnections = 0; private List<ServiceObserver> observers; private ConnectionHelper connectionHelper; private DiscoveryManager discoveryManager; private ConnectionManager connectionManager; private NotificationManager notificationManager; private ServiceHandlerManager serviceHandlerManager; @Override public void onCreate() { super.onCreate(); Log.i(LOG_TAG, "-=-=-=-=-=-=-=-=-= Service created =-=-=-=-=-=-=-=-=-"); start(); } @Override public void onDestroy() { Log.e(LOG_TAG, "xXxXxXxXxXxXxXxXxX Service destroyed XxXxXxXxXxXxXxXxXx"); stop(); getNotificationManager().cancelAll(); super.onDestroy(); } @Override public IBinder onBind(Intent intent) { Log.v(LOG_TAG, "onBind"); return mBinder; } private void start() { Log.v(LOG_TAG, "Starting..."); observers = new ArrayList<>(); BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE) || bluetoothManager == null) { setState(ConnectionState.NoBluetooth); return; } connectionHelper = new ConnectionHelper(this, this); discoveryManager = new DiscoveryManager(this, this, bluetoothManager); connectionManager = new ConnectionManager(this, this, bluetoothManager.getAdapter()); serviceHandlerManager = new ServiceHandlerManager(this, this); setState(ConnectionState.Disconnected); Log.v(LOG_TAG, "Started"); } private void stop() { Log.v(LOG_TAG, "Stopping..."); if (serviceHandlerManager != null) { serviceHandlerManager.close(); serviceHandlerManager = null; } if (discoveryManager != null) { discoveryManager.stopDiscovery(); discoveryManager = null; } if (connectionManager != null) { connectionManager.close(); connectionManager = null; } Log.v(LOG_TAG, "Stopped"); } public void restartConnection() { if (connectionManager == null) { return; } connectionManager.tryToReconnect(); } public void setState(ConnectionState state) { switch (state) { case NoBluetooth: Log.wtf(LOG_TAG, "State: Bluetooth not supported"); connectionManager = null; stop(); break; case Stopped: Log.i(LOG_TAG, "State: Stopped"); break; case Ready: mBondedDeviceFailedConnections = 0; Log.i(LOG_TAG, "State: Ready"); break; case Disconnected: Log.i(LOG_TAG, "State: Disconnected"); BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE); BluetoothDevice device = BluetoothUtils.getBondedDevice(bluetoothManager.getAdapter()); if (device == null || mBondedDeviceFailedConnections >= 3) { Log.i(LOG_TAG, "Starting discovery"); discoveryManager.startDiscovery(); } else { Log.i(LOG_TAG, "Connecting to previously bonded device"); mBondedDeviceFailedConnections += 1; connectionManager.connectToDevice(device); } break; case Connecting: Log.i(LOG_TAG, "State: Connecting"); break; } if (this.state == state) { return; } this.state = state; connectionHelper.showHelpForState(state); notifyStateChange(); } public ServiceHandler getServiceHandler(Class serviceHandlerClass) { return serviceHandlerManager.getServiceHandler(serviceHandlerClass); } public void addObserver(ServiceObserver observer) { if (!observers.contains(observer)) { observers.add(observer); } observer.onConnectionStateChanged(state); } public void removeObserver(ServiceObserver observer) { observers.remove(observer); } private void notifyStateChange() { for (ServiceObserver observer : observers) { observer.onConnectionStateChanged(state); } } private NotificationManager getNotificationManager() { if (notificationManager == null) { notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); } return notificationManager; } @Override public void addCommandToQueue(Command command) { connectionManager.addCommandToQueue(command); } @Override public void notify(String tag, int id, Notification notification) { getNotificationManager().notify(tag, id, notification); } @Override public void cancelNotification(String tag, int id) { getNotificationManager().cancel(tag, id); } @Override public void onDeviceDiscovery(BluetoothDevice device) { Log.v(LOG_TAG, "Device discovered"); if (connectionManager != null) { connectionManager.connectToDevice(device); } } @Override public void onConnectionStateChange(ConnectionState state) { setState(state); } @Override public void onReadyToSubscribe(BluetoothGatt bluetoothGatt) { Log.i(LOG_TAG, "Ready to Subscribe"); Queue<CharacteristicIdentifier> requests = serviceHandlerManager.subscribeToServices(bluetoothGatt); connectionManager.addSubscribeRequests(requests); } @Override public void onCharacteristicChanged(BluetoothGattCharacteristic characteristic) { serviceHandlerManager.handleCharacteristic(characteristic); } public class ServiceBinder extends Binder { public MainService getService() { return MainService.this; } } }