Support for vibration profiles, configurable for notifications

Configurable for sms, k9, incoming calls, pebble messages, generic
notifications.

Color is unfortunately not configurable so far, see #37

Closes #29

Currently provided profiles are
- staccato
- short
- medium
- long
- waterdrop
- ring
- alarm clock
This commit is contained in:
cpfeiffer 2015-06-20 23:22:22 +02:00
parent f105bbbde3
commit c7b4f295a1
11 changed files with 374 additions and 41 deletions

View File

@ -0,0 +1,30 @@
package nodomain.freeyourgadget.gadgetbridge.btle;
import android.bluetooth.BluetoothGatt;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.GBDevice;
/**
* A special action that checks for an abort-condition, and if met, the currently
* executing transaction will be aborted by returning false.
*/
public abstract class AbortTransactionAction extends PlainAction {
private static final Logger LOG = LoggerFactory.getLogger(AbortTransactionAction.class);
public AbortTransactionAction() {
}
@Override
public boolean run(BluetoothGatt gatt) {
if (shouldAbort()) {
LOG.info("Aborting transaction because abort criteria met.");
return false;
}
return true;
}
protected abstract boolean shouldAbort();
}

View File

@ -12,7 +12,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBDevice;
* sequence (transaction). It will abort the entire initialization sequence
* by returning false, when the device is already initialized.
*/
public class CheckInitializedAction extends PlainAction {
public class CheckInitializedAction extends AbortTransactionAction {
private static final Logger LOG = LoggerFactory.getLogger(CheckInitializedAction.class);
private final GBDevice device;
@ -22,11 +22,11 @@ public class CheckInitializedAction extends PlainAction {
}
@Override
public boolean run(BluetoothGatt gatt) {
boolean continueWithOtherInitActions = !device.isInitialized();
if (!continueWithOtherInitActions) {
protected boolean shouldAbort() {
boolean abort = device.isInitialized();
if (abort) {
LOG.info("Aborting device initialization, because already initialized: " + device);
}
return continueWithOtherInitActions;
return abort;
}
}

View File

@ -5,6 +5,8 @@ import android.content.SharedPreferences;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.R;
public final class MiBandConst {
private static final Logger LOG = LoggerFactory.getLogger(MiBandConst.class);
@ -13,9 +15,11 @@ public final class MiBandConst {
public static final String PREF_USER_GENDER = "mi_user_gender";
public static final String PREF_USER_HEIGHT_CM = "mi_user_height_cm";
public static final String PREF_USER_WEIGHT_KG = "mi_user_weight_kg";
public static final String PREF_MIBAND_WEARSIDE = "mi_wearside";
public static final String PREF_MIBAND_ADDRESS = "development_miaddr"; // FIXME: should be prefixed mi_
public static final String ORIGIN_SMS = "sms";
public static final String ORIGIN_INCOMING_CALL = "incoming_call";
public static final String ORIGIN_K9MAIL = "k9mail";
public static final String ORIGIN_PEBBLEMSG = "pebblemsg";
public static final String ORIGIN_GENERIC = "generic";
@ -32,10 +36,16 @@ public final class MiBandConst {
}
}
public static String getNotificationPrefStringValue(String pref, String origin, SharedPreferences prefs, String defaultValue) {
String key = getNotificationPrefKey(pref, origin);
return prefs.getString(key, defaultValue);
}
public static final String getNotificationPrefKey(String pref, String origin) {
return new StringBuilder(pref).append('_').append(origin).toString();
}
public static final String VIBRATION_PROFILE = "mi_vibration_profile";
public static final String VIBRATION_COUNT = "mi_vibration_count";
public static final String VIBRATION_DURATION = "mi_vibration_duration";
public static final String VIBRATION_PAUSE = "mi_vibration_pause";
@ -45,7 +55,8 @@ public final class MiBandConst {
public static final String FLASH_COLOUR = "mi_flash_colour";
public static final String FLASH_ORIGINAL_COLOUR = "mi_flash_original_colour";
public static final int DEFAULT_VALUE_VIBRATION_COUNT = 6;
public static final String DEFAULT_VALUE_VIBRATION_PROFILE = "short";
public static final int DEFAULT_VALUE_VIBRATION_COUNT = 3;
public static final int DEFAULT_VALUE_VIBRATION_DURATION = 500; // ms
public static final int DEFAULT_VALUE_VIBRATION_PAUSE = 500; // ms
public static final int DEFAULT_VALUE_FLASH_COUNT = 10; // ms

View File

@ -10,16 +10,19 @@ import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractSettingsActivity;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.ORIGIN_GENERIC;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.ORIGIN_INCOMING_CALL;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.ORIGIN_K9MAIL;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.ORIGIN_PEBBLEMSG;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.ORIGIN_SMS;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.PREF_MIBAND_ADDRESS;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.PREF_MIBAND_WEARSIDE;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.PREF_USER_ALIAS;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.PREF_USER_GENDER;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.PREF_USER_HEIGHT_CM;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.PREF_USER_WEIGHT_KG;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.PREF_USER_YEAR_OF_BIRTH;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.VIBRATION_COUNT;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.VIBRATION_PROFILE;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.getNotificationPrefKey;
public class MiBandPreferencesActivity extends AbstractSettingsActivity {
@ -51,10 +54,17 @@ public class MiBandPreferencesActivity extends AbstractSettingsActivity {
PREF_USER_GENDER,
PREF_USER_HEIGHT_CM,
PREF_USER_WEIGHT_KG,
PREF_MIBAND_WEARSIDE,
PREF_MIBAND_ADDRESS,
getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_SMS),
getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_SMS),
getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_INCOMING_CALL),
getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_INCOMING_CALL),
getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_K9MAIL),
getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_K9MAIL),
getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_PEBBLEMSG),
getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_PEBBLEMSG),
getNotificationPrefKey(VIBRATION_PROFILE, ORIGIN_GENERIC),
getNotificationPrefKey(VIBRATION_COUNT, ORIGIN_GENERIC),
};
}

