mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-28 12:56:49 +01:00
Initial (ugly) support for device discovery and pairing (#3)
This commit is contained in:
parent
e859ece7c6
commit
9df661bd96
@ -5,5 +5,5 @@ host = https://www.transifex.com
|
||||
file_filter = app/src/main/res/values-<lang>/strings.xml
|
||||
source_file = app/src/main/res/values/strings.xml
|
||||
source_lang = en_US
|
||||
type = ANDROID
|
||||
deviceType = ANDROID
|
||||
|
||||
|
@ -1,8 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="nodomain.freeyourgadget.gadgetbridge">
|
||||
package="nodomain.freeyourgadget.gadgetbridge" >
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="19"
|
||||
android:targetSdkVersion="21" />
|
||||
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
|
||||
<uses-permission android:name="android.permission.CALL_PHONE" />
|
||||
@ -10,45 +15,50 @@
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="com.fsck.k9.permission.READ_MESSAGES" />
|
||||
<uses-sdk android:targetSdkVersion="21" android:minSdkVersion="19"/>
|
||||
|
||||
<android:uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="18" />
|
||||
|
||||
<application
|
||||
android:name=".GBApplication"
|
||||
android:allowBackup="true"
|
||||
android:name="nodomain.freeyourgadget.gadgetbridge.GBApplication"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/GadgetbridgeTheme">
|
||||
android:theme="@style/GadgetbridgeTheme" >
|
||||
<activity
|
||||
android:name=".ControlCenter"
|
||||
android:label="@string/title_activity_controlcenter">
|
||||
android:label="@string/title_activity_controlcenter" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".SettingsActivity"
|
||||
android:label="@string/title_activity_settings">
|
||||
android:label="@string/title_activity_settings" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".ControlCenter" />
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".AppManagerActivity"
|
||||
android:label="@string/title_activity_appmanager">
|
||||
android:label="@string/title_activity_appmanager" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".ControlCenter" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".pebble.PebbleAppInstallerActivity"
|
||||
android:label="@string/title_activity_appinstaller">
|
||||
android:label="@string/title_activity_appinstaller" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".AppManagerActivity" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:host="*" />
|
||||
@ -61,16 +71,16 @@
|
||||
<service
|
||||
android:name=".externalevents.NotificationListener"
|
||||
android:label="@string/app_name"
|
||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
|
||||
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
|
||||
<intent-filter>
|
||||
<action android:name="android.service.notification.NotificationListenerService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name=".BluetoothCommunicationService"></service>
|
||||
<service android:name=".BluetoothCommunicationService" />
|
||||
|
||||
<receiver
|
||||
android:name=".externalevents.PhoneCallReceiver"
|
||||
android:enabled="false">
|
||||
android:enabled="false" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PHONE_STATE" />
|
||||
</intent-filter>
|
||||
@ -80,16 +90,17 @@
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".externalevents.SMSReceiver"
|
||||
android:enabled="false">
|
||||
android:enabled="false" >
|
||||
<intent-filter>
|
||||
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".externalevents.K9Receiver"
|
||||
android:enabled="false">
|
||||
android:enabled="false" >
|
||||
<intent-filter>
|
||||
<data android:scheme="email" />
|
||||
|
||||
<action android:name="com.fsck.k9.intent.action.EMAIL_RECEIVED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
@ -102,28 +113,28 @@
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".externalevents.MusicPlaybackReceiver"
|
||||
android:enabled="false">
|
||||
android:enabled="false" >
|
||||
<intent-filter>
|
||||
<action android:name="com.andrew.apollo.metachanged" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".BluetoothStateChangeReceiver"
|
||||
android:exported="false">
|
||||
android:exported="false" >
|
||||
<intent-filter>
|
||||
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".GBMusicControlReceiver"
|
||||
android:exported="false">
|
||||
android:exported="false" >
|
||||
<intent-filter>
|
||||
<action android:name="nodomain.freeyourgadget.gadgetbridge.musiccontrol" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".GBCallControlReceiver"
|
||||
android:exported="false">
|
||||
android:exported="false" >
|
||||
<intent-filter>
|
||||
<action android:name="nodomain.freeyourgadget.gadgetbridge.callcontrol" />
|
||||
</intent-filter>
|
||||
@ -131,11 +142,26 @@
|
||||
|
||||
<activity
|
||||
android:name=".DebugActivity"
|
||||
android:label="@string/title_activity_debug">
|
||||
android:label="@string/title_activity_debug" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".ControlCenter" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".discovery.DiscoveryActivity"
|
||||
android:label="@string/title_activity_discovery" >
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".ControlCenter" />
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".activities.AndroidPairingActivity"
|
||||
android:label="@string/title_activity_android_pairing" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".miband.MiBandPairingActivity"
|
||||
android:label="@string/title_activity_mi_band_pairing" >
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
@ -25,6 +25,12 @@ public abstract class AbstractBTDeviceSupport extends AbstractDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pair() {
|
||||
// Default implementation does no manual pairing, use the Android
|
||||
// pairing dialog instead.
|
||||
}
|
||||
|
||||
public synchronized GBDeviceProtocol getDeviceProtocol() {
|
||||
if (gbDeviceProtocol == null) {
|
||||
gbDeviceProtocol = createDeviceProtocol();
|
||||
|
@ -27,6 +27,8 @@ import nodomain.freeyourgadget.gadgetbridge.pebble.PebbleSupport;
|
||||
public class BluetoothCommunicationService extends Service {
|
||||
public static final String ACTION_START
|
||||
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.start";
|
||||
public static final String ACTION_PAIR
|
||||
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.pair";
|
||||
public static final String ACTION_CONNECT
|
||||
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.connect";
|
||||
public static final String ACTION_NOTIFICATION_GENERIC
|
||||
@ -49,8 +51,10 @@ public class BluetoothCommunicationService extends Service {
|
||||
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.deleteapp";
|
||||
public static final String ACTION_INSTALL_PEBBLEAPP
|
||||
= "nodomain.freeyourgadget.gadgetbride.bluetoothcommunicationservice.action.install_pebbbleapp";
|
||||
public static final String EXTRA_PERFORM_PAIR = "perform_pair";
|
||||
|
||||
private static final String TAG = "CommunicationService";
|
||||
public static final String EXTRA_DEVICE_ADDRESS = "device_address";
|
||||
private BluetoothAdapter mBtAdapter = null;
|
||||
private GBDeviceIoThread mGBDeviceIoThread = null;
|
||||
|
||||
@ -90,6 +94,7 @@ public class BluetoothCommunicationService extends Service {
|
||||
}
|
||||
|
||||
String action = intent.getAction();
|
||||
boolean pair = intent.getBooleanExtra(EXTRA_PERFORM_PAIR, false);
|
||||
|
||||
if (action == null) {
|
||||
Log.i(TAG, "no action");
|
||||
@ -128,7 +133,7 @@ public class BluetoothCommunicationService extends Service {
|
||||
} else if (!mBtAdapter.isEnabled()) {
|
||||
Toast.makeText(this, R.string.bluetooth_is_disabled_, Toast.LENGTH_SHORT).show();
|
||||
} else {
|
||||
String btDeviceAddress = intent.getStringExtra("device_address");
|
||||
String btDeviceAddress = intent.getStringExtra(EXTRA_DEVICE_ADDRESS);
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
sharedPrefs.edit().putString("last_device_address", btDeviceAddress).apply();
|
||||
|
||||
@ -140,15 +145,19 @@ public class BluetoothCommunicationService extends Service {
|
||||
try {
|
||||
BluetoothDevice btDevice = mBtAdapter.getRemoteDevice(btDeviceAddress);
|
||||
if (btDevice.getName() == null || btDevice.getName().equals("MI")) { //FIXME: workaround for Miband not being paired
|
||||
mGBDevice = new GBDevice(btDeviceAddress, "MI", GBDevice.Type.MIBAND);
|
||||
mGBDevice = new GBDevice(btDeviceAddress, "MI", DeviceType.MIBAND);
|
||||
mDeviceSupport = new MiBandSupport();
|
||||
} else if (btDevice.getName().indexOf("Pebble") == 0) {
|
||||
mGBDevice = new GBDevice(btDeviceAddress, btDevice.getName(), GBDevice.Type.PEBBLE);
|
||||
mGBDevice = new GBDevice(btDeviceAddress, btDevice.getName(), DeviceType.PEBBLE);
|
||||
mDeviceSupport = new PebbleSupport();
|
||||
}
|
||||
if (mDeviceSupport != null) {
|
||||
mDeviceSupport.initialize(mGBDevice, mBtAdapter, this);
|
||||
mDeviceSupport.connect();
|
||||
if (pair) {
|
||||
mDeviceSupport.pair();
|
||||
} else {
|
||||
mDeviceSupport.connect();
|
||||
}
|
||||
if (mDeviceSupport instanceof AbstractBTDeviceSupport) {
|
||||
mGBDeviceIoThread = ((AbstractBTDeviceSupport) mDeviceSupport).getDeviceIOThread();
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ public class BluetoothStateChangeReceiver extends BroadcastReceiver {
|
||||
if (deviceAddress != null) {
|
||||
Intent connectIntent = new Intent(context, BluetoothCommunicationService.class);
|
||||
connectIntent.setAction(BluetoothCommunicationService.ACTION_CONNECT);
|
||||
connectIntent.putExtra("device_address", deviceAddress);
|
||||
connectIntent.putExtra(BluetoothCommunicationService.EXTRA_DEVICE_ADDRESS, deviceAddress);
|
||||
context.startService(connectIntent);
|
||||
}
|
||||
} else if (intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1) == BluetoothAdapter.STATE_OFF) {
|
||||
|
@ -24,6 +24,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.GBDeviceAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.discovery.DiscoveryActivity;
|
||||
|
||||
public class ControlCenter extends Activity {
|
||||
|
||||
@ -83,7 +84,7 @@ public class ControlCenter extends Activity {
|
||||
} else {
|
||||
Intent startIntent = new Intent(ControlCenter.this, BluetoothCommunicationService.class);
|
||||
startIntent.setAction(BluetoothCommunicationService.ACTION_CONNECT);
|
||||
startIntent.putExtra("device_address", deviceList.get(position).getAddress());
|
||||
startIntent.putExtra(BluetoothCommunicationService.EXTRA_DEVICE_ADDRESS, deviceList.get(position).getAddress());
|
||||
startService(startIntent);
|
||||
}
|
||||
}
|
||||
@ -152,6 +153,11 @@ public class ControlCenter extends Activity {
|
||||
return true;
|
||||
case R.id.action_refresh:
|
||||
refreshPairedDevices();
|
||||
return true;
|
||||
case R.id.action_discover:
|
||||
Intent discoverIntent = new Intent(this, DiscoveryActivity.class);
|
||||
startActivity(discoverIntent);
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
@ -182,24 +188,24 @@ public class ControlCenter extends Activity {
|
||||
} else {
|
||||
Set<BluetoothDevice> pairedDevices = btAdapter.getBondedDevices();
|
||||
for (BluetoothDevice pairedDevice : pairedDevices) {
|
||||
GBDevice.Type deviceType;
|
||||
DeviceType deviceDeviceType;
|
||||
if (pairedDevice.getName().indexOf("Pebble") == 0) {
|
||||
deviceType = GBDevice.Type.PEBBLE;
|
||||
deviceDeviceType = DeviceType.PEBBLE;
|
||||
} else if (pairedDevice.getName().equals("MI")) {
|
||||
deviceType = GBDevice.Type.MIBAND;
|
||||
deviceDeviceType = DeviceType.MIBAND;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
GBDevice device = new GBDevice(pairedDevice.getAddress(), pairedDevice.getName(), deviceType);
|
||||
GBDevice device = new GBDevice(pairedDevice.getAddress(), pairedDevice.getName(), deviceDeviceType);
|
||||
if (!availableDevices.contains(device)) {
|
||||
availableDevices.add(device);
|
||||
}
|
||||
}
|
||||
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
String miAddr = sharedPrefs.getString("development_miaddr", null);
|
||||
String miAddr = sharedPrefs.getString(GB.PREF_DEVELOPMENT_MIBAND_ADDRESS, null);
|
||||
if (miAddr != null && miAddr.length() > 0) {
|
||||
GBDevice miDevice = new GBDevice(miAddr, "MI", GBDevice.Type.MIBAND);
|
||||
GBDevice miDevice = new GBDevice(miAddr, "MI", DeviceType.MIBAND);
|
||||
if (!availableDevices.contains(miDevice)) {
|
||||
availableDevices.add(miDevice);
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.discovery.DeviceCandidate;
|
||||
|
||||
public interface DeviceCoordinator {
|
||||
String EXTRA_DEVICE_MAC_ADDRESS = "nodomain.freeyourgadget.gadgetbridge.discovery.DeviceCandidate.EXTRA_MAC_ADDRESS";
|
||||
|
||||
public boolean supports(DeviceCandidate candidate);
|
||||
public boolean supports(GBDevice device);
|
||||
public DeviceType getDeviceType();
|
||||
|
||||
Class<? extends Activity> getPairingActivity();
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge;
|
||||
|
||||
import android.bluetooth.BluetoothClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.discovery.DeviceCandidate;
|
||||
import nodomain.freeyourgadget.gadgetbridge.miband.MiBandCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.pebble.PebbleCoordinator;
|
||||
|
||||
public class DeviceHelper {
|
||||
private static DeviceHelper instance = new DeviceHelper();
|
||||
|
||||
public static DeviceHelper getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
// lazily created
|
||||
private List<DeviceCoordinator> coordinators;
|
||||
// the current single coordinator (typically there's just one device connected
|
||||
private DeviceCoordinator coordinator;
|
||||
|
||||
public boolean isSupported(DeviceCandidate candidate) {
|
||||
if (coordinator != null && coordinator.supports(candidate)) {
|
||||
return true;
|
||||
}
|
||||
for (DeviceCoordinator coordinator : getAllCoordinators()) {
|
||||
if (coordinator.supports(candidate)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public DeviceCoordinator getCoordinator(DeviceCandidate device) {
|
||||
if (coordinator != null && coordinator.supports(device)) {
|
||||
return coordinator;
|
||||
}
|
||||
synchronized (this) {
|
||||
for (DeviceCoordinator coord : getAllCoordinators()) {
|
||||
if (coord.supports(device)) {
|
||||
coordinator = coord;
|
||||
return coordinator;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new UnknownDeviceCoordinator();
|
||||
}
|
||||
|
||||
public DeviceCoordinator getCoordinator(GBDevice device) {
|
||||
if (coordinator != null && coordinator.supports(device)) {
|
||||
return coordinator;
|
||||
}
|
||||
synchronized (this) {
|
||||
for (DeviceCoordinator coord : getAllCoordinators()) {
|
||||
if (coord.supports(device)) {
|
||||
coordinator = coord;
|
||||
return coordinator;
|
||||
}
|
||||
}
|
||||
}
|
||||
return new UnknownDeviceCoordinator();
|
||||
}
|
||||
|
||||
public synchronized List<DeviceCoordinator> getAllCoordinators() {
|
||||
if (coordinators == null) {
|
||||
coordinators = createCoordinators();
|
||||
}
|
||||
return coordinators;
|
||||
}
|
||||
|
||||
private List<DeviceCoordinator> createCoordinators() {
|
||||
List<DeviceCoordinator> result = new ArrayList<>(2);
|
||||
result.add(new MiBandCoordinator());
|
||||
result.add(new PebbleCoordinator());
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
@ -30,4 +30,6 @@ public interface DeviceSupport extends EventHandler {
|
||||
public Context getContext();
|
||||
|
||||
public boolean useAutoConnect();
|
||||
|
||||
public void pair();
|
||||
}
|
||||
|
@ -0,0 +1,7 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge;
|
||||
|
||||
public enum DeviceType {
|
||||
UNKNOWN,
|
||||
PEBBLE,
|
||||
MIBAND
|
||||
}
|
@ -20,6 +20,8 @@ public class GB {
|
||||
public static final int NOTIFICATION_ID = 1;
|
||||
private static final String TAG = "GB";
|
||||
|
||||
public static final String PREF_DEVELOPMENT_MIBAND_ADDRESS = "development_miaddr";
|
||||
|
||||
public static Notification createNotification(String text, Context context) {
|
||||
Intent notificationIntent = new Intent(context, ControlCenter.class);
|
||||
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
@ -81,4 +83,8 @@ public class GB {
|
||||
}
|
||||
return new String(hexChars);
|
||||
}
|
||||
|
||||
public static String formatRssi(short rssi) {
|
||||
return String.valueOf(rssi);
|
||||
}
|
||||
}
|
||||
|
@ -22,31 +22,35 @@ public class GBDevice implements Parcelable {
|
||||
}
|
||||
};
|
||||
private static final String TAG = GBDevice.class.getSimpleName();
|
||||
public static final short RSSI_UNKNOWN = 0;
|
||||
public static final String EXTRA_DEVICE = "device";
|
||||
private final String mName;
|
||||
private final String mAddress;
|
||||
private final Type mType;
|
||||
private final DeviceType mDeviceType;
|
||||
private String mFirmwareVersion = null;
|
||||
private String mHardwareVersion = null;
|
||||
private State mState = State.NOT_CONNECTED;
|
||||
private short mBatteryLevel = 50; // unknown
|
||||
private String mBatteryState;
|
||||
private short mRssi = RSSI_UNKNOWN;
|
||||
|
||||
public GBDevice(String address, String name, Type type) {
|
||||
public GBDevice(String address, String name, DeviceType deviceType) {
|
||||
mAddress = address;
|
||||
mName = name;
|
||||
mType = type;
|
||||
mDeviceType = deviceType;
|
||||
validate();
|
||||
}
|
||||
|
||||
private GBDevice(Parcel in) {
|
||||
mName = in.readString();
|
||||
mAddress = in.readString();
|
||||
mType = Type.values()[in.readInt()];
|
||||
mDeviceType = DeviceType.values()[in.readInt()];
|
||||
mFirmwareVersion = in.readString();
|
||||
mHardwareVersion = in.readString();
|
||||
mState = State.values()[in.readInt()];
|
||||
mBatteryLevel = (short) in.readInt();
|
||||
mBatteryState = in.readString();
|
||||
mRssi = (short) in.readInt();
|
||||
validate();
|
||||
}
|
||||
|
||||
@ -54,12 +58,13 @@ public class GBDevice implements Parcelable {
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(mName);
|
||||
dest.writeString(mAddress);
|
||||
dest.writeInt(mType.ordinal());
|
||||
dest.writeInt(mDeviceType.ordinal());
|
||||
dest.writeString(mFirmwareVersion);
|
||||
dest.writeString(mHardwareVersion);
|
||||
dest.writeInt(mState.ordinal());
|
||||
dest.writeInt(mBatteryLevel);
|
||||
dest.writeString(mBatteryState);
|
||||
dest.writeInt(mRssi);
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
@ -137,14 +142,30 @@ public class GBDevice implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return mType;
|
||||
public DeviceType getType() {
|
||||
return mDeviceType;
|
||||
}
|
||||
|
||||
public void setRssi(short rssi) {
|
||||
if (rssi < 0) {
|
||||
Log.w(TAG, "illegal rssi value " + rssi + ", setting to RSSI_UNKNOWN");
|
||||
mRssi = RSSI_UNKNOWN;
|
||||
} else {
|
||||
mRssi = rssi;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device specific signal strength value, or #RSSI_UNKNOWN
|
||||
*/
|
||||
public short getRssi() {
|
||||
return mRssi;
|
||||
}
|
||||
|
||||
// TODO: this doesn't really belong here
|
||||
public void sendDeviceUpdateIntent(Context context) {
|
||||
Intent deviceUpdateIntent = new Intent(ACTION_DEVICE_CHANGED);
|
||||
deviceUpdateIntent.putExtra("device", this);
|
||||
deviceUpdateIntent.putExtra(EXTRA_DEVICE, this);
|
||||
LocalBroadcastManager.getInstance(context).sendBroadcast(deviceUpdateIntent);
|
||||
}
|
||||
|
||||
@ -208,9 +229,4 @@ public class GBDevice implements Parcelable {
|
||||
INITIALIZED
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
UNKNOWN,
|
||||
PEBBLE,
|
||||
MIBAND
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ public class SettingsActivity extends PreferenceActivity {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
final Preference developmentMiaddr = findPreference("development_miaddr");
|
||||
final Preference developmentMiaddr = findPreference(GB.PREF_DEVELOPMENT_MIBAND_ADDRESS);
|
||||
bindPreferenceSummaryToValue(developmentMiaddr);
|
||||
|
||||
developmentMiaddr.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
|
@ -0,0 +1,27 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.discovery.DeviceCandidate;
|
||||
|
||||
public class UnknownDeviceCoordinator implements DeviceCoordinator {
|
||||
@Override
|
||||
public boolean supports(DeviceCandidate candidate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(GBDevice device) {
|
||||
return getDeviceType().equals(device.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceType getDeviceType() {
|
||||
return DeviceType.UNKNOWN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Activity> getPairingActivity() {
|
||||
return ControlCenter.class;
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
public class AndroidPairingActivity extends Activity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_android_pairing);
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.discovery.DeviceCandidate;
|
||||
|
||||
public class DeviceCandidateAdapter extends ArrayAdapter<DeviceCandidate> {
|
||||
|
||||
private final Context context;
|
||||
private final List<DeviceCandidate> deviceCandidates;
|
||||
|
||||
public DeviceCandidateAdapter(Context context, List<DeviceCandidate> deviceCandidates) {
|
||||
super(context, 0, deviceCandidates);
|
||||
|
||||
this.context = context;
|
||||
this.deviceCandidates = deviceCandidates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup parent) {
|
||||
DeviceCandidate device = getItem(position);
|
||||
|
||||
if (view == null) {
|
||||
LayoutInflater inflater = (LayoutInflater) context
|
||||
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
view = inflater.inflate(R.layout.device_candidate_item, parent, false);
|
||||
}
|
||||
ImageView deviceImageView = (ImageView) view.findViewById(R.id.device_candidate_image);
|
||||
TextView deviceNameLabel = (TextView) view.findViewById(R.id.device_candidate_name);
|
||||
TextView deviceAddressLabel = (TextView) view.findViewById(R.id.device_candidate_address);
|
||||
|
||||
String name = formatDeviceCandidate(device);
|
||||
deviceNameLabel.setText(name);
|
||||
deviceAddressLabel.setText(device.getMacAddress());
|
||||
|
||||
switch (device.getDeviceType()) {
|
||||
case PEBBLE:
|
||||
deviceImageView.setImageResource(R.drawable.ic_device_pebble);
|
||||
break;
|
||||
case MIBAND:
|
||||
deviceImageView.setImageResource(R.drawable.ic_device_miband);
|
||||
break;
|
||||
default:
|
||||
deviceImageView.setImageResource(R.drawable.ic_launcher);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private String formatDeviceCandidate(DeviceCandidate device) {
|
||||
if (device.getRssi() > GBDevice.RSSI_UNKNOWN) {
|
||||
return context.getString(R.string.device_with_rssi, device.getName(), GB.formatRssi(device.getRssi()));
|
||||
}
|
||||
return device.getName();
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ import nodomain.freeyourgadget.gadgetbridge.AbstractDeviceSupport;
|
||||
* @see BtLEQueue
|
||||
*/
|
||||
public abstract class AbstractBTLEDeviceSupport extends AbstractDeviceSupport implements GattCallback {
|
||||
private static final String TAG = "AbstractBTLEDeviceSupport";
|
||||
private static final String TAG = "AbstractBTLEDeviceSupp";
|
||||
|
||||
private BtLEQueue mQueue;
|
||||
private HashMap<UUID, BluetoothGattCharacteristic> mAvailableCharacteristics;
|
||||
|
@ -0,0 +1,67 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.discovery;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
|
||||
/**
|
||||
*/
|
||||
public class DeviceCandidate implements Parcelable {
|
||||
private BluetoothDevice device;
|
||||
private short rssi;
|
||||
private DeviceType deviceType = DeviceType.UNKNOWN;
|
||||
|
||||
public DeviceCandidate(BluetoothDevice device, short rssi) {
|
||||
this.device = device;
|
||||
this.rssi = rssi;
|
||||
}
|
||||
|
||||
private DeviceCandidate(Parcel in) {
|
||||
device = in.readParcelable(getClass().getClassLoader());
|
||||
rssi = (short) in.readInt();
|
||||
deviceType = DeviceType.valueOf(in.readString());
|
||||
|
||||
if (device == null || deviceType == null) {
|
||||
throw new IllegalStateException("Unable to read state from Parcel");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(device, 0);
|
||||
dest.writeInt(rssi);
|
||||
dest.writeString(deviceType.name());
|
||||
}
|
||||
|
||||
public DeviceType getDeviceType() {
|
||||
return deviceType;
|
||||
}
|
||||
|
||||
public String getMacAddress() {
|
||||
return device != null ? device.getAddress() : GBApplication.getContext().getString(R.string._unknown_);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
String name = null;
|
||||
if (device != null) {
|
||||
name = device.getName();
|
||||
}
|
||||
if (name == null || name.length() == 0) {
|
||||
name = GBApplication.getContext().getString(R.string._unknown_);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public short getRssi() {
|
||||
return rssi;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,227 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.discovery;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.bluetooth.BluetoothAdapter;
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.bluetooth.BluetoothManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.DeviceCandidateAdapter;
|
||||
|
||||
public class DiscoveryActivity extends Activity implements AdapterView.OnItemClickListener {
|
||||
private static final String TAG = "DiscoveryAct";
|
||||
|
||||
private BroadcastReceiver bluetoothReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
switch (intent.getAction()) {
|
||||
case BluetoothAdapter.ACTION_DISCOVERY_STARTED:
|
||||
discoveryStarted();
|
||||
break;
|
||||
case BluetoothAdapter.ACTION_DISCOVERY_FINISHED:
|
||||
discoveryFinished();
|
||||
break;
|
||||
case BluetoothAdapter.ACTION_STATE_CHANGED:
|
||||
int oldState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.STATE_OFF);
|
||||
int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
|
||||
bluetoothStateChanged(oldState, newState);
|
||||
break;
|
||||
case BluetoothDevice.ACTION_FOUND:
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void bluetoothStateChanged(int oldState, int newState) {
|
||||
discoveryFinished();
|
||||
startButton.setEnabled(newState == BluetoothAdapter.STATE_ON);
|
||||
}
|
||||
|
||||
private void discoveryFinished() {
|
||||
isScanning = false;
|
||||
progressView.setVisibility(View.GONE);
|
||||
startButton.setText(getString(R.string.discovery_start_scanning));
|
||||
}
|
||||
|
||||
private void discoveryStarted() {
|
||||
isScanning = true;
|
||||
progressView.setVisibility(View.VISIBLE);
|
||||
startButton.setText(getString(R.string.discovery_stop_scanning));
|
||||
}
|
||||
|
||||
private ProgressBar progressView;
|
||||
private BluetoothAdapter adapter;
|
||||
private ArrayList<DeviceCandidate> deviceCandidates = new ArrayList<>();
|
||||
private ListView deviceCandidatesView;
|
||||
private DeviceCandidateAdapter cadidateListAdapter;
|
||||
private Button startButton;
|
||||
private boolean isScanning;
|
||||
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
|
||||
@Override
|
||||
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
|
||||
DeviceCandidate candidate = new DeviceCandidate(device, (short) rssi);
|
||||
if (DeviceHelper.getInstance().isSupported(candidate)) {
|
||||
deviceCandidates.add(candidate);
|
||||
cadidateListAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_discovery);
|
||||
startButton = (Button) findViewById(R.id.discovery_start);
|
||||
startButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onStartButtonClick(startButton);
|
||||
}
|
||||
});
|
||||
|
||||
progressView = (ProgressBar) findViewById(R.id.discovery_progressbar);
|
||||
progressView.setProgress(0);
|
||||
progressView.setIndeterminate(true);
|
||||
progressView.setVisibility(View.GONE);
|
||||
deviceCandidatesView = (ListView) findViewById(R.id.discovery_deviceCandidatesView);
|
||||
|
||||
cadidateListAdapter = new DeviceCandidateAdapter(this, deviceCandidates);
|
||||
deviceCandidatesView.setAdapter(cadidateListAdapter);
|
||||
deviceCandidatesView.setOnItemClickListener(this);
|
||||
|
||||
IntentFilter bluetoothIntents = new IntentFilter();
|
||||
bluetoothIntents.addAction(BluetoothDevice.ACTION_FOUND);
|
||||
bluetoothIntents.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
|
||||
bluetoothIntents.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
|
||||
bluetoothIntents.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
|
||||
|
||||
registerReceiver(bluetoothReceiver, bluetoothIntents);
|
||||
|
||||
startDiscovery();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putParcelableArrayList("deviceCandidates", deviceCandidates);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
ArrayList<Parcelable> restoredCandidates = savedInstanceState.getParcelableArrayList("deviceCandidates");
|
||||
if (restoredCandidates != null) {
|
||||
deviceCandidates.clear();
|
||||
for (Parcelable p : restoredCandidates) {
|
||||
deviceCandidates.add((DeviceCandidate) p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onStartButtonClick(View button) {
|
||||
Log.d(TAG, "Start Button clicked");
|
||||
if (isScanning) {
|
||||
stopDiscovery();
|
||||
} else {
|
||||
startDiscovery();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
unregisterReceiver(bluetoothReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre: bluetooth is available, enabled and scanning is off
|
||||
*/
|
||||
private void startDiscovery() {
|
||||
Log.i(TAG, "Starting discovery...");
|
||||
discoveryStarted(); // just to make sure
|
||||
if (ensureBluetoothReady()) {
|
||||
startBLEDiscovery();
|
||||
} else {
|
||||
discoveryFinished();
|
||||
Toast.makeText(this, "Enable Bluetooth to discover devices.", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
private void stopDiscovery() {
|
||||
if (isScanning) {
|
||||
adapter.stopLeScan(leScanCallback);
|
||||
// unfortunately, we never get a call back when stopping the scan, so
|
||||
// we do it manually:
|
||||
discoveryFinished();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ensureBluetoothReady() {
|
||||
boolean available = checkBluetoothAvailable();
|
||||
startButton.setEnabled(available);
|
||||
if (available) {
|
||||
adapter.cancelDiscovery();
|
||||
// must not return the result of cancelDiscovery()
|
||||
// appears to return false when currently not scanning
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkBluetoothAvailable() {
|
||||
BluetoothManager bluetoothService = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
|
||||
if (bluetoothService == null) {
|
||||
Log.w(TAG, "No bluetooth available");
|
||||
this.adapter = null;
|
||||
return false;
|
||||
}
|
||||
BluetoothAdapter adapter = bluetoothService.getAdapter();
|
||||
if (!adapter.isEnabled()) {
|
||||
Log.w(TAG, "Bluetooth not enabled");
|
||||
this.adapter = null;
|
||||
return false;
|
||||
}
|
||||
this.adapter = adapter;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void startBLEDiscovery() {
|
||||
adapter.startLeScan(leScanCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
DeviceCandidate deviceCandidate = deviceCandidates.get(position);
|
||||
if (deviceCandidate == null) {
|
||||
Log.e(TAG, "Device candidate clicked, but item not found");
|
||||
return;
|
||||
}
|
||||
|
||||
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(deviceCandidate);
|
||||
Intent intent = new Intent(this, coordinator.getPairingActivity());
|
||||
intent.putExtra(DeviceCoordinator.EXTRA_DEVICE_MAC_ADDRESS, deviceCandidate.getMacAddress());
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.miband;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.discovery.DeviceCandidate;
|
||||
|
||||
public class MiBandCoordinator implements DeviceCoordinator {
|
||||
@Override
|
||||
public boolean supports(DeviceCandidate candidate) {
|
||||
return candidate.getMacAddress().toUpperCase().startsWith(MiBandService.MAC_ADDRESS_FILTER);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(GBDevice device) {
|
||||
return getDeviceType().equals(device.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceType getDeviceType() {
|
||||
return DeviceType.MIBAND;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Activity> getPairingActivity() {
|
||||
return MiBandPairingActivity.class;
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.miband;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.BluetoothCommunicationService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.ControlCenter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.discovery.DiscoveryActivity;
|
||||
|
||||
public class MiBandPairingActivity extends Activity {
|
||||
|
||||
private TextView message;
|
||||
private boolean isPairing;
|
||||
private String macAddress;
|
||||
private BroadcastReceiver mPairingReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (GBDevice.ACTION_DEVICE_CHANGED.equals(intent.getAction())) {
|
||||
GBDevice device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
if (macAddress.equals(device.getAddress()) && device.isInitialized()) {
|
||||
pairingFinished(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_mi_band_pairing);
|
||||
|
||||
message = (TextView) findViewById(R.id.miband_pair_message);
|
||||
Intent intent = getIntent();
|
||||
macAddress = intent.getStringExtra(DeviceCoordinator.EXTRA_DEVICE_MAC_ADDRESS);
|
||||
if (macAddress == null) {
|
||||
Toast.makeText(this, getString(R.string.message_cannot_pair_no_mac), Toast.LENGTH_SHORT).show();
|
||||
startActivity(new Intent(this, DiscoveryActivity.class));
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
startPairing();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mPairingReceiver);
|
||||
if (isPairing) {
|
||||
stopPairing();
|
||||
}
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
private void startPairing() {
|
||||
isPairing = true;
|
||||
message.setText(getString(R.string.miband_pairing, macAddress));
|
||||
IntentFilter filter = new IntentFilter(GBDevice.ACTION_DEVICE_CHANGED);
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mPairingReceiver, filter);
|
||||
|
||||
Intent serviceIntent = new Intent(this, BluetoothCommunicationService.class);
|
||||
serviceIntent.setAction(BluetoothCommunicationService.ACTION_START);
|
||||
startService(serviceIntent);
|
||||
|
||||
serviceIntent = new Intent(this, BluetoothCommunicationService.class);
|
||||
serviceIntent.setAction(BluetoothCommunicationService.ACTION_CONNECT);
|
||||
serviceIntent.putExtra(BluetoothCommunicationService.EXTRA_PERFORM_PAIR, true);
|
||||
serviceIntent.putExtra(BluetoothCommunicationService.EXTRA_DEVICE_ADDRESS, macAddress);
|
||||
startService(serviceIntent);
|
||||
}
|
||||
|
||||
private void pairingFinished(boolean pairedSuccessfully) {
|
||||
isPairing = false;
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mPairingReceiver);
|
||||
|
||||
if (pairedSuccessfully) {
|
||||
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
sharedPrefs.edit().putString(GB.PREF_DEVELOPMENT_MIBAND_ADDRESS, macAddress).apply();
|
||||
}
|
||||
|
||||
Intent intent = new Intent(this, ControlCenter.class);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void stopPairing() {
|
||||
// TODO
|
||||
isPairing = false;
|
||||
}
|
||||
}
|
@ -250,7 +250,7 @@ public class MiBandService {
|
||||
MIBAND_DEBUG.put(UUID.fromString("00002a48-0000-1000-8000-00805f9b34fb"), "Supported Unread Alert Category");
|
||||
MIBAND_DEBUG.put(UUID.fromString("00002a23-0000-1000-8000-00805f9b34fb"), "System ID");
|
||||
MIBAND_DEBUG.put(UUID.fromString("00002a1c-0000-1000-8000-00805f9b34fb"), "Temperature Measurement");
|
||||
MIBAND_DEBUG.put(UUID.fromString("00002a1d-0000-1000-8000-00805f9b34fb"), "Temperature Type");
|
||||
MIBAND_DEBUG.put(UUID.fromString("00002a1d-0000-1000-8000-00805f9b34fb"), "Temperature DeviceType");
|
||||
MIBAND_DEBUG.put(UUID.fromString("00002a12-0000-1000-8000-00805f9b34fb"), "Time Accuracy");
|
||||
MIBAND_DEBUG.put(UUID.fromString("00002a13-0000-1000-8000-00805f9b34fb"), "Time Source");
|
||||
MIBAND_DEBUG.put(UUID.fromString("00002a16-0000-1000-8000-00805f9b34fb"), "Time Update Control Point");
|
||||
|
@ -32,6 +32,15 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pair() {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
if (connect()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] getDefaultNotification() {
|
||||
final int vibrateTimes = 1;
|
||||
final long vibrateDuration = 250l;
|
||||
|
@ -0,0 +1,31 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.pebble;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.ControlCenter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.discovery.DeviceCandidate;
|
||||
|
||||
public class PebbleCoordinator implements DeviceCoordinator {
|
||||
@Override
|
||||
public boolean supports(DeviceCandidate candidate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(GBDevice device) {
|
||||
return getDeviceType().equals(device.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceType getDeviceType() {
|
||||
return DeviceType.PEBBLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Activity> getPairingActivity() {
|
||||
return ControlCenter.class;
|
||||
}
|
||||
}
|
12
app/src/main/res/layout/activity_android_pairing.xml
Normal file
12
app/src/main/res/layout/activity_android_pairing.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.AndroidPairingActivity">
|
||||
|
||||
<TextView android:text="@string/android_pairing_hint" android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</RelativeLayout>
|
36
app/src/main/res/layout/activity_discovery.xml
Normal file
36
app/src/main/res/layout/activity_discovery.xml
Normal file
@ -0,0 +1,36 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.discovery.DiscoveryActivity">
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/discovery_start_scanning"
|
||||
android:id="@+id/discovery_start"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/discovery_progressbar"
|
||||
android:indeterminate="true"
|
||||
android:indeterminateOnly="true"
|
||||
android:visibility="gone"
|
||||
android:layout_below="@+id/discovery_start"
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
<ListView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/discovery_deviceCandidatesView"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_toEndOf="@+id/discovery_progressbar"
|
||||
android:layout_below="@+id/discovery_progressbar"
|
||||
android:layout_alignParentStart="true" />
|
||||
|
||||
</RelativeLayout>
|
29
app/src/main/res/layout/activity_mi_band_pairing.xml
Normal file
29
app/src/main/res/layout/activity_mi_band_pairing.xml
Normal file
@ -0,0 +1,29 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.miband.MiBandPairingActivity">
|
||||
|
||||
<TextView android:text="@string/miband_pairing" android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/miband_pair_message" />
|
||||
|
||||
<ProgressBar
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_marginTop="25dp"
|
||||
android:layout_below="@+id/miband_pair_message"
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="When your Mi Band vibrates and blinks, tap it a few times in a row."
|
||||
android:id="@+id/miband_pair_hint"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentStart="true" />
|
||||
|
||||
</RelativeLayout>
|
37
app/src/main/res/layout/device_candidate_item.xml
Normal file
37
app/src/main/res/layout/device_candidate_item.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/activatedBackgroundIndicator"
|
||||
android:padding="8dp" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/device_candidate_image"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_alignParentLeft="true" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_toRightOf="@+id/device_candidate_image"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="8dp" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_candidate_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollHorizontally="false"
|
||||
android:textStyle="bold"
|
||||
android:singleLine="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/device_candidate_address"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textStyle="normal" />
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
@ -2,6 +2,8 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.ControlCenter">
|
||||
<item android:id="@+id/action_discover" android:title="@string/action_discover"
|
||||
android:orderInCategory="100" app:showAsAction="never" />
|
||||
<item android:id="@+id/action_refresh" android:title="@string/action_refresh"
|
||||
android:orderInCategory="100" app:showAsAction="never" />
|
||||
<item android:id="@+id/action_settings" android:title="@string/action_settings"
|
||||
|
@ -39,7 +39,7 @@
|
||||
<string name="never">never</string>
|
||||
|
||||
<string name="pref_header_development">Developer Options</string>
|
||||
<string name="pref_title_development_miaddr">Miband address</string>
|
||||
<string name="pref_title_development_miaddr">Mi Band address</string>
|
||||
|
||||
|
||||
<string name="not_connected">not connected</string>
|
||||
@ -70,4 +70,15 @@
|
||||
<string name="n_a">N/A</string>
|
||||
<string name="initialized">initialized</string>
|
||||
<string name="appversion_by_creator">%1$s by %2$s</string>
|
||||
<string name="title_activity_discovery">Device Discovery</string>
|
||||
|
||||
<string name="discovery_stop_scanning">Stop Scanning</string>
|
||||
<string name="discovery_start_scanning">Start Discovery</string>
|
||||
<string name="action_discover">Discover Device</string>
|
||||
<string name="device_with_rssi">%1$s (%2$s)</string>
|
||||
<string name="title_activity_android_pairing">Pair Device</string>
|
||||
<string name="android_pairing_hint">Use the Android Bluetooth Pairing dialog to pair the device.</string>
|
||||
<string name="title_activity_mi_band_pairing">Pair your Mi Band</string>
|
||||
<string name="miband_pairing">Pairing with %s…</string>
|
||||
<string name="message_cannot_pair_no_mac">No mac address passed, cannot pair.</string>
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user