mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-08-26 17:21:31 +02:00
Fossil Hybrid HR: Add watch app and watchface support to install handler
This commit is contained in:
parent
e12f391dd0
commit
9dac0a80c3
@ -0,0 +1,183 @@
|
|||||||
|
/* Copyright (C) 2021 Arjan Schrijver, Daniel Dakhno
|
||||||
|
|
||||||
|
This file is part of Gadgetbridge.
|
||||||
|
|
||||||
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU Affero General Public License as published
|
||||||
|
by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
Gadgetbridge is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Affero General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Affero General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads and parses files meant to be uploaded to Fossil Hybrid Q & HR watches.
|
||||||
|
* These can be firmware files, watch apps and watchfaces (HR only).
|
||||||
|
*/
|
||||||
|
public class FossilFileReader {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(FossilFileReader.class);
|
||||||
|
private final UriHelper uriHelper;
|
||||||
|
private boolean isValid = false;
|
||||||
|
private boolean isFirmware = false;
|
||||||
|
private boolean isApp = false;
|
||||||
|
private boolean isWatchface = false;
|
||||||
|
private String foundVersion = "(Unknown version)";
|
||||||
|
private String foundName = "(unknown)";
|
||||||
|
|
||||||
|
public FossilFileReader(Uri uri, Context context) throws IOException {
|
||||||
|
uriHelper = UriHelper.get(uri, context);
|
||||||
|
|
||||||
|
try (InputStream in = new BufferedInputStream(uriHelper.openInputStream())) {
|
||||||
|
// Read just the first 32 bytes for file type detection
|
||||||
|
byte[] bytes = new byte[32];
|
||||||
|
int read = in.read(bytes);
|
||||||
|
in.close();
|
||||||
|
if (read < 32) {
|
||||||
|
isValid = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap(bytes);
|
||||||
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
short handle = buf.getShort();
|
||||||
|
short version = buf.getShort();
|
||||||
|
if ((handle == 5630) && (version == 3)) {
|
||||||
|
// This is a watch app or watch face
|
||||||
|
isValid = true;
|
||||||
|
isApp = true;
|
||||||
|
parseApp();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Back to byte 0 for firmware detection
|
||||||
|
buf.rewind();
|
||||||
|
int header0 = buf.getInt();
|
||||||
|
buf.getInt(); // size
|
||||||
|
int header2 = buf.getInt();
|
||||||
|
int header3 = buf.getInt();
|
||||||
|
if (header0 != 1 || header2 != 0x00012000 || header3 != 0x00012000) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.getInt(); // unknown
|
||||||
|
isValid = true;
|
||||||
|
isFirmware = true;
|
||||||
|
parseFirmware();
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn("Error during Fossil file parsing", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseFirmware() throws IOException {
|
||||||
|
InputStream in = new BufferedInputStream(uriHelper.openInputStream());
|
||||||
|
byte[] bytes = new byte[in.available()];
|
||||||
|
in.read(bytes);
|
||||||
|
in.close();
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap(bytes);
|
||||||
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
buf.position(20);
|
||||||
|
int version1 = buf.get() % 0xff;
|
||||||
|
int version2 = buf.get() & 0xff;
|
||||||
|
foundVersion = "DN1.0." + version1 + "." + version2;
|
||||||
|
foundName = "Fossil Hybrid HR firmware";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parseApp() throws IOException {
|
||||||
|
InputStream in = new BufferedInputStream(uriHelper.openInputStream());
|
||||||
|
byte[] bytes = new byte[in.available()];
|
||||||
|
in.read(bytes);
|
||||||
|
in.close();
|
||||||
|
ByteBuffer buf = ByteBuffer.wrap(bytes);
|
||||||
|
buf.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
buf.position(8); // skip file handle and version
|
||||||
|
int fileSize = buf.getInt();
|
||||||
|
foundVersion = (int)buf.get() + "." + (int)buf.get() + "." + (int)buf.get() + "." + (int)buf.get();
|
||||||
|
buf.position(buf.position() + 8); // skip null bytes
|
||||||
|
int jerryStart = buf.getInt();
|
||||||
|
int appIconStart = buf.getInt();
|
||||||
|
int layout_start = buf.getInt();
|
||||||
|
int display_name_start = buf.getInt();
|
||||||
|
int display_name_start_2 = buf.getInt();
|
||||||
|
int config_start = buf.getInt();
|
||||||
|
int file_end = buf.getInt();
|
||||||
|
buf.position(jerryStart);
|
||||||
|
|
||||||
|
ArrayList<String> filenamesCode = parseAppFilenames(buf, appIconStart,false);
|
||||||
|
if (filenamesCode.size() > 0) {
|
||||||
|
foundName = filenamesCode.get(0);
|
||||||
|
}
|
||||||
|
ArrayList<String> filenamesIcons = parseAppFilenames(buf, layout_start,false);
|
||||||
|
ArrayList<String> filenamesLayout = parseAppFilenames(buf, display_name_start,true);
|
||||||
|
ArrayList<String> filenamesDisplayName = parseAppFilenames(buf, config_start,true);
|
||||||
|
if (filenamesDisplayName.contains("theme_class")) {
|
||||||
|
isApp = false;
|
||||||
|
isWatchface = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<String> parseAppFilenames(ByteBuffer buf, int untilPosition, boolean cutTrailingNull) {
|
||||||
|
ArrayList<String> list = new ArrayList<>();
|
||||||
|
while (buf.position() < untilPosition) {
|
||||||
|
int filenameLength = (int)buf.get();
|
||||||
|
byte[] filenameBytes = new byte[filenameLength - 1];
|
||||||
|
buf.get(filenameBytes);
|
||||||
|
buf.get();
|
||||||
|
list.add(new String(filenameBytes, Charset.forName("UTF8")));
|
||||||
|
int filesize = buf.getShort();
|
||||||
|
if (cutTrailingNull) {
|
||||||
|
filesize -= 1;
|
||||||
|
}
|
||||||
|
buf.position(buf.position() + filesize); // skip file data for now
|
||||||
|
if (cutTrailingNull) {
|
||||||
|
buf.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValid() {
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFirmware() {
|
||||||
|
return isFirmware;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isApp() {
|
||||||
|
return isApp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWatchface() {
|
||||||
|
return isWatchface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getVersion() {
|
||||||
|
return foundVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return foundName;
|
||||||
|
}
|
||||||
|
}
|
@ -19,11 +19,7 @@ package nodomain.freeyourgadget.gadgetbridge.devices.qhybrid;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity;
|
import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity;
|
||||||
@ -31,50 +27,19 @@ import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
|
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
|
||||||
|
|
||||||
public class FossilHRInstallHandler implements InstallHandler {
|
public class FossilHRInstallHandler implements InstallHandler {
|
||||||
|
private final Uri mUri;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private boolean mIsValid;
|
private FossilFileReader fossilFile;
|
||||||
private String mVersion = "(Unknown version)";
|
|
||||||
|
|
||||||
FossilHRInstallHandler(Uri uri, Context context) {
|
FossilHRInstallHandler(Uri uri, Context context) {
|
||||||
|
mUri = uri;
|
||||||
mContext = context;
|
mContext = context;
|
||||||
UriHelper uriHelper;
|
|
||||||
try {
|
try {
|
||||||
uriHelper = UriHelper.get(uri, mContext);
|
fossilFile = new FossilFileReader(uri, mContext);
|
||||||
} catch (IOException e) {
|
} catch (IOException ignored) {
|
||||||
mIsValid = false;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
try (InputStream in = new BufferedInputStream(uriHelper.openInputStream())) {
|
|
||||||
byte[] bytes = new byte[32];
|
|
||||||
int read = in.read(bytes);
|
|
||||||
if (read < 32) {
|
|
||||||
mIsValid = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.wrap(bytes);
|
|
||||||
buf.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
int header0 = buf.getInt();
|
|
||||||
buf.getInt(); // size
|
|
||||||
int header2 = buf.getInt();
|
|
||||||
int header3 = buf.getInt();
|
|
||||||
if (header0 != 1 || header2 != 0x00012000 || header3 != 0x00012000) {
|
|
||||||
mIsValid = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.getInt(); // unknown
|
|
||||||
int version1 = buf.get() % 0xff;
|
|
||||||
int version2 = buf.get() & 0xff;
|
|
||||||
mVersion = "DN1.0." + version1 + "." + version2;
|
|
||||||
} catch (Exception e) {
|
|
||||||
mIsValid = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mIsValid = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -84,17 +49,32 @@ public class FossilHRInstallHandler implements InstallHandler {
|
|||||||
installActivity.setInstallEnabled(false);
|
installActivity.setInstallEnabled(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (device.getType() != DeviceType.FOSSILQHYBRID || !device.isConnected()) {
|
if (device.getType() != DeviceType.FOSSILQHYBRID || !device.isConnected() || !fossilFile.isValid()) {
|
||||||
installActivity.setInfoText("Element cannot be installed");
|
installActivity.setInfoText("Element cannot be installed");
|
||||||
installActivity.setInstallEnabled(false);
|
installActivity.setInstallEnabled(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GenericItem installItem = new GenericItem();
|
GenericItem installItem = new GenericItem();
|
||||||
installItem.setIcon(R.drawable.ic_firmware);
|
if (fossilFile.isFirmware()) {
|
||||||
installItem.setName("Fossil Hybrid HR Firmware");
|
installItem.setIcon(R.drawable.ic_firmware);
|
||||||
installItem.setDetails(mVersion);
|
installItem.setName(fossilFile.getName());
|
||||||
|
installItem.setDetails(fossilFile.getVersion());
|
||||||
installActivity.setInfoText(mContext.getString(R.string.firmware_install_warning, "(unknown)"));
|
installActivity.setInfoText(mContext.getString(R.string.firmware_install_warning, "(unknown)"));
|
||||||
|
} else if (fossilFile.isApp()) {
|
||||||
|
installItem.setName(fossilFile.getName());
|
||||||
|
installItem.setDetails(fossilFile.getVersion());
|
||||||
|
installItem.setIcon(R.drawable.ic_watchapp);
|
||||||
|
installActivity.setInfoText(mContext.getString(R.string.app_install_info, installItem.getName(), fossilFile.getVersion(), "(unknown)"));
|
||||||
|
} else if (fossilFile.isWatchface()) {
|
||||||
|
installItem.setName(fossilFile.getName());
|
||||||
|
installItem.setDetails(fossilFile.getVersion());
|
||||||
|
installItem.setIcon(R.drawable.ic_watchface);
|
||||||
|
installActivity.setInfoText(mContext.getString(R.string.watchface_install_info, installItem.getName(), fossilFile.getVersion(), "(unknown)"));
|
||||||
|
} else {
|
||||||
|
installActivity.setInfoText("Element cannot be installed");
|
||||||
|
installActivity.setInstallEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
installActivity.setInstallEnabled(true);
|
installActivity.setInstallEnabled(true);
|
||||||
installActivity.setInstallItem(installItem);
|
installActivity.setInstallItem(installItem);
|
||||||
}
|
}
|
||||||
@ -106,6 +86,6 @@ public class FossilHRInstallHandler implements InstallHandler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid() {
|
public boolean isValid() {
|
||||||
return mIsValid;
|
return fossilFile.isValid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,9 @@ import android.os.ParcelUuid;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
@ -48,6 +51,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.Version;
|
import nodomain.freeyourgadget.gadgetbridge.util.Version;
|
||||||
|
|
||||||
public class QHybridCoordinator extends AbstractDeviceCoordinator {
|
public class QHybridCoordinator extends AbstractDeviceCoordinator {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(QHybridCoordinator.class);
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
|
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
|
||||||
@ -103,7 +108,12 @@ public class QHybridCoordinator extends AbstractDeviceCoordinator {
|
|||||||
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
public InstallHandler findInstallHandler(Uri uri, Context context) {
|
||||||
if (isHybridHR()) {
|
if (isHybridHR()) {
|
||||||
FossilHRInstallHandler installHandler = new FossilHRInstallHandler(uri, context);
|
FossilHRInstallHandler installHandler = new FossilHRInstallHandler(uri, context);
|
||||||
return installHandler.isValid() ? installHandler : null;
|
if (!installHandler.isValid()) {
|
||||||
|
LOG.warn("Not a Fossil Hybrid firmware or app!");
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return installHandler;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
FossilInstallHandler installHandler = new FossilInstallHandler(uri, context);
|
FossilInstallHandler installHandler = new FossilInstallHandler(uri, context);
|
||||||
return installHandler.isValid() ? installHandler : null;
|
return installHandler.isValid() ? installHandler : null;
|
||||||
|
@ -27,6 +27,7 @@ import android.graphics.Canvas;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@ -38,11 +39,13 @@ import org.json.JSONArray;
|
|||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.nio.BufferOverflowException;
|
import java.nio.BufferOverflowException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
@ -66,6 +69,7 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicControl;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl;
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.CommuteActionsActivity;
|
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.CommuteActionsActivity;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.FossilFileReader;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HybridHRActivitySampleProvider;
|
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.HybridHRActivitySampleProvider;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationHRConfiguration;
|
import nodomain.freeyourgadget.gadgetbridge.devices.qhybrid.NotificationHRConfiguration;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.entities.HybridHRActivitySample;
|
import nodomain.freeyourgadget.gadgetbridge.entities.HybridHRActivitySample;
|
||||||
@ -127,6 +131,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.mis
|
|||||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||||
|
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.util.Version;
|
import nodomain.freeyourgadget.gadgetbridge.util.Version;
|
||||||
|
|
||||||
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicControlRequest.MUSIC_PHONE_REQUEST;
|
import static nodomain.freeyourgadget.gadgetbridge.service.devices.qhybrid.requests.fossil_hr.music.MusicControlRequest.MUSIC_PHONE_REQUEST;
|
||||||
@ -692,32 +697,10 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
|||||||
@Override
|
@Override
|
||||||
public void uploadFileIncludesHeader(String filePath) {
|
public void uploadFileIncludesHeader(String filePath) {
|
||||||
final Intent resultIntent = new Intent(QHybridSupport.QHYBRID_ACTION_UPLOADED_FILE);
|
final Intent resultIntent = new Intent(QHybridSupport.QHYBRID_ACTION_UPLOADED_FILE);
|
||||||
byte[] fileData;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FileInputStream fis = new FileInputStream(filePath);
|
FileInputStream fis = new FileInputStream(filePath);
|
||||||
fileData = new byte[fis.available()];
|
uploadFileIncludesHeader(fis);
|
||||||
fis.read(fileData);
|
|
||||||
fis.close();
|
fis.close();
|
||||||
|
|
||||||
short handleBytes = (short) (fileData[0] & 0xFF | ((fileData[1] & 0xFF) << 8));
|
|
||||||
FileHandle handle = FileHandle.fromHandle(handleBytes);
|
|
||||||
|
|
||||||
if (handle == null) {
|
|
||||||
throw new RuntimeException("unknown handle");
|
|
||||||
}
|
|
||||||
|
|
||||||
queueWrite(new FilePutRawRequest(handle, fileData, this) {
|
|
||||||
@Override
|
|
||||||
public void onFilePut(boolean success) {
|
|
||||||
resultIntent.putExtra("EXTRA_SUCCESS", success);
|
|
||||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(resultIntent);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (handle == FileHandle.APP_CODE) {
|
|
||||||
listApplications();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.error("Error while uploading file", e);
|
LOG.error("Error while uploading file", e);
|
||||||
resultIntent.putExtra("EXTRA_SUCCESS", false);
|
resultIntent.putExtra("EXTRA_SUCCESS", false);
|
||||||
@ -725,6 +708,31 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void uploadFileIncludesHeader(InputStream fis) throws IOException {
|
||||||
|
final Intent resultIntent = new Intent(QHybridSupport.QHYBRID_ACTION_UPLOADED_FILE);
|
||||||
|
byte[] fileData = new byte[fis.available()];
|
||||||
|
fis.read(fileData);
|
||||||
|
|
||||||
|
short handleBytes = (short) (fileData[0] & 0xFF | ((fileData[1] & 0xFF) << 8));
|
||||||
|
FileHandle handle = FileHandle.fromHandle(handleBytes);
|
||||||
|
|
||||||
|
if (handle == null) {
|
||||||
|
throw new RuntimeException("unknown handle");
|
||||||
|
}
|
||||||
|
|
||||||
|
queueWrite(new FilePutRawRequest(handle, fileData, this) {
|
||||||
|
@Override
|
||||||
|
public void onFilePut(boolean success) {
|
||||||
|
resultIntent.putExtra("EXTRA_SUCCESS", success);
|
||||||
|
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(resultIntent);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (handle == FileHandle.APP_CODE) {
|
||||||
|
listApplications();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void downloadFile(final FileHandle handle, boolean fileIsEncrypted) {
|
public void downloadFile(final FileHandle handle, boolean fileIsEncrypted) {
|
||||||
if (fileIsEncrypted) {
|
if (fileIsEncrypted) {
|
||||||
@ -776,6 +784,24 @@ public class FossilHRWatchAdapter extends FossilWatchAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInstallApp(Uri uri) {
|
||||||
|
final Intent resultIntent = new Intent(QHybridSupport.QHYBRID_ACTION_UPLOADED_FILE);
|
||||||
|
FossilFileReader fossilFile;
|
||||||
|
try {
|
||||||
|
fossilFile = new FossilFileReader(uri, getContext());
|
||||||
|
if (fossilFile.isFirmware()) {
|
||||||
|
super.onInstallApp(uri);
|
||||||
|
} else if (fossilFile.isApp() || fossilFile.isWatchface()) {
|
||||||
|
UriHelper uriHelper = UriHelper.get(uri, getContext());
|
||||||
|
InputStream in = new BufferedInputStream(uriHelper.openInputStream());
|
||||||
|
uploadFileIncludesHeader(in);
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void negotiateSymmetricKey() {
|
private void negotiateSymmetricKey() {
|
||||||
try {
|
try {
|
||||||
queueWrite(new VerifyPrivateKeyRequest(
|
queueWrite(new VerifyPrivateKeyRequest(
|
||||||
|
@ -344,7 +344,8 @@
|
|||||||
<string name="installation_failed_">Installation failed</string>
|
<string name="installation_failed_">Installation failed</string>
|
||||||
<string name="installation_successful">Installed</string>
|
<string name="installation_successful">Installed</string>
|
||||||
<string name="firmware_install_warning">YOU ARE TRYING TO INSTALL A FIRMWARE, PROCEED AT YOUR OWN RISK.\n\n\n This firmware is for HW Revision: %s</string>
|
<string name="firmware_install_warning">YOU ARE TRYING TO INSTALL A FIRMWARE, PROCEED AT YOUR OWN RISK.\n\n\n This firmware is for HW Revision: %s</string>
|
||||||
<string name="app_install_info">You are about to install the following app:\n\n\n%1$s Version %2$s by %3$s\n</string>
|
<string name="app_install_info">You are about to install the following app:\n\n%1$s\nVersion %2$s by %3$s\n</string>
|
||||||
|
<string name="watchface_install_info">You are about to install the following watchface:\n\n%1$s\nVersion %2$s by %3$s\n</string>
|
||||||
<string name="n_a">N/A</string>
|
<string name="n_a">N/A</string>
|
||||||
<string name="initialized">initialized</string>
|
<string name="initialized">initialized</string>
|
||||||
<string name="appversion_by_creator">%1$s by %2$s</string>
|
<string name="appversion_by_creator">%1$s by %2$s</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user