diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 85bb980a..957a6be6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -5,7 +5,9 @@
-
+
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java
index 56fa1215..1ea4e746 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ControlCenter.java
@@ -340,13 +340,23 @@ public class ControlCenter extends Activity {
}
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
- String miAddr = sharedPrefs.getString(MiBandConst.PREF_MIBAND_ADDRESS, null);
- if (miAddr != null && miAddr.length() > 0) {
+ String miAddr = sharedPrefs.getString(MiBandConst.PREF_MIBAND_ADDRESS, "");
+ if (miAddr.length() > 0) {
GBDevice miDevice = new GBDevice(miAddr, "MI", DeviceType.MIBAND);
if (!availableDevices.contains(miDevice)) {
availableDevices.add(miDevice);
}
}
+
+ String pebbleEmuAddr = sharedPrefs.getString("pebble_emu_addr", "");
+ String pebbleEmuPort = sharedPrefs.getString("pebble_emu_port", "");
+ if (pebbleEmuAddr.length() >= 7 && pebbleEmuPort.length() > 0) {
+ GBDevice pebbleEmuDevice = new GBDevice(pebbleEmuAddr + ":" + pebbleEmuPort, "Pebble qemu", DeviceType.PEBBLE);
+ if (!availableDevices.contains(pebbleEmuDevice)) {
+ availableDevices.add(pebbleEmuDevice);
+ }
+ }
+
deviceList.retainAll(availableDevices);
for (GBDevice dev : availableDevices) {
if (!deviceList.contains(dev)) {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java
index 6f43ed43..735b68af 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/SettingsActivity.java
@@ -3,6 +3,7 @@ package nodomain.freeyourgadget.gadgetbridge.activities;
import android.content.Intent;
import android.os.Bundle;
import android.preference.Preference;
+import android.support.v4.content.LocalBroadcastManager;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandPreferencesActivity;
@@ -35,5 +36,37 @@ public class SettingsActivity extends AbstractSettingsActivity {
}
});
+ final Preference pebbleEmuAddr = findPreference("pebble_emu_addr");
+ pebbleEmuAddr.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newVal) {
+ Intent refreshIntent = new Intent(ControlCenter.ACTION_REFRESH_DEVICELIST);
+ LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(refreshIntent);
+ preference.setSummary(newVal.toString());
+ return true;
+ }
+
+ });
+
+ final Preference pebbleEmuPort = findPreference("pebble_emu_port");
+ pebbleEmuPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newVal) {
+ Intent refreshIntent = new Intent(ControlCenter.ACTION_REFRESH_DEVICELIST);
+ LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(refreshIntent);
+ preference.setSummary(newVal.toString());
+ return true;
+ }
+
+ });
}
+
+ @Override
+ protected String[] getPreferenceKeysWithSummary() {
+ return new String[]{
+ "pebble_emu_addr",
+ "pebble_emu_port"
+ };
+ }
+
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java
index 081fc7fa..97ac915f 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractChartFragment.java
@@ -483,7 +483,7 @@ public abstract class AbstractChartFragment extends Fragment {
}
protected List getSamples(DBHandler db, GBDevice device) {
- return getAllSamples(db, device, getTSStart(), getTSEnd());
+ return getSamples(db, device, getTSStart(), getTSEnd());
}
private int getTSEnd() {
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
index f29efe12..bd3b1bfb 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/DeviceSupportFactory.java
@@ -25,11 +25,16 @@ public class DeviceSupportFactory {
}
public synchronized DeviceSupport createDeviceSupport(String deviceAddress) throws GBException {
- DeviceSupport deviceSupport = createBTDeviceSupport(deviceAddress);
+ DeviceSupport deviceSupport;
+ if (deviceAddress.indexOf(":") == deviceAddress.lastIndexOf(":")) { // only one colon
+ deviceSupport = createTCPDeviceSupport(deviceAddress);
+ } else {
+ deviceSupport = createBTDeviceSupport(deviceAddress);
+ }
+
if (deviceSupport != null) {
return deviceSupport;
}
- // support for other kinds of transports
// no device found, check transport availability and warn
checkBtAvailability();
@@ -68,4 +73,16 @@ public class DeviceSupportFactory {
}
return null;
}
+
+ private DeviceSupport createTCPDeviceSupport(String deviceAddress) throws GBException {
+ try {
+ GBDevice gbDevice = new GBDevice(deviceAddress, "Pebble qemu", DeviceType.PEBBLE); //FIXME, do not hardcode
+ DeviceSupport deviceSupport = new ServiceDeviceSupport(new PebbleSupport(), EnumSet.of(ServiceDeviceSupport.Flags.BUSY_CHECKING));
+ deviceSupport.setContext(gbDevice, mBtAdapter, mContext);
+ return deviceSupport;
+ } catch (Exception e) {
+ throw new GBException("cannot connect to " + deviceAddress, e); // FIXME: localize
+ }
+ }
+
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java
index 4721ca33..44a113c6 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleIoThread.java
@@ -16,6 +16,8 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.zip.ZipInputStream;
@@ -37,14 +39,17 @@ public class PebbleIoThread extends GBDeviceIoThread {
private static final Logger LOG = LoggerFactory.getLogger(PebbleIoThread.class);
private final PebbleProtocol mPebbleProtocol;
private final PebbleSupport mPebbleSupport;
+ private boolean mIsTCP = false;
private BluetoothAdapter mBtAdapter = null;
private BluetoothSocket mBtSocket = null;
+ private Socket mTCPSocket = null; // for emulator
private InputStream mInStream = null;
private OutputStream mOutStream = null;
private boolean mQuit = false;
private boolean mIsConnected = false;
private boolean mIsInstalling = false;
private int mConnectionAttempts = 0;
+
private PBWReader mPBWReader = null;
private int mAppInstallToken = -1;
private ZipInputStream mZis = null;
@@ -66,14 +71,25 @@ public class PebbleIoThread extends GBDeviceIoThread {
@Override
protected boolean connect(String btDeviceAddress) {
- BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(btDeviceAddress);
- ParcelUuid uuids[] = btDevice.getUuids();
GBDevice.State originalState = gbDevice.getState();
try {
- mBtSocket = btDevice.createRfcommSocketToServiceRecord(uuids[0].getUuid());
- mBtSocket.connect();
- mInStream = mBtSocket.getInputStream();
- mOutStream = mBtSocket.getOutputStream();
+ // contains only one ":"? then it is addr:port
+ int firstColon = btDeviceAddress.indexOf(":");
+ if (firstColon == btDeviceAddress.lastIndexOf(":")) {
+ mIsTCP = true;
+ InetAddress serverAddr = InetAddress.getByName(btDeviceAddress.substring(0, firstColon));
+ mTCPSocket = new Socket(serverAddr, Integer.parseInt(btDeviceAddress.substring(firstColon + 1)));
+ mInStream = mTCPSocket.getInputStream();
+ mOutStream = mTCPSocket.getOutputStream();
+ } else {
+ mIsTCP = false;
+ BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(btDeviceAddress);
+ ParcelUuid uuids[] = btDevice.getUuids();
+ mBtSocket = btDevice.createRfcommSocketToServiceRecord(uuids[0].getUuid());
+ mBtSocket.connect();
+ mInStream = mBtSocket.getInputStream();
+ mOutStream = mBtSocket.getOutputStream();
+ }
} catch (IOException e) {
e.printStackTrace();
gbDevice.setState(originalState);
@@ -187,11 +203,14 @@ public class PebbleIoThread extends GBDeviceIoThread {
break;
}
}
+ if (mIsTCP) {
+ mInStream.skip(6);
+ }
int bytes = mInStream.read(buffer, 0, 4);
+
if (bytes < 4) {
continue;
}
-
ByteBuffer buf = ByteBuffer.wrap(buffer);
buf.order(ByteOrder.BIG_ENDIAN);
short length = buf.getShort();
@@ -214,6 +233,10 @@ public class PebbleIoThread extends GBDeviceIoThread {
bytes += mInStream.read(buffer, bytes + 4, length - bytes);
}
+ if (mIsTCP) {
+ mInStream.skip(2);
+ }
+
GBDeviceEvent deviceEvent = mPebbleProtocol.decodeResponse(buffer);
if (deviceEvent == null) {
LOG.info("unhandled message to endpoint " + endpoint + " (" + length + " bytes)");
@@ -261,15 +284,31 @@ public class PebbleIoThread extends GBDeviceIoThread {
gbDevice.sendDeviceUpdateIntent(getContext());
}
+ private void write_real(byte[] bytes) {
+ try {
+ if (mIsTCP) {
+ ByteBuffer buf = ByteBuffer.allocate(bytes.length + 8);
+ buf.order(ByteOrder.BIG_ENDIAN);
+ buf.putShort((short) 0xfeed);
+ buf.putShort((short) 1);
+ buf.putShort((short) bytes.length);
+ buf.put(bytes);
+ buf.putShort((short) 0xbeef);
+ mOutStream.write(buf.array());
+ mOutStream.flush();
+ } else {
+ mOutStream.write(bytes);
+ mOutStream.flush();
+ }
+ } catch (IOException e) {
+ }
+ }
+
@Override
synchronized public void write(byte[] bytes) {
// block writes if app installation in in progress
if (mIsConnected && (!mIsInstalling || mInstallState == PebbleAppInstallState.WAIT_SLOT)) {
- try {
- mOutStream.write(bytes);
- mOutStream.flush();
- } catch (IOException e) {
- }
+ write_real(bytes);
}
}
@@ -371,13 +410,8 @@ public class PebbleIoThread extends GBDeviceIoThread {
if (!mIsInstalling) {
return;
}
- int length = bytes.length;
- LOG.info("got " + length + "bytes for writeInstallApp()");
- try {
- mOutStream.write(bytes);
- mOutStream.flush();
- } catch (IOException e) {
- }
+ LOG.info("got " + bytes.length + "bytes for writeInstallApp()");
+ write_real(bytes);
}
public void installApp(Uri uri, int appId) {
@@ -411,7 +445,7 @@ public class PebbleIoThread extends GBDeviceIoThread {
if (mPebbleProtocol.isFw3x) {
if (appId == 0) {
// only install metadata - not the binaries
- write(mPebbleProtocol.encodeInstallMetadata(app.getUUID(), app.getName(), mPBWReader.getAppVersion(), mPBWReader.getSdkVersion(), mPBWReader.getIconId()));
+ write(mPebbleProtocol.encodeInstallMetadata(app.getUUID(), app.getName(), mPBWReader.getAppVersion(), mPBWReader.getSdkVersion(), mPBWReader.getFlags(), mPBWReader.getIconId()));
GB.toast("To finish installation please start the watchapp on your Pebble", 5, GB.INFO);
} else {
// this came from an app fetch request, so do the real stuff
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java
index cf661913..4b38b3d0 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/pebble/PebbleProtocol.java
@@ -503,7 +503,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
return buf.array();
}
- public byte[] encodeInstallMetadata(UUID uuid, String appName, short appVersion, short sdkVersion, int iconId) {
+ public byte[] encodeInstallMetadata(UUID uuid, String appName, short appVersion, short sdkVersion, int flags, int iconId) {
// Calculate length first
final short BLOBDB_LENGTH = 23;
final short METADATA_LENGTH = 126;
@@ -534,6 +534,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
buf.putLong(uuid.getMostSignificantBits()); // watchapp uuid
buf.putLong(uuid.getLeastSignificantBits());
buf.order(ByteOrder.LITTLE_ENDIAN);
+ buf.putInt(flags);
buf.putInt(iconId);
buf.putShort(appVersion);
buf.putShort(sdkVersion);
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
index 7e6e3cee..6dfe88c3 100644
--- a/app/src/main/res/xml/preferences.xml
+++ b/app/src/main/res/xml/preferences.xml
@@ -77,6 +77,16 @@
android:key="pebble_force_untested"
android:title="@string/pref_title_pebble_forceuntested"
android:summary="@string/pref_summary_pebble_forceuntested" />
+
+