View File

@ -22,11 +22,14 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.GBCommand;
import nodomain.freeyourgadget.gadgetbridge.GBDevice.State;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.btle.AbortTransactionAction;
import nodomain.freeyourgadget.gadgetbridge.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.btle.BtLEAction;
import nodomain.freeyourgadget.gadgetbridge.btle.SetDeviceBusyAction;
import nodomain.freeyourgadget.gadgetbridge.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.database.ActivityDatabaseHandler;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.DEFAULT_VALUE_VIBRATION_PROFILE;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.DEFAULT_VALUE_FLASH_COLOUR;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.DEFAULT_VALUE_FLASH_COUNT;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.DEFAULT_VALUE_FLASH_DURATION;
@ -44,7 +47,9 @@ import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.ORIGIN_SMS
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.VIBRATION_COUNT;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.VIBRATION_DURATION;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.VIBRATION_PAUSE;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.VIBRATION_PROFILE;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.getNotificationPrefIntValue;
import static nodomain.freeyourgadget.gadgetbridge.miband.MiBandConst.getNotificationPrefStringValue;
public class MiBandSupport extends AbstractBTLEDeviceSupport {
@ -63,6 +68,7 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
private GregorianCalendar activityDataTimestampProgress = null;
//same as above, but remains untouched for the ack message
private GregorianCalendar activityDataTimestampToAck = null;
private volatile boolean telephoneRinging;
public MiBandSupport() {
@ -135,6 +141,42 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
builder.write(characteristic, getDefaultNotification()).queue(getQueue());
}
/**
* Sends a custom notification to the Mi Band.
* @param vibrationProfile specifies how and how often the Band shall vibrate.
* @param flashTimes
* @param flashColour
* @param originalColour
* @param flashDuration
* @param extraAction an extra action to be executed after every vibration and flash sequence. Allows to abort the repetition, for example.
* @param builder
*/
private void sendCustomNotification(VibrationProfile vibrationProfile, int flashTimes, int flashColour, int originalColour, long flashDuration, BtLEAction extraAction, TransactionBuilder builder) {
BluetoothGattCharacteristic controlPoint = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT);
for (byte i = 0; i < vibrationProfile.getRepeat(); i++) {
int[] onOffSequence = vibrationProfile.getOnOffSequence();
for (int j = 0; j < onOffSequence.length; j++) {
int on = onOffSequence[j];
on = Math.min(500, on); // longer than 500ms is not possible
builder.write(controlPoint, startVibrate);
builder.wait(on);
builder.write(controlPoint, stopVibrate);
if (++j < onOffSequence.length) {
int off = Math.max(onOffSequence[j], 25); // wait at least 25ms
builder.wait(off);
}
if (extraAction != null) {
builder.add(extraAction);
}
}
}
LOG.info("Sending notification to MiBand: " + controlPoint);
builder.queue(getQueue());
}
private void sendCustomNotification(int vibrateDuration, int vibrateTimes, int pause, int flashTimes, int flashColour, int originalColour, long flashDuration, TransactionBuilder builder) {
BluetoothGattCharacteristic controlPoint = getCharacteristic(MiBandService.UUID_CHARACTERISTIC_CONTROL_POINT);
int vDuration = Math.min(500, vibrateDuration); // longer than 500ms is not possible
@ -221,20 +263,22 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
// }
// }
private void performPreferredNotification(String task, String notificationOrigin) {
private void performPreferredNotification(String task, String notificationOrigin, BtLEAction extraAction) {
try {
TransactionBuilder builder = performInitialized(task);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
int vibrateDuration = getPreferredVibrateDuration(notificationOrigin, prefs);
int vibrateTimes = getPreferredVibrateCount(notificationOrigin, prefs);
int vibratePause = getPreferredVibratePause(notificationOrigin, prefs);
int vibrateTimes = getPreferredVibrateCount(notificationOrigin, prefs);
VibrationProfile profile = getPreferredVibrateProfile(notificationOrigin, prefs, vibrateTimes);
int flashTimes = getPreferredFlashCount(notificationOrigin, prefs);
int flashColour = getPreferredFlashColour(notificationOrigin, prefs);
int originalColour = getPreferredOriginalColour(notificationOrigin, prefs);
int flashDuration = getPreferredFlashDuration(notificationOrigin, prefs);
sendCustomNotification(vibrateDuration, vibrateTimes, vibratePause, flashTimes, flashColour, originalColour, flashDuration, builder);
sendCustomNotification(profile, flashTimes, flashColour, originalColour, flashDuration, extraAction, builder);
// sendCustomNotification(vibrateDuration, vibrateTimes, vibratePause, flashTimes, flashColour, originalColour, flashDuration, builder);
} catch (IOException ex) {
LOG.error("Unable to send notification to MI device", ex);
}
@ -268,20 +312,24 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
return getNotificationPrefIntValue(VIBRATION_DURATION, notificationOrigin, prefs, DEFAULT_VALUE_VIBRATION_DURATION);
}
private VibrationProfile getPreferredVibrateProfile(String notificationOrigin, SharedPreferences prefs, int repeat) {
String profileId = getNotificationPrefStringValue(VIBRATION_PROFILE, notificationOrigin, prefs, DEFAULT_VALUE_VIBRATION_PROFILE);
return VibrationProfile.getProfile(profileId, (byte) repeat);
}
@Override
public void onSMS(String from, String body) {
// performCustomNotification("sms received", 500, 3, 2000, 0, 0, 0, 0);
performPreferredNotification("sms received", ORIGIN_SMS);
performPreferredNotification("sms received", ORIGIN_SMS, null);
}
@Override
public void onEmail(String from, String subject, String body) {
performPreferredNotification("email received", ORIGIN_K9MAIL);
performPreferredNotification("email received", ORIGIN_K9MAIL, null);
}
@Override
public void onGenericNotification(String title, String details) {
performPreferredNotification("generic notification received", ORIGIN_GENERIC);
performPreferredNotification("generic notification received", ORIGIN_GENERIC, null);
}
@Override
@ -328,10 +376,24 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
@Override
public void onSetCallState(String number, String name, GBCommand command) {
if (GBCommand.CALL_INCOMING.equals(command)) {
performDefaultNotification("incoming call");
telephoneRinging = true;
AbortTransactionAction abortAction = new AbortTransactionAction() {
@Override
protected boolean shouldAbort() {
return !isTelephoneRinging();
}
};
performPreferredNotification("incoming call", MiBandConst.ORIGIN_INCOMING_CALL, abortAction);
} else if (GBCommand.CALL_START.equals(command) || GBCommand.CALL_END.equals(command)) {
telephoneRinging = false;
}
}
private boolean isTelephoneRinging() {
// don't synchronize, this is not really important
return telephoneRinging;
}
@Override
public void onSetMusicInfo(String artist, String album, String track) {
// not supported
@ -556,8 +618,12 @@ public class MiBandSupport extends AbstractBTLEDeviceSupport {
unsetBusy();
}
}
for (byte b : value) {
LOG.info("handleControlPoint GOT DATA:" + String.format("0x%8x", b));
if (value != null) {
for (byte b : value) {
LOG.info("handleControlPoint GOT DATA:" + String.format("0x%8x", b));
}
} else {
LOG.warn("handleControlPoint GOT null");
}
}

View File

@ -0,0 +1,69 @@
package nodomain.freeyourgadget.gadgetbridge.miband;
import android.content.Context;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
public class VibrationProfile {
public static final Context CONTEXT = GBApplication.getContext();
public static final String ID_STACCATO = CONTEXT.getString(R.string.p_staccato);
public static final String ID_SHORT = CONTEXT.getString(R.string.p_short);
public static final String ID_MEDIUM = CONTEXT.getString(R.string.p_medium);
public static final String ID_LONG = CONTEXT.getString(R.string.p_long);
public static final String ID_WATERDROP = CONTEXT.getString(R.string.p_waterdrop);
public static final String ID_RING = CONTEXT.getString(R.string.p_ring);
public static final String ID_ALARM_CLOCK = CONTEXT.getString(R.string.p_alarm_clock);
public static VibrationProfile getProfile(String id, byte repeat) {
if (ID_STACCATO.equals(id)) {
return new VibrationProfile(id, new int[]{100, 0}, repeat);
}
if (ID_SHORT.equals(id)) {
return new VibrationProfile(id, new int[] {200, 200}, repeat);
}
if (ID_LONG.equals(id)) {
return new VibrationProfile(id, new int[] {500, 1000}, repeat);
}
if (ID_WATERDROP.equals(id)) {
return new VibrationProfile(id, new int[] {100, 1500}, repeat);
}
if (ID_RING.equals(id)) {
return new VibrationProfile(id, new int[]{300, 200, 600, 2000}, repeat);
}
if (ID_ALARM_CLOCK.equals(id)) {
return new VibrationProfile(id, new int[] {30, 35, 30, 35, 30, 35, 30, 800}, repeat);
}
// medium
return new VibrationProfile(id, new int[] {300, 600}, repeat);
}
private final String id;
private int[] onOffSequence;
private byte repeat; // 1-10
/**
* Creates a new profile instance.
* @param id the ID, used as preference key.
* @param onOffSequence a sequence of alternating on and off durations, in milliseconds
* @param repeat how ofoften the sequence shall be repeated
*/
public VibrationProfile(String id, int[] onOffSequence, byte repeat) {
this.id = id;
this.repeat = repeat;
this.onOffSequence = onOffSequence;
}
public String getId() {
return id;
}
public int[] getOnOffSequence() {
return onOffSequence;
}
public byte getRepeat() {
return repeat;
}
}

View File

@ -21,4 +21,33 @@
<item>female</item>
<item>other</item>
</string-array>
<string-array name="wearside">
<item>@string/left</item>
<item>@string/right</item>
</string-array>
<string-array name="wearside_values">
<item>left</item>
<item>right</item>
</string-array>
<string-array name="vibration_profile">
<item>@string/vibration_profile_staccato</item>
<item>@string/vibration_profile_short</item>
<item>@string/vibration_profile_medium</item>
<item>@string/vibration_profile_long</item>
<item>@string/vibration_profile_waterdrop</item>
<item>@string/vibration_profile_ring</item>
<item>@string/vibration_profile_alarm_clock</item>
</string-array>
<string-array name="vibration_profile_values">
<!-- Note: corresponds with IDs in VibrationProfile -->
<item>@string/p_staccato</item>
<item>@string/p_short</item>
<item>@string/p_medium</item>
<item>@string/p_long</item>
<item>@string/p_waterdrop</item>
<item>@string/p_ring</item>
<item>@string/p_alarm_clock</item>
</string-array>
</resources>

View File

@ -28,7 +28,9 @@
<string name="pref_summary_datetime_syctimeonconnect">Sync time to device when connecting and when time or timezone changes on Android</string>
<string name="pref_header_notifications">Notifications</string>
<string name="pref_title_notifications_repetitions">Repetitions</string>
<string name="pref_title_notifications_sms">SMS</string>
<string name="pref_title_notifications_incoming_call">Incoming Calls</string>
<string name="pref_title_notifications_k9mail">K9-Mail</string>
<string name="pref_title_notifications_pebblemsg">Pebble Messages</string>
<string name="pref_summary_notifications_pebblemsg">Support for applications which send Notifications to the Pebble via Intent. Can be used for Conversations.</string>
@ -91,6 +93,8 @@
<string name="male">male</string>
<string name="female">female</string>
<string name="other">other</string>
<string name="left">left</string>
<string name="right">right</string>
<string name="miband_pairing_using_dummy_userdata">No valid user data given, using dummy user data for now.</string>
<string name="miband_pairing_tap_hint">When your Mi Band vibrates and blinks, tap it a few times in a row.</string>
<string name="appinstaller_install">Install</string>
@ -112,5 +116,22 @@
<string name="controlcenter_fetch_activity_data">Fetch Activity Data</string>
<string name="controlcenter_disconnect">Disconnect</string>
<string name="sleep_activity_date_range">From %1$s to %2$s</string>
<string name="miband_prefs_wearside">Wearing left or right?</string>
<string name="pref_screen_vibration_profile">Vibration Profile</string>
<string name="vibration_profile_staccato">Staccato</string>
<string name="vibration_profile_short">Short</string>
<string name="vibration_profile_medium">Medium</string>
<string name="vibration_profile_long">Long</string>
<string name="vibration_profile_waterdrop">Waterdrop</string>
<string name="vibration_profile_ring">Ring</string>
<string name="vibration_profile_alarm_clock">Alarm Clock</string>
<string name="miband_prefs_vibration">Vibration</string>
<string name="pref_screen_notification_profile_sms">SMS Notification</string>
<string name="pref_header_vibration_settings">Vibration Settings</string>
<string name="pref_screen_notification_profile_generic">Generic Notification</string>
<string name="pref_screen_notification_profile_pebblemsg">Pebble Notification</string>
<string name="pref_screen_notification_profile_k9mail">K9 Mail Notification</string>
<string name="pref_screen_notification_profile_incoming_call">Incoming Call Notification</string>
</resources>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Note: these are not translated! They are used as preference keys -->
<item name="p_staccato" type="string">staccato</item>
<item name="p_short" type="string">short</item>
<item name="p_medium" type="string">medium</item>
<item name="p_long" type="string">long</item>
<item name="p_waterdrop" type="string">waterdrop</item>
<item name="p_ring" type="string">ring</item>
<item name="p_alarm_clock" type="string">alarm_clock</item>
</resources>

View File

@ -34,35 +34,118 @@
android:maxLength="3"
android:title="@string/miband_prefs_weight_kg" />
<ListPreference
android:defaultValue="left"
android:entries="@array/wearside"
android:entryValues="@array/wearside_values"
android:key="mi_wearside"
android:title="@string/miband_prefs_wearside" />
</PreferenceCategory>
<PreferenceCategory
android:key="pref_category_miband_notification"
android:title="@string/pref_header_vibration_count">
<EditTextPreference
android:defaultValue="3"
android:inputType="number"
android:key="mi_vibration_count_sms"
android:maxLength="1"
android:title="@string/pref_title_notifications_sms" />
<EditTextPreference
android:defaultValue="3"
android:inputType="number"
android:key="mi_vibration_count_k9mail"
android:maxLength="1"
android:title="@string/pref_title_notifications_k9mail" />
<EditTextPreference
android:defaultValue="3"
android:inputType="number"
android:key="mi_vibration_count_pebblemsg"
android:maxLength="1"
android:title="@string/pref_title_notifications_pebblemsg" />
<EditTextPreference
android:defaultValue="3"
android:inputType="number"
android:key="mi_vibration_count_generic"
android:maxLength="1"
android:title="@string/pref_title_notifications_generic" />
android:title="@string/pref_header_vibration_settings">
<PreferenceScreen
android:key="vibration_profile_key"
android:title="@string/pref_screen_notification_profile_sms"
android:persistent="false">
<ListPreference
android:defaultValue="@string/p_staccato"
android:entries="@array/vibration_profile"
android:entryValues="@array/vibration_profile_values"
android:key="mi_vibration_profile_sms"
android:title="@string/miband_prefs_vibration" />
<EditTextPreference
android:defaultValue="3"
android:inputType="number"
android:key="mi_vibration_count_sms"
android:maxLength="1"
android:title="@string/pref_title_notifications_repetitions" />
</PreferenceScreen>
<PreferenceScreen
android:key="vibration_profile_key"
android:title="@string/pref_screen_notification_profile_incoming_call"
android:persistent="false">
<ListPreference
android:defaultValue="@string/p_ring"
android:entries="@array/vibration_profile"
android:entryValues="@array/vibration_profile_values"
android:key="mi_vibration_profile_incoming_call"
android:title="@string/miband_prefs_vibration" />
<EditTextPreference
android:defaultValue="60"
android:inputType="number"
android:key="mi_vibration_count_incoming_call"
android:maxLength="1"
android:title="@string/pref_title_notifications_repetitions" />
</PreferenceScreen>
<PreferenceScreen
android:key="vibration_profile_key"
android:title="@string/pref_screen_notification_profile_k9mail"
android:persistent="false">
<ListPreference
android:defaultValue="@string/p_medium"
android:entries="@array/vibration_profile"
android:entryValues="@array/vibration_profile_values"
android:key="mi_vibration_profile_k9mail"
android:title="@string/miband_prefs_vibration" />
<EditTextPreference
android:defaultValue="2"
android:inputType="number"
android:key="mi_vibration_count_k9mail"
android:maxLength="1"
android:title="@string/pref_title_notifications_repetitions" />
</PreferenceScreen>
<PreferenceScreen
android:key="vibration_profile_key"
android:title="@string/pref_screen_notification_profile_pebblemsg"
android:persistent="false">
<ListPreference
android:defaultValue="@string/p_short"
android:entries="@array/vibration_profile"
android:entryValues="@array/vibration_profile_values"
android:key="mi_vibration_profile_pebblemsg"
android:title="@string/miband_prefs_vibration" />
<EditTextPreference
android:defaultValue="1"
android:inputType="number"
android:key="mi_vibration_count_pebblemsg"
android:maxLength="1"
android:title="@string/pref_title_notifications_repetitions" />
</PreferenceScreen>
<PreferenceScreen
android:key="vibration_profile_key"
android:title="@string/pref_screen_notification_profile_generic"
android:persistent="false">
<ListPreference
android:defaultValue="@string/p_waterdrop"
android:entries="@array/vibration_profile"
android:entryValues="@array/vibration_profile_values"
android:key="mi_vibration_profile_generic"
android:title="@string/miband_prefs_vibration" />
<EditTextPreference
android:defaultValue="3"
android:inputType="number"
android:key="mi_vibration_count_generic"
android:maxLength="1"
android:title="@string/pref_title_notifications_repetitions" />
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory

View File

@ -58,9 +58,11 @@
android:title="@string/preferences_category_device_specific_settings">
<Preference
android:key="pref_key_miband"
android:icon="@drawable/ic_device_miband"
android:title="@string/preferences_miband_settings" />
<PreferenceScreen
android:key="pref_key_pebble"
android:icon="@drawable/ic_device_pebble"
android:title="@string/pref_title_pebble_settings" >
<PreferenceCategory
android:key="pref_key_development"