1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-29 13:26:50 +01:00

Add Device settings (screen on, time format, disconnect reminder, find my phone).

Changed device icon.
This commit is contained in:
mamutcho 2019-11-02 22:24:00 +02:00
parent 8f9466ee1c
commit fb08af6d04
9 changed files with 309 additions and 11 deletions

View File

@ -411,7 +411,7 @@
android:label="@string/title_activity_watch9_pairing" />
<activity
android:name=".devices.lenovo.LenovoWatchCalibrationActivity"
android:label="@string/title_activity_watch9_calibration" />
android:label="@string/title_activity_watchXplus_calibration" />
<activity
android:name=".activities.charts.ChartsActivity"
android:label="@string/title_activity_charts"

View File

@ -41,7 +41,7 @@ public class LenovoWatchCalibrationActivity extends AbstractGBActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_watch9_calibration);
setContentView(R.layout.activity_watchxplus_calibration);
pickerHour = findViewById(R.id.np_hour);
pickerMinute = findViewById(R.id.np_minute);

View File

@ -30,6 +30,14 @@ public final class WatchXPlusConstants extends LenovoWatchConstants {
public static final UUID UUID_CHARACTERISTIC_UNKNOWN_3 = UUID.fromString("0000a803-0000-1000-8000-00805f9b34fb");
public static final UUID UUID_CHARACTERISTIC_UNKNOWN_4 = UUID.fromString("0000a804-0000-1000-8000-00805f9b34fb");
public static final String PREF_ACTIVATE_DISPLAY = "activate_display_on_lift_wrist";
public static final String PREF_DISCONNECT_REMIND = "disconnect_notification";
public static final String PREF_FIND_PHONE = "prefs_find_phone";
public static final String PREF_FIND_PHONE_DURATION = "prefs_find_phone_duration";
// time format constants
public static final byte ARG_SET_TIMEMODE_24H = 0x00;
public static final byte ARG_SET_TIMEMODE_12H = 0x01;
public static final int NOTIFICATION_CHANNEL_DEFAULT = 0;
public static final int NOTIFICATION_CHANNEL_PHONE_CALL = 10;
@ -48,6 +56,13 @@ public final class WatchXPlusConstants extends LenovoWatchConstants {
public static final byte[] CMD_FITNESS_GOAL_SETTINGS = new byte[]{0x10, 0x02};
public static final byte[] CMD_DAY_STEPS_INFO = new byte[]{0x10, 0x03};
public static final byte[] CMD_SHAKE_SWITCH = new byte[]{0x03, -0x6E};
public static final byte[] CMD_DISCONNECT_REMIND = new byte[]{0x00, 0x11};
public static final byte[] CMD_TIME_LANGUAGE = new byte[]{0x03, -0x6F};
public static final byte[] RESP_SHAKE_SWITCH = new byte[]{0x08, 0x03, -0x6E};
public static final byte[] RESP_DISCONNECT_REMIND = new byte[]{0x08, 0x00, 0x11};
public static final byte[] RESP_AUTHORIZATION_TASK = new byte[]{0x01, 0x01, 0x05};
public static final byte[] RESP_DAY_STEPS_INDICATOR = new byte[]{0x08, 0x10, 0x03};
public static final byte[] RESP_HEARTRATE = new byte[]{-0x80, 0x15, 0x03};

View File

@ -4,6 +4,7 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.bluetooth.le.ScanFilter;
import android.content.Context;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.ParcelUuid;
@ -15,6 +16,8 @@ import java.util.Collection;
import java.util.Collections;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
@ -26,8 +29,12 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import static nodomain.freeyourgadget.gadgetbridge.GBApplication.getContext;
public class WatchXPlusDeviceCoordinator extends AbstractDeviceCoordinator {
public static final int FindPhone_ON = -1;
public static final int FindPhone_OFF = 0;
@NonNull
@Override
@ -135,17 +142,73 @@ public class WatchXPlusDeviceCoordinator extends AbstractDeviceCoordinator {
}
@Override
public boolean supportsRealtimeData() {
return false;
}
public boolean supportsRealtimeData() { return false; }
@Override
public boolean supportsWeather() {
return true;
}
@Override
public boolean supportsFindDevice() {
return false;
public boolean supportsFindDevice() { return false; }
@Override
public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
return new int[]{
R.xml.devicesettings_liftwrist_display,
R.xml.devicesettings_disconnectnotification,
R.xml.devicesettings_find_phone,
R.xml.devicesettings_timeformat
};
}
public static byte getTimeMode(SharedPreferences sharedPrefs) {
String timeMode = sharedPrefs.getString(DeviceSettingsPreferenceConst.PREF_TIMEFORMAT, getContext().getString(R.string.p_timeformat_24h));
if (timeMode.equals(getContext().getString(R.string.p_timeformat_24h))) {
return WatchXPlusConstants.ARG_SET_TIMEMODE_24H;
} else {
return WatchXPlusConstants.ARG_SET_TIMEMODE_12H;
}
}
// check if it is needed to toggle Lift Wrist to Sreen on
public static boolean shouldEnableHeadsUpScreen(SharedPreferences sharedPrefs) {
String liftMode = sharedPrefs.getString(WatchXPlusConstants.PREF_ACTIVATE_DISPLAY, getContext().getString(R.string.p_on));
// WatchXPlus doesn't support scheduled intervals. Treat it as "on".
return !liftMode.equals(getContext().getString(R.string.p_off));
}
// check if it is needed to toggle Disconnect reminder
public static boolean shouldEnableDisconnectReminder(SharedPreferences sharedPrefs) {
String lostReminder = sharedPrefs.getString(WatchXPlusConstants.PREF_DISCONNECT_REMIND, getContext().getString(R.string.p_on));
// WatchXPlus doesn't support scheduled intervals. Treat it as "on".
return !lostReminder.equals(getContext().getString(R.string.p_off));
}
/**
* @return {@link #FindPhone_OFF}, {@link #FindPhone_ON}, or the duration
*/
public static int getFindPhone(SharedPreferences sharedPrefs) {
String findPhone = sharedPrefs.getString(WatchXPlusConstants.PREF_FIND_PHONE, getContext().getString(R.string.p_off));
if (findPhone.equals(getContext().getString(R.string.p_off))) {
return FindPhone_OFF;
} else if (findPhone.equals(getContext().getString(R.string.p_on))) {
return FindPhone_ON;
} else { // Duration
String duration = sharedPrefs.getString(WatchXPlusConstants.PREF_FIND_PHONE_DURATION, "0");
try {
int iDuration;
try {
iDuration = Integer.valueOf(duration);
} catch (Exception ex) {
iDuration = 60;
}
return iDuration;
} catch (Exception e) {
return FindPhone_ON;
}
}
}
}

View File

@ -52,8 +52,8 @@ public enum DeviceType {
ZETIME(80, R.drawable.ic_device_zetime, R.drawable.ic_device_zetime_disabled, R.string.devicetype_mykronoz_zetime),
ID115(90, R.drawable.ic_device_h30_h10, R.drawable.ic_device_h30_h10_disabled, R.string.devicetype_id115),
WATCH9(100, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_watch9),
WATCHX(101, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_watchx),
WATCHXPLUS(102, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_watchxplus),
WATCHX(101, R.drawable.ic_device_watchxplus, R.drawable.ic_device_watchxplus_disabled, R.string.devicetype_watchx),
WATCHXPLUS(102, R.drawable.ic_device_watchxplus, R.drawable.ic_device_watchxplus_disabled, R.string.devicetype_watchxplus),
ROIDMI(110, R.drawable.ic_device_roidmi, R.drawable.ic_device_roidmi_disabled, R.string.devicetype_roidmi),
ROIDMI3(112, R.drawable.ic_device_roidmi, R.drawable.ic_device_roidmi_disabled, R.string.devicetype_roidmi3),
CASIOGB6900(120, R.drawable.ic_device_default, R.drawable.ic_device_default_disabled, R.string.devicetype_casiogb6900),

View File

@ -23,11 +23,14 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Handler;
import androidx.annotation.IntRange;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -46,16 +49,19 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventBatteryInfo;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventVersionInfo;
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.DataType;
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus.WatchXPlusConstants;
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus.WatchXPlusDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.lenovo.watchxplus.WatchXPlusSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusHealthActivityOverlay;
import nodomain.freeyourgadget.gadgetbridge.entities.WatchXPlusHealthActivityOverlayDao;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventFindPhone;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
@ -371,7 +377,10 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
.getBatteryState(builder)
.enableNotificationChannels(builder)
.enableDoNotDisturb(builder, false)
.setFitnessGoal(builder);
.setFitnessGoal(builder)
.syncPreferences(builder);
//.setHeadsUpScreen(builder, true);
//.getSwitchStatus(builder);
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
builder.setGattCallback(this);
@ -569,12 +578,24 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
@Override
public void onSendConfiguration(String config) {
TransactionBuilder builder;
SharedPreferences sharedPreferences = GBApplication.getDeviceSpecificSharedPrefs(this.getDevice().getAddress());
try {
builder = performInitialized("sendConfig: " + config);
switch (config) {
case ActivityUser.PREF_USER_STEPS_GOAL:
setFitnessGoal(builder);
break;
case WatchXPlusConstants.PREF_ACTIVATE_DISPLAY:
setHeadsUpScreen(builder, sharedPreferences);
getShakeStatus(builder);
break;
case WatchXPlusConstants.PREF_DISCONNECT_REMIND:
setDisconnectReminder(builder, sharedPreferences);
getDisconnectReminderStatus(builder);
break;
case DeviceSettingsPreferenceConst.PREF_TIMEFORMAT:
setTimeMode(builder, sharedPreferences);
break;
}
builder.queue(getQueue());
} catch (IOException e) {
@ -641,11 +662,18 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
if (WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE.equals(characteristicUUID)) {
if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_FIRMWARE_INFO, 5)) {
handleFirmwareInfo(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_SHAKE_SWITCH, 5)) {
LOG.info(" RESP LIGHT SCREEN ");
handleShakeState(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_DISCONNECT_REMIND, 5)) {
LOG.info(" RESP DISCONNECT REMINDER ");
handleDisconnectReminderState(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_BATTERY_INFO, 5)) {
handleBatteryState(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_TIME_SETTINGS, 5)) {
handleTime(value);
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_BUTTON_INDICATOR, 5)) {
this.onReverseFindDevice(true);
// It looks like WatchXPlus doesn't send this action
LOG.info(" Unhandled action: Button pressed");
} else if (ArrayUtils.equals(value, WatchXPlusConstants.RESP_ALARM_INDICATOR, 5)) {
@ -1109,6 +1137,154 @@ public class WatchXPlusDeviceSupport extends AbstractBTLEDeviceSupport {
handleGBDeviceEvent(batteryInfo);
}
// handle lift wrist to screen on and shake to refuse call
// for test purposes only
private void handleShakeState(byte[] value) {
boolean z = true;
String light = "lightScreen";
if ((value[11] & 1) == 1) {
light = light + " on";
} else {
light = light + " off";
}
String refuse = "refuseCall";
if ((((value[11] & 2) >> 1) & 1) != 1) {
//z = false;
refuse = refuse + " off";
} else {
refuse = refuse + " on";
}
LOG.info(" handleShakeState: " + light + " " + refuse);
}
// handle disconnect reminder state
// for test purposes only
private void handleDisconnectReminderState(byte[] value) {
boolean z = true;
if (1 != value[8]) {
z = false;
}
LOG.info(" disconnectReminder: " + Boolean.valueOf(z) + " val: " + value[8]);
return;
}
// read preferences
private void syncPreferences(TransactionBuilder transaction) {
SharedPreferences sharedPreferences = GBApplication.getDeviceSpecificSharedPrefs(this.getDevice().getAddress());
this.setHeadsUpScreen(transaction, sharedPreferences);
this.setDisconnectReminder(transaction, sharedPreferences);
this.setTimeMode(transaction, sharedPreferences);
}
private Handler mFindPhoneHandler = new Handler();
private void onReverseFindDevice(boolean start) {
if (start) {
SharedPreferences sharedPreferences = GBApplication.getDeviceSpecificSharedPrefs(
this.getDevice().getAddress());
int findPhone = WatchXPlusDeviceCoordinator.getFindPhone(sharedPreferences);
if (findPhone != WatchXPlusDeviceCoordinator.FindPhone_OFF) {
GBDeviceEventFindPhone findPhoneEvent = new GBDeviceEventFindPhone();
findPhoneEvent.event = GBDeviceEventFindPhone.Event.START;
evaluateGBDeviceEvent(findPhoneEvent);
if (findPhone > 0) {
this.mFindPhoneHandler.postDelayed(new Runnable() {
@Override
public void run() {
onReverseFindDevice(false);
}
}, findPhone * 1000);
}
}
} else {
// Always send stop, ignore preferences.
GBDeviceEventFindPhone findPhoneEvent = new GBDeviceEventFindPhone();
findPhoneEvent.event = GBDeviceEventFindPhone.Event.STOP;
evaluateGBDeviceEvent(findPhoneEvent);
}
}
// Set Lift Wrist to Light Screen based on saved preferences
private WatchXPlusDeviceSupport setHeadsUpScreen(TransactionBuilder transactionBuilder, SharedPreferences sharedPreferences) {
return this.setHeadsUpScreen(transactionBuilder,
WatchXPlusDeviceCoordinator.shouldEnableHeadsUpScreen(sharedPreferences));
}
// Command to toggle Lift Wrist to Light Screen
private WatchXPlusDeviceSupport setHeadsUpScreen(TransactionBuilder transactionBuilder, boolean enable) {
byte refuseCall = 0x00;
byte lightScreen = 0x00;
if (enable) {
lightScreen = 0x01;
}
byte b = (byte) (lightScreen + (refuseCall << 1));
byte[] liftScreen = new byte[4];
liftScreen[0] = 0x00;
liftScreen[1] = 0x00;
liftScreen[2] = 0x00;
liftScreen[3] = b; //byte[11]
transactionBuilder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
buildCommand(WatchXPlusConstants.CMD_SHAKE_SWITCH,
WatchXPlusConstants.WRITE_VALUE,
liftScreen));
return this;
}
private WatchXPlusDeviceSupport setDisconnectReminder(TransactionBuilder transactionBuilder, SharedPreferences sharedPreferences) {
return this.setDisconnectReminder(transactionBuilder,
WatchXPlusDeviceCoordinator.shouldEnableDisconnectReminder(sharedPreferences));
}
private WatchXPlusDeviceSupport setDisconnectReminder(TransactionBuilder transactionBuilder, boolean enable) {
transactionBuilder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
buildCommand(WatchXPlusConstants.CMD_DISCONNECT_REMIND,
WatchXPlusConstants.WRITE_VALUE,
new byte[]{(byte) (enable ? 0x01 : 0x00)}));
return this;
}
// Request status of Disconnect reminder
public WatchXPlusDeviceSupport getDisconnectReminderStatus(TransactionBuilder transactionBuilder) {
transactionBuilder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
buildCommand(WatchXPlusConstants.CMD_DISCONNECT_REMIND,
WatchXPlusConstants.READ_VALUE));
return this;
}
// Request status of Lift Wrist to Light Screen, and Shake to Refuse Call
public WatchXPlusDeviceSupport getShakeStatus(TransactionBuilder transactionBuilder) {
transactionBuilder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
buildCommand(WatchXPlusConstants.CMD_SHAKE_SWITCH,
WatchXPlusConstants.READ_VALUE));
return this;
}
// set time format
private WatchXPlusDeviceSupport setTimeMode(TransactionBuilder transactionBuilder, byte timeMode) {
byte[] bArr = new byte[2];
bArr[0] = 0x01; //byte[08] language - force to English language
bArr[1] = timeMode; //byte[09] time
transactionBuilder.write(getCharacteristic(WatchXPlusConstants.UUID_CHARACTERISTIC_WRITE),
buildCommand(WatchXPlusConstants.CMD_TIME_LANGUAGE,
WatchXPlusConstants.WRITE_VALUE,
bArr));
LOG.info(" setTimeMode: " + bArr);
return this;
}
private WatchXPlusDeviceSupport setTimeMode(TransactionBuilder transactionBuilder, SharedPreferences sharedPreferences) {
return this.setTimeMode(transactionBuilder,
WatchXPlusDeviceCoordinator.getTimeMode(sharedPreferences));
}
@Override
public void dispose() {
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());

