diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java index 3dde0bba..63c1facf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java @@ -1,10 +1,5 @@ package nodomain.freeyourgadget.gadgetbridge; -import nodomain.freeyourgadget.gadgetbridge.GBDevice.State; -import nodomain.freeyourgadget.gadgetbridge.pebble.PebbleIoThread; -import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceProtocol; -import nodomain.freeyourgadget.gadgetbridge.protocol.MibandProtocol; -import nodomain.freeyourgadget.gadgetbridge.protocol.PebbleProtocol; import android.app.NotificationManager; import android.app.Service; import android.bluetooth.BluetoothAdapter; @@ -21,6 +16,12 @@ import android.provider.ContactsContract; import android.util.Log; import android.widget.Toast; +import nodomain.freeyourgadget.gadgetbridge.GBDevice.State; +import nodomain.freeyourgadget.gadgetbridge.pebble.PebbleIoThread; +import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceProtocol; +import nodomain.freeyourgadget.gadgetbridge.protocol.MibandProtocol; +import nodomain.freeyourgadget.gadgetbridge.protocol.PebbleProtocol; + public class BluetoothCommunicationService extends Service { public static final String ACTION_START = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.start"; @@ -197,10 +198,10 @@ public class BluetoothCommunicationService extends Service { } private boolean isConnected() { - return mGBDevice != null && mGBDevice.getState() == State.CONNECTED; - } + return mGBDevice != null && mGBDevice.getState() == State.CONNECTED; + } - @Override + @Override public void onDestroy() { super.onDestroy(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDevice.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDevice.java index 039f6412..f691b8c0 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDevice.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDevice.java @@ -73,7 +73,7 @@ public class GBDevice { LocalBroadcastManager.getInstance(context).sendBroadcast(deviceUpdateIntent); } - + public enum State { NOT_CONNECTED, CONNECTING, diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDeviceIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDeviceIoThread.java index 1256c3ad..d47b866b 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDeviceIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDeviceIoThread.java @@ -4,21 +4,21 @@ import android.content.Context; public abstract class GBDeviceIoThread extends Thread { protected final GBDevice gbDevice; - private final Context context; + private final Context context; public GBDeviceIoThread(GBDevice gbDevice, Context context) { - this.gbDevice = gbDevice; + this.gbDevice = gbDevice; this.context = context; } public Context getContext() { - return context; - } - + return context; + } + public GBDevice getDevice() { - return gbDevice; - } - + return gbDevice; + } + protected boolean connect(String btDeviceAddress) { return false; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleIoThread.java index cd3caace..77dece7d 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleIoThread.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/pebble/PebbleIoThread.java @@ -1,5 +1,17 @@ package nodomain.freeyourgadget.gadgetbridge.pebble; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothSocket; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.net.Uri; +import android.os.ParcelUuid; +import android.preference.PreferenceManager; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -21,379 +33,369 @@ import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandMusicControl import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandVersionInfo; import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceProtocol; import nodomain.freeyourgadget.gadgetbridge.protocol.PebbleProtocol; -import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothSocket; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; -import android.os.ParcelUuid; -import android.preference.PreferenceManager; -import android.support.v4.content.LocalBroadcastManager; -import android.util.Log; public class PebbleIoThread extends GBDeviceIoThread { - private static final String TAG = PebbleIoThread.class.getSimpleName(); + private static final String TAG = PebbleIoThread.class.getSimpleName(); - private enum PebbleAppInstallState { - UNKNOWN, - APP_WAIT_SLOT, - APP_START_INSTALL, - APP_WAIT_TOKEN, - APP_UPLOAD_CHUNK, - APP_UPLOAD_COMMIT, - APP_WAIT_COMMMIT, - APP_UPLOAD_COMPLETE, - APP_REFRESH, - } + private enum PebbleAppInstallState { + UNKNOWN, + APP_WAIT_SLOT, + APP_START_INSTALL, + APP_WAIT_TOKEN, + APP_UPLOAD_CHUNK, + APP_UPLOAD_COMMIT, + APP_WAIT_COMMMIT, + APP_UPLOAD_COMPLETE, + APP_REFRESH, + } - private final PebbleProtocol mmPebbleProtocol; - private InputStream mmInStream = null; - private OutputStream mmOutStream = null; - private boolean mmQuit = false; - private boolean mmIsConnected = false; - private boolean mmIsInstalling = false; - private int mmConnectionAttempts = 0; + private final PebbleProtocol mmPebbleProtocol; - /* app installation */ - private Uri mmInstallURI = null; - private PBWReader mmPBWReader = null; - private int mmAppInstallToken = -1; - private ZipInputStream mmZis = null; - private STM32CRC mmSTM32CRC = new STM32CRC(); - private PebbleAppInstallState mmInstallState = PebbleAppInstallState.UNKNOWN; - private String[] mmFilesToInstall = null; - private int mmCurrentFileIndex = -1; - private int mmInstallSlot = -1; - private BluetoothAdapter mBtAdapter = null; - private BluetoothSocket mBtSocket = null; + private BluetoothAdapter mBtAdapter = null; + private BluetoothSocket mBtSocket = null; + private InputStream mmInStream = null; + private OutputStream mmOutStream = null; + private boolean mmQuit = false; + private boolean mmIsConnected = false; + private boolean mmIsInstalling = false; + private int mmConnectionAttempts = 0; - public PebbleIoThread(GBDevice gbDevice, GBDeviceProtocol gbDeviceProtocol, BluetoothAdapter btAdapter, Context context) { - super(gbDevice, context); - mmPebbleProtocol = (PebbleProtocol) gbDeviceProtocol; - mBtAdapter = btAdapter; - } + /* app installation */ + private Uri mmInstallURI = null; + private PBWReader mmPBWReader = null; + private int mmAppInstallToken = -1; + private ZipInputStream mmZis = null; + private STM32CRC mmSTM32CRC = new STM32CRC(); + private PebbleAppInstallState mmInstallState = PebbleAppInstallState.UNKNOWN; + private String[] mmFilesToInstall = null; + private int mmCurrentFileIndex = -1; + private int mmInstallSlot = -1; - protected 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(); - gbDevice.setState(GBDevice.State.NOT_CONNECTED); - mmInStream = null; - mmOutStream = null; - mBtSocket = null; - return false; - } - gbDevice.setState(GBDevice.State.CONNECTED); - gbDevice.sendDeviceUpdateIntent(getContext()); - GB.updateNotification("connected to " + btDevice.getName(), getContext()); + public PebbleIoThread(GBDevice gbDevice, GBDeviceProtocol gbDeviceProtocol, BluetoothAdapter btAdapter, Context context) { + super(gbDevice, context); + mmPebbleProtocol = (PebbleProtocol) gbDeviceProtocol; + mBtAdapter = btAdapter; + } - return true; - } + protected 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(); + gbDevice.setState(GBDevice.State.NOT_CONNECTED); + mmInStream = null; + mmOutStream = null; + mBtSocket = null; + return false; + } + gbDevice.setState(GBDevice.State.CONNECTED); + gbDevice.sendDeviceUpdateIntent(getContext()); + GB.updateNotification("connected to " + btDevice.getName(), getContext()); - public void run() { - mmIsConnected = connect(gbDevice.getAddress()); - GB.setReceiversEnableState(mmIsConnected, getContext()); // enable/disable BroadcastReceivers - mmQuit = !mmIsConnected; // quit if not connected + return true; + } - byte[] buffer = new byte[8192]; - int bytes; + public void run() { + mmIsConnected = connect(gbDevice.getAddress()); + GB.setReceiversEnableState(mmIsConnected, getContext()); // enable/disable BroadcastReceivers + mmQuit = !mmIsConnected; // quit if not connected - while (!mmQuit) { - try { - if (mmIsInstalling) { - switch (mmInstallState) { - case APP_WAIT_SLOT: - if (mmInstallSlot != -1) { - GB.updateNotification("starting installation", getContext()); - mmInstallState = PebbleAppInstallState.APP_START_INSTALL; - continue; - } - break; - case APP_START_INSTALL: - Log.i(TAG, "start installing app binary"); - mmSTM32CRC.reset(); - if (mmPBWReader == null) { - mmPBWReader = new PBWReader(mmInstallURI, getContext()); - mmFilesToInstall = mmPBWReader.getFilesToInstall(); - mmCurrentFileIndex = 0; - } - String fileName = mmFilesToInstall[mmCurrentFileIndex]; - mmZis = mmPBWReader.getInputStreamFile(fileName); - int binarySize = mmPBWReader.getFileSize(fileName); - // FIXME: do not assume type from filename, parse json correctly in PBWReader - byte type = -1; - if (fileName.equals("pebble-app.bin")) { - type = PebbleProtocol.PUTBYTES_TYPE_BINARY; - } else if (fileName.equals("pebble-worker.bin")) { - type = PebbleProtocol.PUTBYTES_TYPE_WORKER; - } else if (fileName.equals("app_resources.pbpack")) { - type = PebbleProtocol.PUTBYTES_TYPE_RESOURCES; - } else { - finishInstall(true); - break; - } + byte[] buffer = new byte[8192]; + int bytes; - writeInstallApp(mmPebbleProtocol.encodeUploadStart(type, (byte) mmInstallSlot, binarySize)); - mmInstallState = PebbleAppInstallState.APP_WAIT_TOKEN; - break; - case APP_WAIT_TOKEN: - if (mmAppInstallToken != -1) { - Log.i(TAG, "got token " + mmAppInstallToken); - mmInstallState = PebbleAppInstallState.APP_UPLOAD_CHUNK; - continue; - } - break; - case APP_UPLOAD_CHUNK: - bytes = mmZis.read(buffer); + while (!mmQuit) { + try { + if (mmIsInstalling) { + switch (mmInstallState) { + case APP_WAIT_SLOT: + if (mmInstallSlot != -1) { + GB.updateNotification("starting installation", getContext()); + mmInstallState = PebbleAppInstallState.APP_START_INSTALL; + continue; + } + break; + case APP_START_INSTALL: + Log.i(TAG, "start installing app binary"); + mmSTM32CRC.reset(); + if (mmPBWReader == null) { + mmPBWReader = new PBWReader(mmInstallURI, getContext()); + mmFilesToInstall = mmPBWReader.getFilesToInstall(); + mmCurrentFileIndex = 0; + } + String fileName = mmFilesToInstall[mmCurrentFileIndex]; + mmZis = mmPBWReader.getInputStreamFile(fileName); + int binarySize = mmPBWReader.getFileSize(fileName); + // FIXME: do not assume type from filename, parse json correctly in PBWReader + byte type = -1; + if (fileName.equals("pebble-app.bin")) { + type = PebbleProtocol.PUTBYTES_TYPE_BINARY; + } else if (fileName.equals("pebble-worker.bin")) { + type = PebbleProtocol.PUTBYTES_TYPE_WORKER; + } else if (fileName.equals("app_resources.pbpack")) { + type = PebbleProtocol.PUTBYTES_TYPE_RESOURCES; + } else { + finishInstall(true); + break; + } - if (bytes != -1) { - mmSTM32CRC.addData(buffer, bytes); - writeInstallApp(mmPebbleProtocol.encodeUploadChunk(mmAppInstallToken, buffer, bytes)); - mmAppInstallToken = -1; - mmInstallState = PebbleAppInstallState.APP_WAIT_TOKEN; - } else { - mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMMIT; - continue; - } - break; - case APP_UPLOAD_COMMIT: - writeInstallApp(mmPebbleProtocol.encodeUploadCommit(mmAppInstallToken, mmSTM32CRC.getResult())); - mmAppInstallToken = -1; - mmInstallState = PebbleAppInstallState.APP_WAIT_COMMMIT; - break; - case APP_WAIT_COMMMIT: - if (mmAppInstallToken != -1) { - Log.i(TAG, "got token " + mmAppInstallToken); - mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMPLETE; - continue; - } - break; - case APP_UPLOAD_COMPLETE: - writeInstallApp(mmPebbleProtocol.encodeUploadComplete(mmAppInstallToken)); - if (++mmCurrentFileIndex < mmFilesToInstall.length) { - mmInstallState = PebbleAppInstallState.APP_START_INSTALL; - } else { - mmInstallState = PebbleAppInstallState.APP_REFRESH; - } - break; - case APP_REFRESH: - writeInstallApp(mmPebbleProtocol.encodeAppRefresh(mmInstallSlot)); - break; - default: - break; - } - } - bytes = mmInStream.read(buffer, 0, 4); - if (bytes < 4) - continue; + writeInstallApp(mmPebbleProtocol.encodeUploadStart(type, (byte) mmInstallSlot, binarySize)); + mmInstallState = PebbleAppInstallState.APP_WAIT_TOKEN; + break; + case APP_WAIT_TOKEN: + if (mmAppInstallToken != -1) { + Log.i(TAG, "got token " + mmAppInstallToken); + mmInstallState = PebbleAppInstallState.APP_UPLOAD_CHUNK; + continue; + } + break; + case APP_UPLOAD_CHUNK: + bytes = mmZis.read(buffer); - 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; - } + if (bytes != -1) { + mmSTM32CRC.addData(buffer, bytes); + writeInstallApp(mmPebbleProtocol.encodeUploadChunk(mmAppInstallToken, buffer, bytes)); + mmAppInstallToken = -1; + mmInstallState = PebbleAppInstallState.APP_WAIT_TOKEN; + } else { + mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMMIT; + continue; + } + break; + case APP_UPLOAD_COMMIT: + writeInstallApp(mmPebbleProtocol.encodeUploadCommit(mmAppInstallToken, mmSTM32CRC.getResult())); + mmAppInstallToken = -1; + mmInstallState = PebbleAppInstallState.APP_WAIT_COMMMIT; + break; + case APP_WAIT_COMMMIT: + if (mmAppInstallToken != -1) { + Log.i(TAG, "got token " + mmAppInstallToken); + mmInstallState = PebbleAppInstallState.APP_UPLOAD_COMPLETE; + continue; + } + break; + case APP_UPLOAD_COMPLETE: + writeInstallApp(mmPebbleProtocol.encodeUploadComplete(mmAppInstallToken)); + if (++mmCurrentFileIndex < mmFilesToInstall.length) { + mmInstallState = PebbleAppInstallState.APP_START_INSTALL; + } else { + mmInstallState = PebbleAppInstallState.APP_REFRESH; + } + break; + case APP_REFRESH: + writeInstallApp(mmPebbleProtocol.encodeAppRefresh(mmInstallSlot)); + break; + default: + break; + } + } + bytes = mmInStream.read(buffer, 0, 4); + if (bytes < 4) + 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; - } + 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; + } - if (length == 1 && endpoint == PebbleProtocol.ENDPOINT_PHONEVERSION) { - Log.i(TAG, "Pebble asked for Phone/App Version - repLYING!"); - write(mmPebbleProtocol.encodePhoneVersion(PebbleProtocol.PHONEVERSION_REMOTE_OS_ANDROID)); - write(mmPebbleProtocol.encodeFirmwareVersionReq()); + 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; + } - // this does not really belong here, but since the pebble only asks for our version once it should do the job - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); - if (sharedPrefs.getBoolean("datetime_synconconnect", true)) { - Log.i(TAG, "syncing time"); - write(mmPebbleProtocol.encodeSetTime(-1)); - } - } else if (endpoint != PebbleProtocol.ENDPOINT_DATALOG) { - GBDeviceCommand deviceCmd = mmPebbleProtocol.decodeResponse(buffer); - if (deviceCmd == null) { - Log.i(TAG, "unhandled message to endpoint " + endpoint + " (" + bytes + " bytes)"); - } else { - evaluateGBCommandBundle(deviceCmd); - } - } - try { - Thread.sleep(100); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } catch (IOException e) { - if (e.getMessage().contains("socket closed")) { //FIXME: this does not feel right - Log.i(TAG, e.getMessage()); - gbDevice.setState(GBDevice.State.CONNECTING); - gbDevice.sendDeviceUpdateIntent(getContext()); - GB.updateNotification("connection lost, trying to reconnect", getContext()); + if (length == 1 && endpoint == PebbleProtocol.ENDPOINT_PHONEVERSION) { + Log.i(TAG, "Pebble asked for Phone/App Version - repLYING!"); + write(mmPebbleProtocol.encodePhoneVersion(PebbleProtocol.PHONEVERSION_REMOTE_OS_ANDROID)); + write(mmPebbleProtocol.encodeFirmwareVersionReq()); - while (mmConnectionAttempts++ < 10) { - Log.i(TAG, "Trying to reconnect (attempt " + mmConnectionAttempts + ")"); - mmIsConnected = connect(gbDevice.getAddress()); - if (mmIsConnected) - break; - } - mmConnectionAttempts = 0; - if (!mmIsConnected) { - mBtSocket = null; - GB.setReceiversEnableState(false, getContext()); - Log.i(TAG, "Bluetooth socket closed, will quit IO Thread"); - mmQuit = true; - } - } - } - } - mmIsConnected = false; - if (mBtSocket != null) { - try { - mBtSocket.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - mBtSocket = null; - GB.updateNotification("not connected", getContext()); - gbDevice.setState(GBDevice.State.NOT_CONNECTED); - gbDevice.sendDeviceUpdateIntent(getContext()); - } + // this does not really belong here, but since the pebble only asks for our version once it should do the job + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); + if (sharedPrefs.getBoolean("datetime_synconconnect", true)) { + Log.i(TAG, "syncing time"); + write(mmPebbleProtocol.encodeSetTime(-1)); + } + } else if (endpoint != PebbleProtocol.ENDPOINT_DATALOG) { + GBDeviceCommand deviceCmd = mmPebbleProtocol.decodeResponse(buffer); + if (deviceCmd == null) { + Log.i(TAG, "unhandled message to endpoint " + endpoint + " (" + bytes + " bytes)"); + } else { + evaluateGBCommandBundle(deviceCmd); + } + } + try { + Thread.sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } catch (IOException e) { + if (e.getMessage().contains("socket closed")) { //FIXME: this does not feel right + Log.i(TAG, e.getMessage()); + gbDevice.setState(GBDevice.State.CONNECTING); + gbDevice.sendDeviceUpdateIntent(getContext()); + GB.updateNotification("connection lost, trying to reconnect", getContext()); - synchronized public void write(byte[] bytes) { - // block writes if app installation in in progress - if (mmIsConnected && !mmIsInstalling) { - try { - mmOutStream.write(bytes); - mmOutStream.flush(); - } catch (IOException e) { - } - } - } + while (mmConnectionAttempts++ < 10) { + Log.i(TAG, "Trying to reconnect (attempt " + mmConnectionAttempts + ")"); + mmIsConnected = connect(gbDevice.getAddress()); + if (mmIsConnected) + break; + } + mmConnectionAttempts = 0; + if (!mmIsConnected) { + mBtSocket = null; + GB.setReceiversEnableState(false, getContext()); + Log.i(TAG, "Bluetooth socket closed, will quit IO Thread"); + mmQuit = true; + } + } + } + } + mmIsConnected = false; + if (mBtSocket != null) { + try { + mBtSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + mBtSocket = null; + GB.updateNotification("not connected", getContext()); + gbDevice.setState(GBDevice.State.NOT_CONNECTED); + gbDevice.sendDeviceUpdateIntent(getContext()); + } - private void evaluateGBCommandBundle(GBDeviceCommand deviceCmd) { - Context context = getContext(); + synchronized public void write(byte[] bytes) { + // block writes if app installation in in progress + if (mmIsConnected && !mmIsInstalling) { + try { + mmOutStream.write(bytes); + mmOutStream.flush(); + } catch (IOException e) { + } + } + } - switch (deviceCmd.commandClass) { - case MUSIC_CONTROL: - Log.i(TAG, "Got command for MUSIC_CONTROL"); - GBDeviceCommandMusicControl musicCmd = (GBDeviceCommandMusicControl) deviceCmd; - Intent musicIntent = new Intent(GBMusicControlReceiver.ACTION_MUSICCONTROL); - musicIntent.putExtra("command", musicCmd.command.ordinal()); - musicIntent.setPackage(context.getPackageName()); - context.sendBroadcast(musicIntent); - break; - case CALL_CONTROL: - Log.i(TAG, "Got command for CALL_CONTROL"); - GBDeviceCommandCallControl callCmd = (GBDeviceCommandCallControl) deviceCmd; - Intent callIntent = new Intent(GBCallControlReceiver.ACTION_CALLCONTROL); - callIntent.putExtra("command", callCmd.command.ordinal()); - callIntent.setPackage(context.getPackageName()); - context.sendBroadcast(callIntent); - break; - case VERSION_INFO: - Log.i(TAG, "Got command for VERSION_INFO"); - if (gbDevice == null) { - return; - } - GBDeviceCommandVersionInfo infoCmd = (GBDeviceCommandVersionInfo) deviceCmd; - gbDevice.setFirmwareVersion(infoCmd.fwVersion); - gbDevice.sendDeviceUpdateIntent(context); - break; - case APP_INFO: - Log.i(TAG, "Got command for APP_INFO"); - GBDeviceCommandAppInfo appInfoCmd = (GBDeviceCommandAppInfo) deviceCmd; - setInstallSlot(appInfoCmd.freeSlot); + private void evaluateGBCommandBundle(GBDeviceCommand deviceCmd) { + Context context = getContext(); - Intent appInfoIntent = new Intent(AppManagerActivity.ACTION_REFRESH_APPLIST); - int appCount = appInfoCmd.apps.length; - appInfoIntent.putExtra("app_count", appCount); - for (Integer i = 0; i < appCount; i++) { - appInfoIntent.putExtra("app_name" + i.toString(), appInfoCmd.apps[i].getName()); - appInfoIntent.putExtra("app_creator" + i.toString(), appInfoCmd.apps[i].getCreator()); - appInfoIntent.putExtra("app_id" + i.toString(), appInfoCmd.apps[i].getId()); - appInfoIntent.putExtra("app_index" + i.toString(), appInfoCmd.apps[i].getIndex()); - appInfoIntent.putExtra("app_type" + i.toString(), appInfoCmd.apps[i].getType().ordinal()); - } - LocalBroadcastManager.getInstance(context).sendBroadcast(appInfoIntent); - break; - case APP_MANAGEMENT_RES: - GBDeviceCommandAppManagementResult appMgmtRes = (GBDeviceCommandAppManagementResult) deviceCmd; - switch (appMgmtRes.type) { - case DELETE: - // right now on the Pebble we also receive this on a failed/successful installation ;/ - switch (appMgmtRes.result) { - case FAILURE: - Log.i(TAG, "failure removing app"); // TODO: report to AppManager - finishInstall(true); - break; - case SUCCESS: - finishInstall(false); - // refresh app list - write(mmPebbleProtocol.encodeAppInfoReq()); - break; - default: - break; - } - break; - case INSTALL: - switch (appMgmtRes.result) { - case FAILURE: - Log.i(TAG, "failure installing app"); // TODO: report to Installer - finishInstall(true); - break; - case SUCCESS: - setToken(appMgmtRes.token); - break; - default: - break; - } - break; - default: - break; - } - default: - break; - } - } + switch (deviceCmd.commandClass) { + case MUSIC_CONTROL: + Log.i(TAG, "Got command for MUSIC_CONTROL"); + GBDeviceCommandMusicControl musicCmd = (GBDeviceCommandMusicControl) deviceCmd; + Intent musicIntent = new Intent(GBMusicControlReceiver.ACTION_MUSICCONTROL); + musicIntent.putExtra("command", musicCmd.command.ordinal()); + musicIntent.setPackage(context.getPackageName()); + context.sendBroadcast(musicIntent); + break; + case CALL_CONTROL: + Log.i(TAG, "Got command for CALL_CONTROL"); + GBDeviceCommandCallControl callCmd = (GBDeviceCommandCallControl) deviceCmd; + Intent callIntent = new Intent(GBCallControlReceiver.ACTION_CALLCONTROL); + callIntent.putExtra("command", callCmd.command.ordinal()); + callIntent.setPackage(context.getPackageName()); + context.sendBroadcast(callIntent); + break; + case VERSION_INFO: + Log.i(TAG, "Got command for VERSION_INFO"); + if (gbDevice == null) { + return; + } + GBDeviceCommandVersionInfo infoCmd = (GBDeviceCommandVersionInfo) deviceCmd; + gbDevice.setFirmwareVersion(infoCmd.fwVersion); + gbDevice.sendDeviceUpdateIntent(context); + break; + case APP_INFO: + Log.i(TAG, "Got command for APP_INFO"); + GBDeviceCommandAppInfo appInfoCmd = (GBDeviceCommandAppInfo) deviceCmd; + setInstallSlot(appInfoCmd.freeSlot); - public void setToken(int token) { - mmAppInstallToken = token; - } + Intent appInfoIntent = new Intent(AppManagerActivity.ACTION_REFRESH_APPLIST); + int appCount = appInfoCmd.apps.length; + appInfoIntent.putExtra("app_count", appCount); + for (Integer i = 0; i < appCount; i++) { + appInfoIntent.putExtra("app_name" + i.toString(), appInfoCmd.apps[i].getName()); + appInfoIntent.putExtra("app_creator" + i.toString(), appInfoCmd.apps[i].getCreator()); + appInfoIntent.putExtra("app_id" + i.toString(), appInfoCmd.apps[i].getId()); + appInfoIntent.putExtra("app_index" + i.toString(), appInfoCmd.apps[i].getIndex()); + appInfoIntent.putExtra("app_type" + i.toString(), appInfoCmd.apps[i].getType().ordinal()); + } + LocalBroadcastManager.getInstance(context).sendBroadcast(appInfoIntent); + break; + case APP_MANAGEMENT_RES: + GBDeviceCommandAppManagementResult appMgmtRes = (GBDeviceCommandAppManagementResult) deviceCmd; + switch (appMgmtRes.type) { + case DELETE: + // right now on the Pebble we also receive this on a failed/successful installation ;/ + switch (appMgmtRes.result) { + case FAILURE: + Log.i(TAG, "failure removing app"); // TODO: report to AppManager + finishInstall(true); + break; + case SUCCESS: + finishInstall(false); + // refresh app list + write(mmPebbleProtocol.encodeAppInfoReq()); + break; + default: + break; + } + break; + case INSTALL: + switch (appMgmtRes.result) { + case FAILURE: + Log.i(TAG, "failure installing app"); // TODO: report to Installer + finishInstall(true); + break; + case SUCCESS: + setToken(appMgmtRes.token); + break; + default: + break; + } + break; + default: + break; + } + default: + break; + } + } - public void setInstallSlot(int slot) { - if (mmIsInstalling) { - mmInstallSlot = slot; - } - } + public void setToken(int token) { + mmAppInstallToken = token; + } - private void writeInstallApp(byte[] bytes) { - if (!mmIsInstalling) { - return; - } - int length = bytes.length; - Log.i(TAG, "got bytes for writeInstallApp()" + length); - /* + public void setInstallSlot(int slot) { + if (mmIsInstalling) { + mmInstallSlot = slot; + } + } + + private void writeInstallApp(byte[] bytes) { + if (!mmIsInstalling) { + return; + } + int length = bytes.length; + Log.i(TAG, "got bytes for writeInstallApp()" + length); + /* final char[] hexArray = "0123456789ABCDEF".toCharArray(); char[] hexChars = new char[length * 2]; for (int j = 0; j < length; j++) { @@ -403,53 +405,53 @@ public class PebbleIoThread extends GBDeviceIoThread { } Log.i(TAG, new String(hexChars)); */ - try { - mmOutStream.write(bytes); - mmOutStream.flush(); - } catch (IOException e) { - } - } + try { + mmOutStream.write(bytes); + mmOutStream.flush(); + } catch (IOException e) { + } + } - public void installApp(Uri uri) { - if (mmIsInstalling) { - return; - } - write(mmPebbleProtocol.encodeAppInfoReq()); // do this here to get run() out of its blocking read - mmInstallState = PebbleAppInstallState.APP_WAIT_SLOT; - mmInstallURI = uri; - mmIsInstalling = true; - } + public void installApp(Uri uri) { + if (mmIsInstalling) { + return; + } + write(mmPebbleProtocol.encodeAppInfoReq()); // do this here to get run() out of its blocking read + mmInstallState = PebbleAppInstallState.APP_WAIT_SLOT; + mmInstallURI = uri; + mmIsInstalling = true; + } - public void finishInstall(boolean hadError) { - if (!mmIsInstalling) { - return; - } - if (hadError) { - GB.updateNotification("installation failed!", getContext()); - } else { - GB.updateNotification("installation successful", getContext()); - } - mmInstallState = PebbleAppInstallState.UNKNOWN; + public void finishInstall(boolean hadError) { + if (!mmIsInstalling) { + return; + } + if (hadError) { + GB.updateNotification("installation failed!", getContext()); + } else { + GB.updateNotification("installation successful", getContext()); + } + mmInstallState = PebbleAppInstallState.UNKNOWN; - if (hadError == true && mmAppInstallToken != -1) { - writeInstallApp(mmPebbleProtocol.encodeUploadCancel(mmAppInstallToken)); - } + if (hadError == true && mmAppInstallToken != -1) { + writeInstallApp(mmPebbleProtocol.encodeUploadCancel(mmAppInstallToken)); + } - mmPBWReader = null; - mmIsInstalling = false; - mmZis = null; - mmAppInstallToken = -1; - mmInstallSlot = -1; - } + mmPBWReader = null; + mmIsInstalling = false; + mmZis = null; + mmAppInstallToken = -1; + mmInstallSlot = -1; + } - public void quit() { - mmQuit = true; - if (mBtSocket != null) { - try { - mBtSocket.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } + public void quit() { + mmQuit = true; + if (mBtSocket != null) { + try { + mBtSocket.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } } \ No newline at end of file