Initial support for Mi Band specific settings

(User info for now).

TODO: We need to have that information *before* starting a connect
master
cpfeiffer 2015-05-07 01:30:40 +02:00
parent 44333c4244
commit a23690c8e1
11 changed files with 287 additions and 78 deletions

View File

@ -42,6 +42,13 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".ControlCenter" />
</activity>
<activity
android:name=".miband.MiBandPreferencesActivity"
android:label="@string/preferences_miband_settings" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".SettingsActivity" />
</activity>
<activity
android:name=".AppManagerActivity"
android:label="@string/title_activity_appmanager" >

View File

@ -1,6 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge;
import android.content.Intent;
import android.media.audiofx.BassBoost;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
@ -10,12 +11,19 @@ import android.support.v4.app.NavUtils;
import android.support.v4.content.LocalBroadcastManager;
import android.view.MenuItem;
public class SettingsActivity extends PreferenceActivity {
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity;
import nodomain.freeyourgadget.gadgetbridge.miband.MiBandPreferencesActivity;
public class SettingsActivity extends AbstractSettingsActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
addPreferencesFromResource(R.xml.preferences);
Preference pref = (Preference) findPreference("notifications_generic");
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@ -25,9 +33,16 @@ public class SettingsActivity extends PreferenceActivity {
return true;
}
});
final Preference developmentMiaddr = findPreference(GB.PREF_DEVELOPMENT_MIBAND_ADDRESS);
bindPreferenceSummaryToValue(developmentMiaddr);
pref = (Preference) findPreference("pref_key_miband");
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
Intent enableIntent = new Intent(SettingsActivity.this, MiBandPreferencesActivity.class);
startActivity(enableIntent);
return true;
}
});
final Preference developmentMiaddr = findPreference(GB.PREF_DEVELOPMENT_MIBAND_ADDRESS);
developmentMiaddr.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
@ -40,65 +55,8 @@ public class SettingsActivity extends PreferenceActivity {
});
}
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
}
};
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* @see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference) {
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
protected String[] getPreferenceKeysWithSummary() {
return new String[] { GB.PREF_DEVELOPMENT_MIBAND_ADDRESS };
}
}

View File

@ -0,0 +1,101 @@
package nodomain.freeyourgadget.gadgetbridge.activities;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.util.Log;
import android.view.MenuItem;
public class AbstractSettingsActivity extends PreferenceActivity {
private static final String TAG = "AbstractSettingsAct";
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
for (String prefKey : getPreferenceKeysWithSummary()) {
final Preference pref = findPreference(prefKey);
if (pref != null) {
bindPreferenceSummaryToValue(pref);
} else {
Log.e(TAG, "Unknown preference key: " + prefKey + ", unable to display value.");
}
}
}
/**
* Subclasses should reimplement this to return the keys of those
* preferences which should print its values as a summary below the
* preference name.
*/
protected String[] getPreferenceKeysWithSummary() {
return new String[0];
}
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference.setSummary(
index >= 0
? listPreference.getEntries()[index]
: null);
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
return true;
}
};
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* @see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference) {
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
NavUtils.navigateUpFromSameTask(this);
return true;
}
return super.onOptionsItemSelected(item);
}
}

View File

@ -0,0 +1,10 @@
package nodomain.freeyourgadget.gadgetbridge.miband;
public interface MiBandConst {
String PREF_USER_ALIAS = "mi_user_alias";
String PREF_USER_YEAR_OF_BIRTH = "mi_user_year_of_birth";
String PREF_USER_GENDER = "mi_user_gender";
String PREF_USER_HEIGHT_CM = "mi_user_height_cm";
String PREF_USER_WEIGHT_KG = "mi_user_weight_kg";
}

View File

@ -0,0 +1,30 @@
package nodomain.freeyourgadget.gadgetbridge.miband;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import nodomain.freeyourgadget.gadgetbridge.GB;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity;
public class MiBandPreferencesActivity extends AbstractSettingsActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.miband_preferences);
}
@Override
protected String[] getPreferenceKeysWithSummary() {
String[] prefsWithSummary = {
MiBandConst.PREF_USER_ALIAS,
MiBandConst.PREF_USER_YEAR_OF_BIRTH,
MiBandConst.PREF_USER_GENDER,
MiBandConst.PREF_USER_HEIGHT_CM,
MiBandConst.PREF_USER_WEIGHT_KG
};
return prefsWithSummary;
}
}

View File