View File

@ -30,6 +30,12 @@
<string name="appmanager_cached_watchapps_watchfaces">Приложения в кеша</string>
<string name="appmanager_installed_watchapps">Инсталирани приложения</string>
<string name="appmanager_installed_watchfaces">Инсталирани циферблати</string>
<string name="mi2_prefs_activate_display_on_lift">Включи екрана при вдигане</string>
<string name="prefs_disconnect_notification">Известие при прекъсване</string>
<string name="prefs_find_phone">Намери телефона</string>
<string name="prefs_enable_find_phone">Включи намиране на телефона</string>
<string name="prefs_find_phone_summary">Използвайте устройството, за да накарате телефона да звъни.</string>
<string name="prefs_find_phone_duration">Звънене - секунди</string>
<string name="appmananger_app_delete">Изтриване</string>
<string name="appmananger_app_delete_cache">Изтриване и премахване от кеша</string>
<string name="appmananger_app_reinstall">Преинсталиране</string>
@ -253,6 +259,14 @@
<string name="miband_prefs_alias">Име/Псевдоним</string>
<string name="pref_header_vibration_count">Брой на вибрациите</string>
<string name="watch9_pairing_tap_hint">Когато часовникът завибрира, разклатете устройството или натиснете бутона</string>
<string name="watch9_time_minutes">Минути:</string>
<string name="watch9_time_hours">Часове:</string>
<string name="watch9_time_seconds">Секунди:</string>
<string name="watch9_calibration_hint">Задайте времето, което показва устройството Ви.</string>
<string name="watch9_calibration_button">Сверяване</string>
<string name="title_activity_watch9_pairing">Watch 9 свързване</string>
<string name="title_activity_watch9_calibration">Watch 9 сверяване</string>
<string name="title_activity_watchXplus_calibration">WatchX Plus сверяване</string>
<string name="title_activity_sleepmonitor">Наблюдение/анализ на съня</string>
<string name="pref_write_logfiles">Съхраняване на log файлове</string>
<string name="initializing">Инициализиране</string>

