2015-04-14 01:24:03 +02:00
|
|
|
package nodomain.freeyourgadget.gadgetbridge.miband;
|
|
|
|
|
2015-05-01 01:49:43 +02:00
|
|
|
import android.bluetooth.BluetoothGatt;
|
|
|
|
import android.bluetooth.BluetoothGattCharacteristic;
|
|
|
|
import android.util.Log;
|
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
import java.io.IOException;
|
2015-04-23 14:11:57 +02:00
|
|
|
import java.util.Calendar;
|
2015-04-26 00:53:48 +02:00
|
|
|
import java.util.UUID;
|
2015-04-19 02:37:29 +02:00
|
|
|
|
2015-04-14 01:24:03 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.GBCommand;
|
2015-04-19 15:11:50 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.GBDevice.State;
|
2015-04-19 02:37:29 +02:00
|
|
|
import nodomain.freeyourgadget.gadgetbridge.btle.AbstractBTLEDeviceSupport;
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.btle.TransactionBuilder;
|
2015-04-14 01:24:03 +02:00
|
|
|
|
|
|
|
public class MiBandSupport extends AbstractBTLEDeviceSupport {
|
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
private static final String TAG = MiBandSupport.class.getSimpleName();
|
2015-04-14 10:29:09 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
public MiBandSupport() {
|
|
|
|
addSupportedService(MiBandService.UUID_SERVICE_MIBAND_SERVICE);
|
2015-04-14 02:03:14 +02:00
|
|
|
}
|
|
|
|
|
2015-04-14 01:24:03 +02:00
|
|
|
@Override
|
2015-04-19 02:37:29 +02:00
|
|
|
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
|
2015-04-27 21:43:57 +02:00
|
|
|
pair(builder).sendUserInfo(builder).setCurrentTime(builder);
|
2015-04-19 02:37:29 +02:00
|
|
|
return builder;
|
2015-04-14 01:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2015-04-19 02:37:29 +02:00
|
|
|
public boolean useAutoConnect() {
|
|
|
|
return true;
|
|
|
|
}
|
2015-04-19 11:28:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
private byte[] getDefaultNotification() {
|
|
|
|
final int vibrateTimes = 1;
|
|
|
|
final long vibrateDuration = 250l;
|
|
|
|
final int flashTimes = 1;
|
|
|
|
final int flashColour = 0xFFFFFFFF;
|
|
|
|
final int originalColour = 0xFFFFFFFF;
|
|
|
|
final long flashDuration = 250l;
|
|
|
|
|
|
|
|
return getNotification(vibrateDuration, vibrateTimes, flashTimes, flashColour, originalColour, flashDuration);
|
|
|
|
}
|
2015-04-14 01:24:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
private void sendDefaultNotification(TransactionBuilder builder) {
|
|
|
|
BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT);
|
|
|
|
Log.i(TAG, "Sending notification to MiBand: " + characteristic);
|
|
|
|
builder.write(characteristic, getDefaultNotification()).queue(getQueue());
|
|
|
|
}
|
|
|
|
|
|
|
|
private byte[] getNotification(long vibrateDuration, int vibrateTimes, int flashTimes, int flashColour, int originalColour, long flashDuration) {
|
2015-04-19 11:28:03 +02:00
|
|
|
byte[] vibrate = new byte[]{(byte) 8, (byte) 1};
|
2015-04-19 02:37:29 +02:00
|
|
|
byte r = 6;
|
|
|
|
byte g = 0;
|
|
|
|
byte b = 6;
|
|
|
|
boolean display = true;
|
|
|
|
// byte[] flashColor = new byte[]{ 14, r, g, b, display ? (byte) 1 : (byte) 0 };
|
|
|
|
return vibrate;
|
|
|
|
}
|
|
|
|
|
|
|
|
private UserInfo getUserInfo() {
|
|
|
|
// SharedPreferences mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext.getApplicationContext());
|
|
|
|
// UserInfo mInfo = new UserInfo(
|
|
|
|
// mSharedPreferences.getString(MiBandConstants.PREFERENCE_MAC_ADDRESS, ""),
|
|
|
|
// "1550050550",
|
|
|
|
// (mSharedPreferences.getString(MiBandConstants.PREFERENCE_GENDER, "Male") == "Male") ? 1 : 0,
|
|
|
|
// Integer.parseInt(mSharedPreferences.getString(MiBandConstants.PREFERENCE_AGE, "25")),
|
|
|
|
// Integer.parseInt(mSharedPreferences.getString(MiBandConstants.PREFERENCE_HEIGHT, "175")),
|
|
|
|
// Integer.parseInt(mSharedPreferences.getString(MiBandConstants.PREFERENCE_WEIGHT, "60")),
|
|
|
|
// 0
|
|
|
|
// );
|
|
|
|
return UserInfo.getDefault(getDevice().getAddress());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Part of device initialization process. Do not call manually.
|
2015-04-19 11:28:03 +02:00
|
|
|
*
|
2015-04-19 02:37:29 +02:00
|
|
|
* @param builder
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
private MiBandSupport sendUserInfo(TransactionBuilder builder) {
|
|
|
|
Log.d(TAG, "Writing User Info!");
|
|
|
|
BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_USER_INFO);
|
|
|
|
builder.write(characteristic, getUserInfo().getData());
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Part of device initialization process. Do not call manually.
|
2015-04-19 11:28:03 +02:00
|
|
|
*
|
2015-04-19 02:37:29 +02:00
|
|
|
* @param builder
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
private MiBandSupport pair(TransactionBuilder transaction) {
|
|
|
|
Log.i(TAG, "Attempting to pair MI device...");
|
|
|
|
BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_PAIR);
|
|
|
|
if (characteristic != null) {
|
|
|
|
transaction.write(characteristic, new byte[]{2});
|
|
|
|
} else {
|
|
|
|
Log.i(TAG, "Unable to pair MI device -- characteristic not available");
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void performDefaultNotification(String task) {
|
|
|
|
try {
|
|
|
|
TransactionBuilder builder = performInitialized(task);
|
|
|
|
sendDefaultNotification(builder);
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Log.e(TAG, "Unable to send notification to MI device", ex);
|
|
|
|
}
|
2015-04-14 01:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2015-04-19 02:37:29 +02:00
|
|
|
public void onSMS(String from, String body) {
|
|
|
|
performDefaultNotification("sms received");
|
|
|
|
}
|
2015-04-14 01:24:03 +02:00
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
@Override
|
|
|
|
public void onEmail(String from, String subject, String body) {
|
|
|
|
performDefaultNotification("email received");
|
2015-04-14 01:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSetTime(long ts) {
|
2015-04-27 21:43:57 +02:00
|
|
|
try {
|
|
|
|
TransactionBuilder builder = performInitialized("Set date and time");
|
|
|
|
setCurrentTime(builder);
|
|
|
|
builder.queue(getQueue());
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Log.e(TAG, "Unable to set time on MI device", ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sets the current time to the Mi device using the given builder.
|
2015-05-01 01:49:43 +02:00
|
|
|
*
|
2015-04-27 21:43:57 +02:00
|
|
|
* @param builder
|
|
|
|
*/
|
|
|
|
private MiBandSupport setCurrentTime(TransactionBuilder builder) {
|
2015-04-26 00:53:48 +02:00
|
|
|
Calendar now = Calendar.getInstance();
|
|
|
|
byte[] time = new byte[]{
|
|
|
|
(byte) (now.get(Calendar.YEAR) - 2000),
|
|
|
|
(byte) now.get(Calendar.MONTH),
|
|
|
|
(byte) now.get(Calendar.DATE),
|
|
|
|
(byte) now.get(Calendar.HOUR_OF_DAY),
|
|
|
|
(byte) now.get(Calendar.MINUTE),
|
|
|
|
(byte) now.get(Calendar.SECOND),
|
|
|
|
(byte) 0x0f,
|
|
|
|
(byte) 0x0f,
|
|
|
|
(byte) 0x0f,
|
|
|
|
(byte) 0x0f,
|
|
|
|
(byte) 0x0f,
|
|
|
|
(byte) 0x0f
|
|
|
|
};
|
2015-04-27 21:43:57 +02:00
|
|
|
BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_DATE_TIME);
|
|
|
|
if (characteristic != null) {
|
|
|
|
builder.write(characteristic, time);
|
|
|
|
} else {
|
|
|
|
Log.i(TAG, "Unable to set time -- characteristic not available");
|
2015-04-23 14:11:57 +02:00
|
|
|
}
|
2015-04-27 21:43:57 +02:00
|
|
|
return this;
|
2015-04-14 01:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSetCallState(String number, String name, GBCommand command) {
|
2015-04-19 15:15:53 +02:00
|
|
|
if (GBCommand.CALL_INCOMING.equals(command)) {
|
|
|
|
performDefaultNotification("incoming call");
|
|
|
|
}
|
2015-04-14 01:24:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onSetMusicInfo(String artist, String album, String track) {
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onFirmwareVersionReq() {
|
2015-04-19 22:20:47 +02:00
|
|
|
try {
|
2015-04-19 22:31:09 +02:00
|
|
|
TransactionBuilder builder = performInitialized("Get MI Band device info");
|
2015-04-19 22:20:47 +02:00
|
|
|
BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_DEVICE_INFO);
|
|
|
|
builder.read(characteristic).queue(getQueue());
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Log.e(TAG, "Unable to read device info from MI", ex);
|
|
|
|
}
|
2015-04-14 01:24:03 +02:00
|
|
|
}
|
|
|
|
|
2015-04-19 22:31:09 +02:00
|
|
|
@Override
|
|
|
|
public void onBatteryInfoReq() {
|
|
|
|
try {
|
|
|
|
TransactionBuilder builder = performInitialized("Get MI Band battery info");
|
|
|
|
BluetoothGattCharacteristic characteristic = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_BATTERY);
|
|
|
|
builder.read(characteristic).queue(getQueue());
|
|
|
|
} catch (IOException ex) {
|
|
|
|
Log.e(TAG, "Unable to read battery info from MI", ex);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-14 01:24:03 +02:00
|
|
|
@Override
|
|
|
|
public void onAppInfoReq() {
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onAppDelete(int id, int index) {
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onPhoneVersion(byte os) {
|
|
|
|
// TODO Auto-generated method stub
|
|
|
|
|
|
|
|
}
|
2015-04-19 02:37:29 +02:00
|
|
|
|
2015-04-19 22:20:47 +02:00
|
|
|
@Override
|
|
|
|
public void onCharacteristicRead(BluetoothGatt gatt,
|
2015-04-20 11:58:59 +02:00
|
|
|
BluetoothGattCharacteristic characteristic, int status) {
|
2015-04-19 22:20:47 +02:00
|
|
|
super.onCharacteristicRead(gatt, characteristic, status);
|
|
|
|
|
2015-04-19 22:31:09 +02:00
|
|
|
UUID characteristicUUID = characteristic.getUuid();
|
|
|
|
if (MiBandService.UUID_CHARACTERISTIC_DEVICE_INFO.equals(characteristicUUID)) {
|
2015-04-19 22:20:47 +02:00
|
|
|
handleDeviceInfo(characteristic.getValue(), status);
|
2015-04-19 22:31:09 +02:00
|
|
|
} else if (MiBandService.UUID_CHARACTERISTIC_BATTERY.equals(characteristicUUID)) {
|
|
|
|
handleBatteryInfo(characteristic.getValue(), status);
|
2015-04-19 22:20:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
@Override
|
|
|
|
public void onCharacteristicWrite(BluetoothGatt gatt,
|
2015-04-19 11:28:03 +02:00
|
|
|
BluetoothGattCharacteristic characteristic, int status) {
|
2015-04-19 02:37:29 +02:00
|
|
|
UUID characteristicUUID = characteristic.getUuid();
|
|
|
|
if (MiBandService.UUID_CHARACTERISTIC_PAIR.equals(characteristicUUID)) {
|
|
|
|
handlePairResult(characteristic.getValue(), status);
|
2015-04-19 15:11:50 +02:00
|
|
|
} else if (MiBandService.UUID_CHARACTERISTIC_USER_INFO.equals(characteristicUUID)) {
|
|
|
|
handleUserInfoResult(characteristic.getValue(), status);
|
2015-04-19 02:37:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-19 22:31:09 +02:00
|
|
|
private void handleDeviceInfo(byte[] value, int status) {
|
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
|
|
|
DeviceInfo info = new DeviceInfo(value);
|
|
|
|
getDevice().setFirmwareVersion(info.getFirmwareVersion());
|
|
|
|
getDevice().sendDeviceUpdateIntent(getContext());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleBatteryInfo(byte[] value, int status) {
|
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
|
|
|
BatteryInfo info = new BatteryInfo(value);
|
|
|
|
getDevice().setBatteryLevel((short) info.getLevelInPercent());
|
|
|
|
getDevice().setBatteryState(info.getStatus());
|
|
|
|
getDevice().sendDeviceUpdateIntent(getContext());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-19 15:11:50 +02:00
|
|
|
private void handleUserInfoResult(byte[] value, int status) {
|
|
|
|
// successfully transfered user info means we're initialized
|
|
|
|
if (status == BluetoothGatt.GATT_SUCCESS) {
|
|
|
|
setConnectionState(State.INITIALIZED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void setConnectionState(State newState) {
|
|
|
|
getDevice().setState(newState);
|
|
|
|
getDevice().sendDeviceUpdateIntent(getContext());
|
|
|
|
}
|
|
|
|
|
2015-04-19 02:37:29 +02:00
|
|
|
private void handlePairResult(byte[] pairResult, int status) {
|
|
|
|
if (status != BluetoothGatt.GATT_SUCCESS) {
|
|
|
|
Log.i(TAG, "Pairing MI device failed: " + status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object value = null;
|
|
|
|
if (pairResult != null) {
|
|
|
|
if (pairResult.length == 1) {
|
|
|
|
try {
|
|
|
|
byte b = pairResult[0];
|
2015-04-19 22:20:47 +02:00
|
|
|
Integer intValue = Integer.valueOf(b);
|
2015-04-19 02:37:29 +02:00
|
|
|
if (intValue.intValue() == 2) {
|
|
|
|
Log.i(TAG, "Successfully paired MI device");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} catch (Exception ex) {
|
|
|
|
Log.w(TAG, "Error identifying pairing result", ex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
value = pairResult.toString();
|
|
|
|
}
|
|
|
|
Log.i(TAG, "MI Band pairing result: " + value);
|
|
|
|
}
|
2015-04-14 01:24:03 +02:00
|
|
|
}
|