diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AppManagerActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AppManagerActivity.java index 764aed0dc..30f25b6a5 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AppManagerActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/AppManagerActivity.java @@ -6,6 +6,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; +import android.view.ContextMenu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; import android.widget.ListView; import java.util.ArrayList; @@ -15,15 +19,8 @@ import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAppAdapter; public class AppManagerActivity extends Activity { - private final String TAG = this.getClass().getSimpleName(); - public static final String ACTION_REFRESH_APPLIST = "nodomain.freeyourgadget.gadgetbride.appmanager.action.refresh_applist"; - - ListView appListView; - GBDeviceAppAdapter mGBDeviceAppAdapter; - final List appList = new ArrayList<>(); - private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -31,16 +28,25 @@ public class AppManagerActivity extends Activity { if (action.equals(ControlCenter.ACTION_QUIT)) { finish(); } else if (action.equals(ACTION_REFRESH_APPLIST)) { + appList.clear(); int appCount = intent.getIntExtra("app_count", 0); for (Integer i = 0; i < appCount; i++) { String appName = intent.getStringExtra("app_name" + i.toString()); String appCreator = intent.getStringExtra("app_creator" + i.toString()); - appList.add(new GBDeviceApp(appName, appCreator, "")); + int id = intent.getIntExtra("app_id" + i.toString(), -1); + int index = intent.getIntExtra("app_index" + i.toString(), -1); + + appList.add(new GBDeviceApp(id, index, appName, appCreator, "")); } mGBDeviceAppAdapter.notifyDataSetChanged(); } } }; + final List appList = new ArrayList<>(); + private final String TAG = this.getClass().getSimpleName(); + private ListView appListView; + private GBDeviceAppAdapter mGBDeviceAppAdapter; + private GBDeviceApp selectedApp = null; @Override protected void onCreate(Bundle savedInstanceState) { @@ -50,6 +56,7 @@ public class AppManagerActivity extends Activity { appListView = (ListView) findViewById(R.id.appListView); mGBDeviceAppAdapter = new GBDeviceAppAdapter(this, appList); appListView.setAdapter(this.mGBDeviceAppAdapter); + registerForContextMenu(appListView); IntentFilter filter = new IntentFilter(); filter.addAction(ControlCenter.ACTION_QUIT); @@ -61,6 +68,33 @@ public class AppManagerActivity extends Activity { startService(startIntent); } + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, v, menuInfo); + getMenuInflater().inflate( + R.menu.appmanager_context, menu); + AdapterView.AdapterContextMenuInfo acmi = (AdapterView.AdapterContextMenuInfo) menuInfo; + selectedApp = appList.get(acmi.position); + menu.setHeaderTitle(selectedApp.getName()); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.appmanager_app_delete: + if (selectedApp != null) { + Intent deleteIntent = new Intent(this, BluetoothCommunicationService.class); + deleteIntent.setAction(BluetoothCommunicationService.ACTION_DELETEAPP); + deleteIntent.putExtra("app_id", selectedApp.getId()); + deleteIntent.putExtra("app_index", selectedApp.getIndex()); + startService(deleteIntent); + } + return true; + default: + return super.onContextItemSelected(item); + } + } + @Override protected void onDestroy() { super.onDestroy(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java index 39b0e5cea..d81a2a6ff 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/BluetoothCommunicationService.java @@ -31,6 +31,7 @@ import java.nio.ByteOrder; import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommand; import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandAppInfo; +import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandAppManagementResult; import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandCallControl; import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandMusicControl; import nodomain.freeyourgadget.gadgetbridge.protocol.GBDeviceCommandVersionInfo; @@ -57,6 +58,8 @@ public class BluetoothCommunicationService extends Service { = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.request_versioninfo"; public static final String ACTION_REQUEST_APPINFO = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.request_appinfo"; + public static final String ACTION_DELETEAPP + = "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.deleteapp"; private static final String TAG = "BluetoothCommunicationService"; private static final int NOTIFICATION_ID = 1; @@ -128,14 +131,14 @@ public class BluetoothCommunicationService extends Service { switch (deviceCmd.commandClass) { case MUSIC_CONTROL: Log.i(TAG, "Got command for MUSIC_CONTROL"); - GBDeviceCommandMusicControl musicCmd = (GBDeviceCommandMusicControl)deviceCmd; + GBDeviceCommandMusicControl musicCmd = (GBDeviceCommandMusicControl) deviceCmd; Intent musicIntent = new Intent(GBMusicControlReceiver.ACTION_MUSICCONTROL); musicIntent.putExtra("command", musicCmd.command.ordinal()); sendBroadcast(musicIntent); break; case CALL_CONTROL: Log.i(TAG, "Got command for CALL_CONTROL"); - GBDeviceCommandCallControl callCmd = (GBDeviceCommandCallControl)deviceCmd; + GBDeviceCommandCallControl callCmd = (GBDeviceCommandCallControl) deviceCmd; Intent callIntent = new Intent(GBCallControlReceiver.ACTION_CALLCONTROL); callIntent.putExtra("command", callCmd.command.ordinal()); sendBroadcast(callIntent); @@ -145,22 +148,43 @@ public class BluetoothCommunicationService extends Service { if (gbdevice == null) { return; } - GBDeviceCommandVersionInfo infoCmd = (GBDeviceCommandVersionInfo)deviceCmd; + GBDeviceCommandVersionInfo infoCmd = (GBDeviceCommandVersionInfo) deviceCmd; gbdevice.setFirmwareVersion(infoCmd.fwVersion); sendDeviceUpdateIntent(); break; case APP_INFO: Log.i(TAG, "Got command for APP_INFO"); - GBDeviceCommandAppInfo appInfoCmd = (GBDeviceCommandAppInfo)deviceCmd; + GBDeviceCommandAppInfo appInfoCmd = (GBDeviceCommandAppInfo) deviceCmd; 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()); } sendBroadcast(appInfoIntent); break; + 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; + } default: break; } @@ -276,6 +300,10 @@ public class BluetoothCommunicationService extends Service { } } else if (action.equals(ACTION_REQUEST_APPINFO)) { mBtSocketIoThread.write(PebbleProtocol.encodeAppInfoReq()); + } 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)); } else if (action.equals(ACTION_START)) { startForeground(NOTIFICATION_ID, createNotification("Gadgetbridge running")); mStarted = true; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDeviceApp.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDeviceApp.java index 17b122325..fbf443a22 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDeviceApp.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBDeviceApp.java @@ -4,8 +4,12 @@ public class GBDeviceApp { private final String name; private final String creator; private final String version; + private final int id; + private final int index; - public GBDeviceApp(String name, String creator, String version) { + public GBDeviceApp(int id, int index, String name, String creator, String version) { + this.id = id; + this.index = index; this.name = name; this.creator = creator; this.version = version; @@ -22,4 +26,12 @@ public class GBDeviceApp { public String getVersion() { return version; } + + public int getId() { + return id; + } + + public int getIndex() { + return index; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceCommand.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceCommand.java index a257b1d2d..63092df00 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceCommand.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceCommand.java @@ -9,7 +9,8 @@ public abstract class GBDeviceCommand { MUSIC_CONTROL, CALL_CONTROL, APP_INFO, - VERSION_INFO + VERSION_INFO, + APP_MANAGEMENT_RES, } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceCommandAppManagementResult.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceCommandAppManagementResult.java new file mode 100644 index 000000000..1cd7202c8 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/GBDeviceCommandAppManagementResult.java @@ -0,0 +1,21 @@ +package nodomain.freeyourgadget.gadgetbridge.protocol; + +public class GBDeviceCommandAppManagementResult extends GBDeviceCommand { + public Result result = Result.UNKNOWN; + public CommandType type = CommandType.UNKNOWN; + + public GBDeviceCommandAppManagementResult() { + commandClass = CommandClass.APP_MANAGEMENT_RES; + } + + public enum CommandType { + UNKNOWN, + DELETE, + } + + public enum Result { + UNKNOWN, + SUCCESS, + FAILURE, + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/PebbleProtocol.java index 6661c9bb4..5f4efe0df 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/PebbleProtocol.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/protocol/PebbleProtocol.java @@ -69,10 +69,14 @@ public class PebbleProtocol { static final byte FIRMWAREVERSION_GETVERSION = 0; static final byte APPMANAGER_GETAPPBANKSTATUS = 1; + static final byte APPMANAGER_REMOVEAPP = 2; + + static final int APPMANAGER_RES_SUCCESS = 1; static final short LENGTH_PREFIX = 4; - static final short LENGTH_SETTIME = 9; - static final short LENGTH_PHONEVERSION = 21; + static final short LENGTH_SETTIME = 5; + static final short LENGTH_REMOVEAPP = 9; + static final short LENGTH_PHONEVERSION = 17; static final byte PHONEVERSION_APPVERSION_MAGIC = 2; // increase this if pebble complains @@ -166,9 +170,9 @@ public class PebbleProtocol { ts = System.currentTimeMillis() / 1000; ts += SimpleTimeZone.getDefault().getOffset(ts) / 1000; } - ByteBuffer buf = ByteBuffer.allocate(LENGTH_SETTIME); + ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_SETTIME); buf.order(ByteOrder.BIG_ENDIAN); - buf.putShort((short) (LENGTH_SETTIME - LENGTH_PREFIX)); + buf.putShort(LENGTH_SETTIME); buf.putShort(ENDPOINT_TIME); buf.put(TIME_SETTIME); buf.putInt((int) ts); @@ -222,10 +226,22 @@ public class PebbleProtocol { return encodeMessage(ENDPOINT_APPMANAGER, APPMANAGER_GETAPPBANKSTATUS, 0, null); } - public static byte[] encodePhoneVersion(byte os) { - ByteBuffer buf = ByteBuffer.allocate(LENGTH_PHONEVERSION); + public static byte[] encodeAppDelete(int id, int index) { + ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_REMOVEAPP); buf.order(ByteOrder.BIG_ENDIAN); - buf.putShort((short) (LENGTH_PHONEVERSION - LENGTH_PREFIX)); + buf.putShort(LENGTH_REMOVEAPP); + buf.putShort(ENDPOINT_APPMANAGER); + buf.put(APPMANAGER_REMOVEAPP); + buf.putInt(id); + buf.putInt(index); + + return buf.array(); + } + + public static byte[] encodePhoneVersion(byte os) { + ByteBuffer buf = ByteBuffer.allocate(LENGTH_PREFIX + LENGTH_PHONEVERSION); + buf.order(ByteOrder.BIG_ENDIAN); + buf.putShort(LENGTH_PHONEVERSION); buf.putShort(ENDPOINT_PHONEVERSION); buf.put((byte) 0x01); buf.putInt(-1); //0xffffffff @@ -296,7 +312,6 @@ public class PebbleProtocol { buf.get(versionString, 0, 32); versionCmd.fwVersion = new String(versionString).trim(); - Log.i(TAG, "Got firmware version: " + versionCmd.fwVersion); cmd = versionCmd; break; case ENDPOINT_APPMANAGER: @@ -310,23 +325,38 @@ public class PebbleProtocol { appInfoCmd.apps = new GBDeviceApp[banksUsed]; for (int i = 0; i < banksUsed; i++) { - buf.getInt(); // id - buf.getInt(); // index + int id = buf.getInt(); + int index = buf.getInt(); buf.get(appName, 0, 32); buf.get(creatorName, 0, 32); int flags = buf.getInt(); Short appVersion = buf.getShort(); - appInfoCmd.apps[i] = new GBDeviceApp(new String(appName).trim(), new String(creatorName).trim(), appVersion.toString()); + appInfoCmd.apps[i] = new GBDeviceApp(id, index, new String(appName).trim(), new String(creatorName).trim(), appVersion.toString()); } cmd = appInfoCmd; break; + case APPMANAGER_REMOVEAPP: + GBDeviceCommandAppManagementResult deleteRes = new GBDeviceCommandAppManagementResult(); + deleteRes.type = GBDeviceCommandAppManagementResult.CommandType.DELETE; + + int result = buf.getInt(); + switch (result) { + case APPMANAGER_RES_SUCCESS: + deleteRes.result = GBDeviceCommandAppManagementResult.Result.SUCCESS; + break; + default: + deleteRes.result = GBDeviceCommandAppManagementResult.Result.FAILURE; + break; + } + cmd = deleteRes; + break; default: Log.i(TAG, "Unknown APPMANAGER command" + pebbleCmd); break; } break; default: - return null; + break; } return cmd; diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ef82dae97..a796cc2b2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -8,9 +8,12 @@ Quit Refresh - App Manager Debug + + App Manager + Delete + Settings General Settings