View File

@ -186,6 +186,12 @@
<string name="pref_title_screentime">Screen on duration</string>
<string name="prefs_title_all_day_heart_rate">All day heart rate measurement</string>
<string name="preferences_hplus_settings">HPlus/Makibes settings</string>
<!-- WatchXPlus Preferences -->
<string name="pref_wxp_title_unit_system">Units</string>
<string name="pref_wxp_title_timeformat">Time format</string>
<string name="pref_wxp_title_screentime">Screen on duration</string>
<string name="pref_wxp_title_lift_wirst">Lift wirst to screen on</string>
<string name="preferences_watchxplus_settings">WatchXPlus settings</string>
<!-- Makibes HR3 Preferences -->
<string name="preferences_makibes_hr3_settings">Makibes HR3 settings</string>
<!-- ID115 Preferences -->
@ -701,6 +707,7 @@
<string name="watch9_calibration_button">Calibrate</string>
<string name="title_activity_watch9_pairing">Watch 9 pairing</string>
<string name="title_activity_watch9_calibration">Watch 9 calibration</string>
<string name="title_activity_watchXplus_calibration">WatchX Plus calibration</string>
<string name="pref_title_contextual_arabic">Contextual Arabic</string>
<string name="pref_summary_contextual_arabic">Enable this to support contextual Arabic</string>
<string name="preferences_rtl_settings">Right To Left Support</string>

View File

@ -574,6 +574,29 @@
android:icon="@drawable/ic_device_zetime"
android:key="pref_key_zetime"
android:title="@string/zetime_title_settings"/>
<PreferenceScreen
android:icon="@drawable/ic_device_watchxplus"
android:key="pref_key_watchxplus"
android:title="@string/preferences_watchxplus_settings">
<PreferenceCategory
android:key="pref_category_watchxplus_general"
android:title="@string/pref_header_general">
<EditTextPreference
android:defaultValue="5"
android:key="watchxplus_screentime"
android:title="@string/pref_wxp_title_screentime"/>
<CheckBoxPreference
android:layout="@layout/preference_checkbox"
android:defaultValue="true"
android:key="watchxplus_liftwirst"
android:title="@string/pref_wxp_title_lift_wirst" />
</PreferenceCategory>
</PreferenceScreen>
</PreferenceCategory>
<PreferenceCategory