1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-27 20:36:51 +01:00

Fossil/Skagen Hybrids: Add app/watchface downloading from watch to app manager

This commit is contained in:
Arjan Schrijver 2023-01-04 22:40:38 +01:00
parent 82dac7177e
commit 845887ddeb
16 changed files with 214 additions and 58 deletions

View File

@ -17,6 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.activities.appmanager;
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.QHybridSupport.QHYBRID_ACTION_DOWNLOADED_FILE;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@ -34,6 +36,7 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.PopupMenu;
import android.widget.Toast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@ -57,7 +60,11 @@ import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.ExternalPebbleJSActivity;
import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAppAdapter;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.FileManagementActivity;
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.FossilFileReader;
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.FossilHRInstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.QHybridConstants;
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.QHybridCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceApp;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
@ -65,6 +72,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.pebble.PebbleProtocol;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.GridAutoFitLayoutManager;
import nodomain.freeyourgadget.gadgetbridge.util.PebbleUtils;
import nodomain.freeyourgadget.gadgetbridge.util.Version;
@ -142,6 +150,7 @@ public abstract class AbstractAppManagerFragment extends Fragment {
app.setUpToDate(false);
}
} catch (IllegalArgumentException e) {
LOG.warn("App JSON: " + app.getJSON().toString());
LOG.warn("Couldn't read app version", e);
}
if (filterApp(app)) {
@ -174,19 +183,55 @@ public abstract class AbstractAppManagerFragment extends Fragment {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(ACTION_REFRESH_APPLIST)) {
if (intent.hasExtra("app_count")) {
LOG.info("got app info from device");
if (!isCacheManager()) {
LOG.info("will refresh list based on data from device");
refreshListFromDevice(intent);
switch (action) {
case ACTION_REFRESH_APPLIST: {
if (intent.hasExtra("app_count")) {
LOG.info("got app info from device");
if (!isCacheManager()) {
LOG.info("will refresh list based on data from device");
refreshListFromDevice(intent);
}
} else if (mCoordinator.supportsAppListFetching()) {
refreshList();
} else if (isCacheManager()) {
refreshList();
}
} else if (mCoordinator.supportsAppListFetching()) {
refreshList();
} else if (isCacheManager()) {
refreshList();
mGBDeviceAppAdapter.notifyDataSetChanged();
break;
}
case QHYBRID_ACTION_DOWNLOADED_FILE: {
if (!intent.getBooleanExtra("EXTRA_SUCCESS", false)) {
LOG.warn("wapp download was not successful");
GB.toast(context.getString(R.string.appmanager_download_app_error), Toast.LENGTH_LONG, GB.ERROR);
break;
}
if (!intent.getBooleanExtra("EXTRA_TOCACHE", false)) {
break;
}
String path = intent.getStringExtra("EXTRA_PATH");
String name = intent.getStringExtra("EXTRA_NAME");
LOG.info("Attempting to add downloaded app " + name + " to cache");
FossilFileReader fileReader;
try {
fileReader = new FossilFileReader(Uri.fromFile(new File(path)), context);
} catch (IOException e) {
LOG.warn("Could not find downloaded wapp", e);
break;
}
if (FossilHRInstallHandler.saveAppInCache(fileReader, fileReader.getBackground(), fileReader.getPreview(), mCoordinator, context)) {
LOG.info("Successfully moved downloaded app " + name + " to cache");
GB.toast(String.format(context.getString(R.string.appmanager_downloaded_to_cache), name), Toast.LENGTH_LONG, GB.INFO);
if (isCacheManager()) {
refreshList();
mGBDeviceAppAdapter.notifyDataSetChanged();
}
(new File(path)).delete();
} else {
LOG.warn("Parsing downloaded wapp was not successful");
GB.toast(context.getString(R.string.appmanager_download_app_error), Toast.LENGTH_LONG, GB.ERROR);
}
break;
}
mGBDeviceAppAdapter.notifyDataSetChanged();
}
}
};
@ -306,6 +351,7 @@ public abstract class AbstractAppManagerFragment extends Fragment {
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_REFRESH_APPLIST);
filter.addAction(QHYBRID_ACTION_DOWNLOADED_FILE);
LocalBroadcastManager.getInstance(getContext()).registerReceiver(mReceiver, filter);
@ -401,12 +447,7 @@ public abstract class AbstractAppManagerFragment extends Fragment {
}
public void onItemClick(View view, GBDeviceApp deviceApp) {
if (isCacheManager()) {
openPopupMenu(view, deviceApp);
} else {
UUID uuid = deviceApp.getUUID();
GBApplication.deviceService(mGBDevice).onAppStart(uuid, true);
}
openPopupMenu(view, deviceApp);
}
public boolean openPopupMenu(View view, GBDeviceApp deviceApp) {
@ -415,6 +456,12 @@ public abstract class AbstractAppManagerFragment extends Fragment {
Menu menu = popupMenu.getMenu();
final GBDeviceApp selectedApp = deviceApp;
if (!selectedApp.isOnDevice() || selectedApp.getType() != GBDeviceApp.Type.WATCHFACE) {
menu.removeItem(R.id.appmanager_watchface_activate);
}
if (!selectedApp.isOnDevice() || selectedApp.getType() != GBDeviceApp.Type.APP_GENERIC) {
menu.removeItem(R.id.appmanager_app_start);
}
if (!selectedApp.isInCache()) {
menu.removeItem(R.id.appmanager_app_edit);
menu.removeItem(R.id.appmanager_app_reinstall);
@ -455,6 +502,9 @@ public abstract class AbstractAppManagerFragment extends Fragment {
if ((mGBDevice.getType() != DeviceType.FOSSILQHYBRID) || (selectedApp.getType() != GBDeviceApp.Type.WATCHFACE)) {
menu.removeItem(R.id.appmanager_app_edit);
}
if ((mGBDevice.getType() != DeviceType.FOSSILQHYBRID) || (!selectedApp.isOnDevice()) || ((selectedApp.getType() != GBDeviceApp.Type.WATCHFACE) && (selectedApp.getType() != GBDeviceApp.Type.APP_GENERIC))) {
menu.removeItem(R.id.appmanager_app_download);
}
if (mGBDevice.getType() == DeviceType.PEBBLE) {
switch (selectedApp.getType()) {
@ -514,6 +564,14 @@ public abstract class AbstractAppManagerFragment extends Fragment {
}
GBApplication.deviceService(mGBDevice).onAppDelete(selectedApp.getUUID());
return true;
case R.id.appmanager_app_start:
case R.id.appmanager_watchface_activate:
GBApplication.deviceService(mGBDevice).onAppStart(selectedApp.getUUID(), true);
return true;
case R.id.appmanager_app_download:
GBApplication.deviceService(mGBDevice).onAppDownload(selectedApp.getUUID());
GB.toast(getContext().getString(R.string.appmanager_download_started), Toast.LENGTH_LONG, GB.INFO);
return true;
case R.id.appmanager_app_reinstall:
File cachePath = new File(appCacheDir, selectedApp.getUUID() + mCoordinator.getAppFileExtension());
GBApplication.deviceService(mGBDevice).onInstallApp(Uri.fromFile(cachePath));

View File

@ -76,6 +76,8 @@ public interface EventHandler {
void onAppStart(UUID uuid, boolean start);
void onAppDownload(UUID uuid);
void onAppDelete(UUID uuid);
void onAppConfiguration(UUID appUuid, String config, Integer id);

View File

@ -175,7 +175,9 @@ public class FileManagementActivity extends AbstractGBActivity implements View.O
Intent fileIntent = new Intent();
fileIntent.putExtra("EXTRA_ENCRYPTED", isEncrypted);
fileIntent.setAction(QHybridSupport.QHYBRID_COMMAND_DOWNLOAD_FILE);
fileIntent.putExtra("EXTRA_HANDLE", (FileHandle) fileTypesSpinner.getSelectedItem());
fileIntent.putExtra("EXTRA_MAJORHANDLE", ((FileHandle) fileTypesSpinner.getSelectedItem()).getMajorHandle());
fileIntent.putExtra("EXTRA_MINORHANDLE", ((FileHandle) fileTypesSpinner.getSelectedItem()).getMinorHandle());
fileIntent.putExtra("EXTRA_NAME", ((FileHandle) fileTypesSpinner.getSelectedItem()).name());
LocalBroadcastManager.getInstance(this).sendBroadcast(fileIntent);
} else if (v.getId() == R.id.qhybrid_button_upload_file) {
Intent chooserIntent = new Intent()

View File

@ -102,7 +102,6 @@ public class FossilHRInstallHandler implements InstallHandler {
installActivity.setInstallItem(installItem);
}
@Override
public void onStartInstall(GBDevice device) {
DeviceCoordinator mCoordinator = DeviceHelper.getInstance().getCoordinator(device);
@ -116,7 +115,7 @@ public class FossilHRInstallHandler implements InstallHandler {
manager.sendBroadcast(new Intent(AbstractAppManagerFragment.ACTION_REFRESH_APPLIST));
}
public static void saveAppInCache(FossilFileReader fossilFile, Bitmap backgroundImg, Bitmap previewImg, DeviceCoordinator mCoordinator, Context mContext) {
public static boolean saveAppInCache(FossilFileReader fossilFile, Bitmap backgroundImg, Bitmap previewImg, DeviceCoordinator mCoordinator, Context mContext) {
GBDeviceApp app;
File destDir;
// write app file
@ -127,7 +126,7 @@ public class FossilHRInstallHandler implements InstallHandler {
FileUtils.copyURItoFile(mContext, fossilFile.getUri(), new File(destDir, app.getUUID().toString() + mCoordinator.getAppFileExtension()));
} catch (IOException e) {
LOG.error("Saving app in cache failed: " + e.getMessage(), e);
return;
return false;
}
// write app metadata
File outputFile = new File(destDir, app.getUUID().toString() + ".json");
@ -136,7 +135,7 @@ public class FossilHRInstallHandler implements InstallHandler {
writer = new BufferedWriter(new FileWriter(outputFile));
} catch (IOException e) {
LOG.error("Failed to open output file: " + e.getMessage(), e);
return;
return false;
}
try {
LOG.info(app.getJSON().toString());
@ -150,8 +149,10 @@ public class FossilHRInstallHandler implements InstallHandler {
writer.close();
} catch (IOException e) {
LOG.error("Failed to write to output file: " + e.getMessage(), e);
return false;
} catch (JSONException e) {
LOG.error(e.getMessage(), e);
LOG.error("Failed to load or write appKeys JSON: " + e.getMessage(), e);
return false;
}
// write watchface background image
if (backgroundImg != null) {
@ -162,6 +163,7 @@ public class FossilHRInstallHandler implements InstallHandler {
fos.close();
} catch (IOException e) {
LOG.error("Failed to write to output file: " + e.getMessage(), e);
return false;
}
}
// write watchface preview image
@ -173,8 +175,10 @@ public class FossilHRInstallHandler implements InstallHandler {
fos.close();
} catch (IOException e) {
LOG.error("Failed to write to output file: " + e.getMessage(), e);
return false;
}
}
return true;
}
@Override

View File

@ -301,6 +301,13 @@ public class GBDeviceService implements DeviceService {
invokeService(intent);
}
@Override
public void onAppDownload(UUID uuid) {
Intent intent = createIntent().setAction(ACTION_DOWNLOADAPP)
.putExtra(EXTRA_APP_UUID, uuid);
invokeService(intent);
}
@Override
public void onAppDelete(UUID uuid) {
Intent intent = createIntent().setAction(ACTION_DELETEAPP)

View File

@ -44,6 +44,7 @@ public interface DeviceService extends EventHandler {
String ACTION_REQUEST_APPINFO = PREFIX + ".action.request_appinfo";
String ACTION_REQUEST_SCREENSHOT = PREFIX + ".action.request_screenshot";
String ACTION_STARTAPP = PREFIX + ".action.startapp";
String ACTION_DOWNLOADAPP = PREFIX + ".action.downloadapp";
String ACTION_DELETEAPP = PREFIX + ".action.deleteapp";
String ACTION_APP_CONFIGURE = PREFIX + ".action.app_configure";
String ACTION_APP_REORDER = PREFIX + ".action.app_reorder";

View File

@ -748,6 +748,16 @@ public abstract class AbstractDeviceSupport implements DeviceSupport {
}
/**
* If apps can be downloaded from the device, this method can be
* overridden and implemented by the device support class.
* @param uuid the Gadgetbridge internal UUID of the app
*/
@Override
public void onAppDownload(UUID uuid) {
}
/**
* If apps on the device can be deleted with a command, this method
* can be overridden and implemented by the device support class.

View File

@ -134,6 +134,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SE
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_SET_WORLD_CLOCKS;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_START;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_STARTAPP;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_DOWNLOADAPP;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_TEST_NEW_FUNCTION;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_ALARMS;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_APP_CONFIG;
@ -847,6 +848,11 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
deviceSupport.onAppStart(uuid, start);
break;
}
case ACTION_DOWNLOADAPP: {
UUID uuid = (UUID) intent.getSerializableExtra(EXTRA_APP_UUID);
deviceSupport.onAppDownload(uuid);
break;
}
case ACTION_DELETEAPP: {
UUID uuid = (UUID) intent.getSerializableExtra(EXTRA_APP_UUID);
deviceSupport.onAppDelete(uuid);

View File

@ -251,6 +251,14 @@ public class ServiceDeviceSupport implements DeviceSupport {
delegate.onAppStart(uuid, start);
}
@Override
public void onAppDownload(UUID uuid) {
if (checkBusy("app download")) {
return;
}
delegate.onAppDownload(uuid);
}
@Override
public void onAppDelete(UUID uuid) {
if (checkBusy("app delete")) {

View File

@ -284,10 +284,10 @@ public class QHybridSupport extends QHybridBaseSupport {
break;
}
case QHYBRID_COMMAND_DOWNLOAD_FILE:{
Object handleObject = intent.getSerializableExtra("EXTRA_HANDLE");
if(handleObject == null || !(handleObject instanceof FileHandle)) return;
FileHandle handle = (FileHandle) handleObject;
watchAdapter.downloadFile(handle, intent.getBooleanExtra("EXTRA_ENCRYPTED", false));
byte majorHandle = intent.getByteExtra("EXTRA_MAJORHANDLE", (byte) 0x00);
byte minorHandle = intent.getByteExtra("EXTRA_MINORHANDLE", (byte) 0x00);
String filename = intent.getStringExtra("EXTRA_NAME");
watchAdapter.downloadFile(majorHandle, minorHandle, filename, intent.getBooleanExtra("EXTRA_ENCRYPTED", false), false);
break;
}
case QHYBRID_COMMAND_UPLOAD_FILE:{
@ -833,6 +833,11 @@ public class QHybridSupport extends QHybridBaseSupport {
}
}
@Override
public void onAppDownload(UUID uuid) {
((FossilHRWatchAdapter) watchAdapter).downloadAppToCache(uuid);
}
@Override
public void onAppDelete(UUID uuid) {
if(this.watchAdapter instanceof FossilHRWatchAdapter) {

View File

@ -147,7 +147,7 @@ public abstract class WatchAdapter {
public void onDeleteNotification(int id) {
}
public void downloadFile(FileHandle handle, boolean fileIsEncrypted) {
public void downloadFile(byte majorHandle, byte minorHandle, String name, boolean fileIsEncrypted, boolean toCache) {
}
public void uploadFileGenerateHeader(FileHandle handle, String filePath, boolean fileIsEncrypted) {

View File

@ -486,6 +486,16 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
}
}
public void downloadAppToCache(UUID uuid) {
LOG.info("Going to download app with UUID " + uuid.toString());
for (ApplicationInformation appInfo : installedApplications) {
if (UUID.nameUUIDFromBytes(appInfo.getAppName().getBytes(StandardCharsets.UTF_8)).equals(uuid)) {
LOG.info("Going to download app with name " + appInfo.getAppName() + " and handle " + appInfo.getFileHandle());
downloadFile(FileHandle.APP_CODE.getMajorHandle(), appInfo.getFileHandle(), appInfo.getAppName(), false, true);
}
}
}
private void setVibrationStrengthFromConfig() {
Prefs prefs = new Prefs(getDeviceSpecificPreferences());
int vibrationStrengh = prefs.getInt(DeviceSettingsPreferenceConst.PREF_VIBRATION_STRENGH_PERCENTAGE, 2);
@ -920,15 +930,18 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
}
}
private void handleFileDownload(FileHandle handle, byte[] file) {
private void handleFileDownload(String name, byte[] file, boolean toCache) {
Intent resultIntent = new Intent(QHybridSupport.QHYBRID_ACTION_DOWNLOADED_FILE);
File outputFile = new File(getContext().getExternalFilesDir("download"), handle.name() + "_" + System.currentTimeMillis() + ".bin");
File outputFile = new File(getContext().getExternalFilesDir("download"), name + "_" + System.currentTimeMillis() + ".bin");
try {
FileOutputStream fos = new FileOutputStream(outputFile);
fos.write(file);
fos.close();
resultIntent.putExtra("EXTRA_SUCCESS", true);
resultIntent.putExtra("EXTRA_PATH", outputFile.getAbsolutePath());
resultIntent.putExtra("EXTRA_NAME", name);
resultIntent.putExtra("EXTRA_TOCACHE", toCache);
LOG.info("Wrote downloaded file to " + outputFile.getAbsolutePath());
} catch (IOException e) {
LOG.error("Error while downloading file", e);
resultIntent.putExtra("EXTRA_SUCCESS", false);
@ -1002,21 +1015,21 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
}
@Override
public void downloadFile(final FileHandle handle, boolean fileIsEncrypted) {
public void downloadFile(byte majorHandle, byte minorHandle, String name, boolean fileIsEncrypted, boolean toCache) {
if (fileIsEncrypted) {
queueWrite((FileEncryptedInterface) new FileEncryptedGetRequest(handle, this) {
queueWrite((FileEncryptedInterface) new FileEncryptedGetRequest(majorHandle, minorHandle, this) {
@Override
public void handleFileData(byte[] fileData) {
LOG.debug("downloaded encrypted file");
handleFileDownload(handle, fileData);
handleFileDownload(name, fileData, toCache);
}
});
} else {
queueWrite(new FileGetRawRequest(handle, this) {
queueWrite(new FileGetRawRequest(majorHandle, minorHandle, this) {
@Override
public void handleFileRawData(byte[] fileData) {
LOG.debug("downloaded regular file");
handleFileDownload(handle, fileData);
handleFileDownload(name, fileData, toCache);
}
});
}

View File

@ -24,12 +24,14 @@ import java.util.UUID;
import java.util.zip.CRC32;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil.FossilWatchAdapter;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.adapter.fossil_hr.FossilHRWatchAdapter;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.file.FileHandle;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil.FossilRequest;
import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.file.ResultCode;
public abstract class FileGetRawRequest extends FossilRequest {
private short handle;
private byte majorHandle;
private byte minorHandle;
private FossilWatchAdapter adapter;
private ByteBuffer fileBuffer;
@ -38,20 +40,26 @@ public abstract class FileGetRawRequest extends FossilRequest {
private boolean finished = false;
public FileGetRawRequest(short handle, FossilWatchAdapter adapter) {
this.handle = handle;
public FileGetRawRequest(byte majorHandle, byte minorHandle, FossilWatchAdapter adapter) {
this.majorHandle = majorHandle;
this.minorHandle = minorHandle;
this.adapter = adapter;
this.data =
createBuffer()
.putShort(handle)
.put(minorHandle)
.put(majorHandle)
.putInt(0)
.putInt(0xFFFFFFFF)
.array();
}
public FileGetRawRequest(FileHandle handle, FossilWatchAdapter adapter){
this(handle.getHandle(), adapter);
public FileGetRawRequest(FileHandle handle, FossilWatchAdapter adapter) {
this(handle.getMajorHandle(), handle.getMinorHandle(), adapter);
}
public FileGetRawRequest(short handle, FossilWatchAdapter adapter) {
this((byte) ((handle >> 8) & 0xff), (byte) (handle), adapter);
}
public FossilWatchAdapter getAdapter() {
@ -72,7 +80,8 @@ public abstract class FileGetRawRequest extends FossilRequest {
ByteBuffer buffer = ByteBuffer.wrap(value);
buffer.order(ByteOrder.LITTLE_ENDIAN);
short handle = buffer.getShort(1);
short minorHandle = buffer.get(1);
short majorHandle = buffer.get(2);
int size = buffer.getInt(4);
byte status = buffer.get(3);
@ -82,8 +91,11 @@ public abstract class FileGetRawRequest extends FossilRequest {
throw new RuntimeException("FileGet error: " + code + " (" + status + ")");
}
if(this.handle != handle){
throw new RuntimeException("handle: " + handle + " expected: " + this.handle);
if (this.minorHandle != minorHandle) {
throw new RuntimeException("minor handle: " + minorHandle + " expected: " + this.minorHandle);
}
if (this.majorHandle != majorHandle) {
throw new RuntimeException("major handle: " + majorHandle + " expected: " + this.majorHandle);
}
log("file size: " + size);
fileBuffer = ByteBuffer.allocate(size);
@ -94,8 +106,11 @@ public abstract class FileGetRawRequest extends FossilRequest {
buffer.order(ByteOrder.LITTLE_ENDIAN);
short handle = buffer.getShort(1);
if(this.handle != handle){
throw new RuntimeException("handle: " + handle + " expected: " + this.handle);
if (this.minorHandle != minorHandle) {
throw new RuntimeException("minor handle: " + minorHandle + " expected: " + this.minorHandle);
}
if (this.majorHandle != majorHandle) {
throw new RuntimeException("major handle: " + majorHandle + " expected: " + this.majorHandle);
}
CRC32 crc = new CRC32();
@ -104,7 +119,7 @@ public abstract class FileGetRawRequest extends FossilRequest {
int crcExpected = buffer.getInt(8);
if((int) crc.getValue() != crcExpected){
throw new RuntimeException("handle: " + handle + " expected: " + this.handle);
throw new RuntimeException("crc: " + crc.getValue() + " expected: " + crcExpected);
}
this.handleFileRawData(this.fileData);

View File

@ -43,7 +43,8 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
public abstract class FileEncryptedGetRequest extends FossilRequest implements FileEncryptedInterface{
private short handle;
private byte majorHandle;
private byte minorHandle;
private FossilHRWatchAdapter adapter;
private ByteBuffer fileBuffer;
@ -61,20 +62,22 @@ public abstract class FileEncryptedGetRequest extends FossilRequest implements F
private int packetCount = 0;
private int ivIncrementor = 0x1f;
public FileEncryptedGetRequest(short handle, FossilHRWatchAdapter adapter) {
this.handle = handle;
public FileEncryptedGetRequest(byte majorHandle, byte minorHandle, FossilHRWatchAdapter adapter) {
this.majorHandle = majorHandle;
this.minorHandle = minorHandle;
this.adapter = adapter;
this.data =
createBuffer()
.putShort(handle)
.put(minorHandle)
.put(majorHandle)
.putInt(0)
.putInt(0xFFFFFFFF)
.array();
}
public FileEncryptedGetRequest(FileHandle handle, FossilHRWatchAdapter adapter) {
this(handle.getHandle(), adapter);
public FileEncryptedGetRequest(short handle, FossilHRWatchAdapter adapter) {
this((byte) ((handle >> 8) & 0xff), (byte) (handle), adapter);
}
private void initDecryption() {
@ -134,7 +137,8 @@ public abstract class FileEncryptedGetRequest extends FossilRequest implements F
this.initDecryption();
short handle = buffer.getShort(1);
short minorHandle = buffer.get(1);
short majorHandle = buffer.get(2);
fileSize = buffer.getInt(4);
byte status = buffer.get(3);
@ -144,8 +148,11 @@ public abstract class FileEncryptedGetRequest extends FossilRequest implements F
throw new RuntimeException("FileGet error: " + code + " (" + status + ")");
}
if (this.handle != handle) {
throw new RuntimeException("handle: " + handle + " expected: " + this.handle);
if (this.minorHandle != minorHandle) {
throw new RuntimeException("minor handle: " + minorHandle + " expected: " + this.minorHandle);
}
if (this.majorHandle != majorHandle) {
throw new RuntimeException("major handle: " + majorHandle + " expected: " + this.majorHandle);
}
log("file size: " + fileSize);
fileBuffer = ByteBuffer.allocate(fileSize);
@ -156,8 +163,11 @@ public abstract class FileEncryptedGetRequest extends FossilRequest implements F
buffer.order(ByteOrder.LITTLE_ENDIAN);
short handle = buffer.getShort(1);
if (this.handle != handle) {
throw new RuntimeException("handle: " + handle + " expected: " + this.handle);
if (this.minorHandle != minorHandle) {
throw new RuntimeException("minor handle: " + minorHandle + " expected: " + this.minorHandle);
}
if (this.majorHandle != majorHandle) {
throw new RuntimeException("major handle: " + majorHandle + " expected: " + this.majorHandle);
}
CRC32 crc = new CRC32();

View File

@ -1,5 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/appmanager_watchface_activate"
android:title="@string/appmanager_watchface_activate"/>
<item
android:id="@+id/appmanager_app_start"
android:title="@string/appmanager_app_start"/>
<item
android:id="@+id/appmanager_app_edit"
android:title="@string/appmanager_app_edit"/>
@ -9,6 +15,9 @@
<item
android:id="@+id/appmanager_app_share"
android:title="@string/appmanager_app_share"/>
<item
android:id="@+id/appmanager_app_download"
android:title="@string/appmanager_app_download"/>
<item
android:id="@+id/appmanager_app_delete"
android:title="@string/appmananger_app_delete"/>

View File

@ -102,6 +102,9 @@
<string name="appmanager_cached_watchapps_watchfaces">Apps in cache</string>
<string name="appmanager_installed_watchapps">Installed apps</string>
<string name="appmanager_installed_watchfaces">Installed watchfaces</string>
<string name="appmanager_watchface_activate">Activate</string>
<string name="appmanager_app_start">Start</string>
<string name="appmanager_app_download">Download to cache</string>
<string name="appmananger_app_delete">Delete</string>
<string name="appmananger_app_delete_cache">Delete and remove from cache</string>
<string name="appmananger_app_reinstall">Reinstall</string>
@ -117,6 +120,9 @@
<string name="app_configure">Configure</string>
<string name="app_move_to_top">Move to top</string>
<string name="appmanager_item_outdated">(outdated)</string>
<string name="appmanager_download_started">App download started</string>
<string name="appmanager_downloaded_to_cache">Downloaded %s to cache</string>
<string name="appmanager_download_app_error">Error downloading app</string>
<!-- Strings related to AppBlacklist -->
<string name="title_activity_notification_management">Notification settings</string>
<string name="blacklist_all_for_notifications">Blacklist all for notifications</string>