@ -2,6 +2,8 @@ package nodomain.freeyourgadget.gadgetbridge.miband;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import java.io.IOException;
@ -10,6 +12,7 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBCommand;
import nodomain.freeyourgadget.gadgetbridge.GBDevice.State;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.btle.TransactionBuilder;
@ -69,17 +72,30 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
}
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());
try {
SharedPreferences mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext().getApplicationContext());
int userYear = Integer.parseInt(mSharedPreferences.getString(MiBandConst.PREF_USER_YEAR_OF_BIRTH, "0"));
int age = 25;
if (userYear > 1900) {
age = Calendar.getInstance().get(Calendar.YEAR) - userYear;
if (age <= 0) {
age = 25;
}
}
UserInfo info = new UserInfo(
getDevice().getAddress(),
mSharedPreferences.getString(MiBandConst.PREF_USER_ALIAS, "1550050550"),
(mSharedPreferences.getString(MiBandConst.PREF_USER_GENDER, "male") == "male" ? 1 : 0),
age,
Integer.parseInt(mSharedPreferences.getString(MiBandConst.PREF_USER_HEIGHT_CM, "175")),
Integer.parseInt(mSharedPreferences.getString(MiBandConst.PREF_USER_WEIGHT_KG, "70")),
0
);
return info;
} catch (Exception ex) {
Log.e(TAG, "Error creating user info from settings, using default user instead: " + ex);
return UserInfo.getDefault(getDevice().getAddress());
}
}
/**

View File

@ -41,8 +41,8 @@ public class UserInfo {
byte[] sequence = new byte[20];
int uid = Integer.parseInt(alias);
int uid = calculateUidFrom(alias);
String normalizedAlias = ensureTenCharacters(alias);
sequence[0] = (byte) uid;
sequence[1] = (byte) (uid >>> 8);
sequence[2] = (byte) (uid >>> 16);
@ -55,7 +55,7 @@ public class UserInfo {
sequence[8] = (byte) (type & 0xff);
for (int u = 9; u < 19; u++)
sequence[u] = alias.getBytes()[u - 9];
sequence[u] = normalizedAlias.getBytes()[u - 9];
byte[] crcSequence = new byte[19];
for (int u = 0; u < crcSequence.length; u++)
@ -66,6 +66,30 @@ public class UserInfo {
this.data = sequence;
}
private String ensureTenCharacters(String alias) {
char[] result = new char[10];
int aliasLen = alias.length();
int maxLen = Math.min(10, alias.length());
int diff = 10 - maxLen;
for (int i = 0; i < maxLen; i++) {
result[i + diff] = alias.charAt(i);
}
for (int i = 0; i < diff; i++) {
result[i] = '0';
}
return new String(result);
}
private int calculateUidFrom(String alias) {
int uid = 0;
try {
uid = Integer.parseInt(alias);
} catch (NumberFormatException ex) {
uid = alias.hashCode(); // simple as that
}
return uid;
}
public byte[] getData() {
return this.data;
}

View File

@ -11,4 +11,14 @@
<item>never</item>
</string-array>
<string-array name="gender">
<item>@string/male</item>
<item>@string/female</item>
<item>@string/other</item>
</string-array>
<string-array name="gender_values">
<item>male</item>
<item>female</item>
<item>other</item>
</string-array>
</resources>

View File

@ -81,4 +81,10 @@
<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>
<string name="preferences_category_device_specific_settings">Device Specific Settings</string>
<string name="preferences_miband_settings">Mi Band Settings</string>
<string name="male">male</string>
<string name="female">female</string>
<string name="other">other</string>
</resources>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:key="pref_category_miband_personal"
android:title="About You">
<EditTextPreference
android:key="mi_user_alias"
android:maxLength="17"
android:title="Name/Alias" />
<EditTextPreference
android:key="mi_user_year_of_birth"
android:digits="0123456789"
android:maxLength="4"
android:title="Year of Birth" />
<ListPreference
android:defaultValue="male"
android:entries="@array/gender"
android:entryValues="@array/gender_values"
android:key="mi_user_gender"
android:title="Gender" />
<!--TODO: support localized heights and weights -->
<EditTextPreference
android:key="mi_user_height_cm"
android:digits="0123456789"
android:maxLength="3"
android:title="Height in cm" />
<EditTextPreference
android:key="mi_user_weight_kg"
android:digits="0123456789"
android:maxLength="3"
android:title="Weight in kg" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -52,6 +52,14 @@
android:title="@string/pref_title_whenscreenon" />
</PreferenceCategory>
<PreferenceCategory
android:key="pref_key_device_specific_category"
android:title="@string/preferences_category_device_specific_settings">
<Preference
android:key="pref_key_miband"
android:title="@string/preferences_miband_settings" />
</PreferenceCategory>
<PreferenceCategory
android:key="pref_key_development"
android:title="@string/pref_header_development">