1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-07 21:57:57 +02:00

[Banglejs] Send phone location data to banglejs, which can be used as gps data (#2992)

Since the PR #2961 aswell as #2976, i pushed the changes to this pr.

Original text:

With this PR, the gadgetbridge app sends the current locationd data, obtained from the gps or network provider, to a connected banglejs device as an "gps" event.

The bangle device can use this data instead of the internal gps data. Therefor saving battery energy, since the gps chip is one of the biggest energy consumers.

Furthermore it enables the banglejs device to use the location data, based on the network with which the phone is currently connected. This would be usefull if there is no gps signal.

Updates:

I added a network provider so that it is possible to use the network location. I also overload the start method of GBLocationManager so that it is now possible to select which provider should be used to get the data (currently GPS or Network) and to set a interval to determine how often the update should be run.

For the banglejs device i added a switch to enable the sending of gps data. I also added a setting, to set the interval on how often the gps data is being updated. This allows to throttle the updates of the gps data and therefore saving energy of the smartphone batterie.

To further save energy, the app now requestes the current status of the gps from the banglejs and only sends data, if the gps of the banglejs is turned on.

In the PR #2976 I also moved the settings to the device settings of the banglejs and i moved the logic to the onLocationChanged method of the GBLocationManager.

Co-authored-by: Lukas <lukas.edi@gmx.net>
Reviewed-on: https://codeberg.org/Freeyourgadget/Gadgetbridge/pulls/2992
Co-authored-by: LukasEdl <lukasedl@noreply.codeberg.org>
Co-committed-by: LukasEdl <lukasedl@noreply.codeberg.org>
This commit is contained in:
LukasEdl 2022-12-12 07:48:19 +00:00 committed by Andreas Shimokawa
parent 0dd0b2bead
commit abf19f2b6c
10 changed files with 288 additions and 26 deletions

View File

@ -70,6 +70,9 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_VIBRATION_STRENGH_PERCENTAGE = "vibration_strength";
public static final String PREF_RELAX_FIRMWARE_CHECKS = "relax_firmware_checks";
public static final String PREF_DEVICE_GPS_UPDATE = "banglejs_gps_update";
public static final String PREF_DEVICE_GPS_UPDATE_INTERVAL = "banglejs_gps_update_interval";
public static final String PREF_DEVICE_INTERNET_ACCESS = "device_internet_access";
public static final String PREF_DEVICE_INTENTS = "device_intents";

View File

@ -17,6 +17,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.banglejs;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_GPS_UPDATE;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_INTENTS;
import android.annotation.TargetApi;
import android.app.Activity;
import android.bluetooth.le.ScanFilter;
@ -44,6 +47,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDeviceCandidate;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class BangleJSCoordinator extends AbstractBLEDeviceCoordinator {

View File

@ -40,6 +40,13 @@ public abstract class AbstractLocationProvider {
*/
abstract void start(final Context context);
/**
* Start sending periodic location updates.
*
* @param context the {@link Context}.
*/
abstract void start(final Context context, final int interval);
/**
* Stop sending periodic location updates.
*

View File

@ -34,6 +34,7 @@ import java.util.Set;
import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
/**
* A static location manager, which keeps track of what providers are currently running. A notification is kept
* while there is at least one provider runnin.
@ -44,10 +45,15 @@ public class GBLocationManager {
/**
* The current number of running listeners.
*/
private static Map<EventHandler, AbstractLocationProvider> providers = new HashMap<>();
private static Map<EventHandler, Map<LocationProviderType, AbstractLocationProvider>> providers = new HashMap<>();
public static void start(final Context context, final EventHandler eventHandler) {
if (providers.containsKey(eventHandler)) {
GBLocationManager.start(context, eventHandler, LocationProviderType.GPS, null);
}
public static void start(final Context context, final EventHandler eventHandler, final LocationProviderType providerType, Integer updateInterval) {
System.out.println("Starting");
if (providers.containsKey(eventHandler) && providers.get(eventHandler).containsKey(providerType)) {
LOG.warn("EventHandler already registered");
return;
}
@ -55,16 +61,52 @@ public class GBLocationManager {
GB.createGpsNotification(context, providers.size() + 1);
final GBLocationListener locationListener = new GBLocationListener(eventHandler);
final AbstractLocationProvider locationProvider = new PhoneGpsLocationProvider(locationListener);
final AbstractLocationProvider locationProvider;
switch (providerType) {
case GPS:
LOG.info("Using gps location provider");
locationProvider = new PhoneGpsLocationProvider(locationListener);
break;
case NETWORK:
LOG.info("Using network location provider");
locationProvider = new PhoneNetworkLocationProvider(locationListener);
break;
default:
LOG.info("Using default location provider: GPS");
locationProvider = new PhoneGpsLocationProvider(locationListener);
}
locationProvider.start(context);
if (updateInterval != null) {
locationProvider.start(context, updateInterval);
} else {
locationProvider.start(context);
}
providers.put(eventHandler, locationProvider);
if (providers.containsKey(eventHandler)) {
providers.get(eventHandler).put(providerType, locationProvider);
} else {
Map<LocationProviderType, AbstractLocationProvider> providerMap = new HashMap<>();
providerMap.put(providerType, locationProvider);
providers.put(eventHandler, providerMap);
}
}
public static void stop(final Context context, final EventHandler eventHandler) {
final AbstractLocationProvider locationProvider = providers.remove(eventHandler);
GBLocationManager.stop(context, eventHandler, null);
}
public static void stop(final Context context, final EventHandler eventHandler, final LocationProviderType gpsType) {
if (!providers.containsKey(eventHandler)) return;
Map<LocationProviderType, AbstractLocationProvider> providerMap = providers.get(eventHandler);
if (gpsType == null) {
for (LocationProviderType providerType: providerMap.keySet()) {
if (!providerMap.containsKey(providerType)) return;
stopProvider(context, providerMap.get(providerType));
}
}
}
private static void stopProvider(final Context context, AbstractLocationProvider locationProvider) {
if (locationProvider != null) {
LOG.warn("EventHandler not registered");

View File

@ -0,0 +1,6 @@
package nodomain.freeyourgadget.gadgetbridge.externalevents.gps;
public enum LocationProviderType {
GPS,
NETWORK,
}

View File

@ -88,6 +88,14 @@ public class MockLocationProvider extends AbstractLocationProvider {
handler.postDelayed(locationUpdateRunnable, interval);
}
@Override
void start(final Context context, int minInterval) {
LOG.info("Starting mock location provider");
running = true;
handler.postDelayed(locationUpdateRunnable, interval);
}
@Override
void stop(final Context context) {
LOG.info("Stopping mock location provider");

View File

@ -41,9 +41,17 @@ public class PhoneGpsLocationProvider extends AbstractLocationProvider {
public PhoneGpsLocationProvider(LocationListener locationListener) {
super(locationListener);
}
public PhoneGpsLocationProvider(LocationListener locationListener, int intervalTime) {
super(locationListener);
}
@Override
void start(final Context context) {
start(context, INTERVAL_MIN_TIME);
}
@Override
void start(Context context, int interval) {
LOG.info("Starting phone gps location provider");
if (!GB.checkPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) && !GB.checkPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)) {
@ -55,14 +63,14 @@ public class PhoneGpsLocationProvider extends AbstractLocationProvider {
locationManager.removeUpdates(getLocationListener());
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
INTERVAL_MIN_TIME,
interval,
INTERVAL_MIN_DISTANCE,
getLocationListener(),
Looper.getMainLooper()
);
final Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
LOG.debug("Last known location: {}", lastKnownLocation);
LOG.debug("Last known gps location: {}", lastKnownLocation);
}
@Override

View File

@ -0,0 +1,80 @@
/* Copyright (C) 2022 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.externalevents.gps;
import android.Manifest;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Looper;
import android.widget.Toast;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
/**
* A location provider that uses the phone GPS, using {@link LocationManager}.
*/
public class PhoneNetworkLocationProvider extends AbstractLocationProvider {
private static final Logger LOG = LoggerFactory.getLogger(PhoneNetworkLocationProvider.class);
private static final int INTERVAL_MIN_TIME = 1000;
private static final int INTERVAL_MIN_DISTANCE = 0;
public PhoneNetworkLocationProvider(LocationListener locationListener) {
super(locationListener);
}
@Override
void start(final Context context) {
start(context, INTERVAL_MIN_TIME);
}
@Override
void start(Context context, int interval) {
LOG.info("Starting phone network location provider");
if (!GB.checkPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) && !GB.checkPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION)) {
GB.toast("Location permission not granted", Toast.LENGTH_SHORT, GB.ERROR);
return;
}
final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
locationManager.removeUpdates(getLocationListener());
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
interval,
INTERVAL_MIN_DISTANCE,
getLocationListener(),
Looper.getMainLooper()
);
final Location lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
LOG.debug("Last known network location: {}", lastKnownLocation);
}
@Override
void stop(final Context context) {
LOG.info("Stopping phone network location provider");
final LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
locationManager.removeUpdates(getLocationListener());
}
}

View File

@ -16,6 +16,15 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.service.devices.banglejs;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_ALLOW_HIGH_MTU;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BANGLEJS_TEXT_BITMAP;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BANGLEJS_TEXT_BITMAP_SIZE;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_GPS_UPDATE;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_GPS_UPDATE_INTERVAL;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_INTENTS;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_INTERNET_ACCESS;
import static nodomain.freeyourgadget.gadgetbridge.database.DBHelper.getUser;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.content.BroadcastReceiver;
@ -27,6 +36,8 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Build;
import android.util.Base64;
@ -36,8 +47,8 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.android.volley.AuthFailureError;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
@ -54,6 +65,7 @@ import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@ -61,18 +73,21 @@ import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.SimpleTimeZone;
import java.util.Timer;
import java.util.UUID;
import java.lang.reflect.Field;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import de.greenrobot.dao.query.QueryBuilder;
import io.wax911.emojify.Emoji;
import io.wax911.emojify.EmojiManager;
import io.wax911.emojify.EmojiUtils;
import de.greenrobot.dao.query.QueryBuilder;
import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
@ -84,18 +99,18 @@ import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventMusicContr
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventNotificationControl;
import nodomain.freeyourgadget.gadgetbridge.devices.banglejs.BangleJSConstants;
import nodomain.freeyourgadget.gadgetbridge.devices.banglejs.BangleJSSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver;
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiCoordinator;
import nodomain.freeyourgadget.gadgetbridge.entities.BangleJSActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncState;
import nodomain.freeyourgadget.gadgetbridge.entities.CalendarSyncStateDao;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationManager;
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.LocationProviderType;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.model.BatteryState;
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEQueue;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
@ -105,22 +120,16 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.BtLEQueue;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiPhoneGpsStatus;
import nodomain.freeyourgadget.gadgetbridge.util.EmojiConverter;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_ALLOW_HIGH_MTU;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BANGLEJS_TEXT_BITMAP_SIZE;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_INTERNET_ACCESS;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_DEVICE_INTENTS;
import static nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst.PREF_BANGLEJS_TEXT_BITMAP;
import static nodomain.freeyourgadget.gadgetbridge.database.DBHelper.*;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarEvent;
import nodomain.freeyourgadget.gadgetbridge.util.calendar.CalendarManager;
public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
private static final Logger LOG = LoggerFactory.getLogger(BangleJSDeviceSupport.class);
@ -143,6 +152,10 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
private final LimitedQueue/*Long*/ mNotificationReplyAction = new LimitedQueue(16);
private Boolean gpsUpdateSetup = false;
private Timer gpsPositionTimer;
private final int gpsUpdateTimerInterval = 1000;
/// Maximum amount of characters to store in receiveHistory
public static final int MAX_RECEIVE_HISTORY_CHARS = 100000;
@ -160,6 +173,17 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
registerGlobalIntents();
}
@Override
public void dispose() {
super.dispose();
stopLocationUpdate();
}
private void stopLocationUpdate() {
GBLocationManager.stop(getContext(), this, null);
gpsUpdateSetup = false;
}
private void addReceiveHistory(String s) {
receiveHistory += s;
if (receiveHistory.length() > MAX_RECEIVE_HISTORY_CHARS)
@ -193,6 +217,9 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
case GBDevice.ACTION_DEVICE_CHANGED: {
LOG.info("ACTION_DEVICE_CHANGED " + (gbDevice!=null ? gbDevice.getStateString():""));
addReceiveHistory("\n================================================\nACTION_DEVICE_CHANGED "+gbDevice.getStateString()+" "+(new SimpleDateFormat("yyyy-mm-dd hh:mm:ss", Locale.US)).format(Calendar.getInstance().getTime())+"\n================================================\n");
if (gbDevice.getState() == GBDevice.State.NOT_CONNECTED) {
stopLocationUpdate();
}
}
}
}
@ -273,6 +300,8 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
LOG.info("Initialization Done");
requestBangleGPSPowerStatus();
return builder;
}
@ -762,6 +791,15 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
intent.setPackage(BuildConfig.APPLICATION_ID);
GBApplication.getContext().sendBroadcast(intent);
} break;
case "gps_power": {
boolean status = json.getBoolean("status");
LOG.info("Got gps power status: " + status);
if (status) {
setupGPSUpdateTimer();
} else {
stopLocationUpdate();
}
} break;
default : {
LOG.info("UART RX JSON packet type '"+packetType+"' not understood.");
}
@ -848,6 +886,59 @@ public class BangleJSDeviceSupport extends AbstractBTLEDeviceSupport {
uartTx(builder, cmd+"\n");
}
void requestBangleGPSPowerStatus() {
try {
JSONObject o = new JSONObject();
o.put("t", "is_gps_active");
LOG.debug("Requesting gps power status: " + o.toString());
uartTxJSON("is_gps_active", o);
} catch (JSONException e) {
GB.toast(getContext(), "uartTxJSONError: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
}
}
void setupGPSUpdateTimer() {
if (gpsUpdateSetup) {
LOG.debug("GPS position timer is already setup");
return;
}
Prefs devicePrefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress()));
if(devicePrefs.getBoolean(PREF_DEVICE_GPS_UPDATE, false)) {
int intervalLength = devicePrefs.getInt(PREF_DEVICE_GPS_UPDATE_INTERVAL, 10000);
LOG.info("Setup location listener with an update interval of " + intervalLength + " ms");
GBLocationManager.start(getContext(), this, LocationProviderType.GPS, intervalLength);
GBLocationManager.start(getContext(), this, LocationProviderType.NETWORK, intervalLength);
} else {
LOG.debug("Phone gps data update is deactivated in the settings");
}
}
@Override
public void onSetGpsLocation(final Location location) {
if (!GBApplication.getPrefs().getBoolean("use_updated_location_if_available", false)) return;
LOG.debug("new location: " + location.toString());
JSONObject o = new JSONObject();
try {
o.put("t", "gps");
o.put("lat", location.getLatitude());
o.put("long", location.getLongitude());
o.put("alt", location.getAltitude());
o.put("speed", location.getSpeed());
o.put("course", 0);
o.put("time", new Date().getTime());
o.put("satellites", 0);
o.put("hdop", location.getAccuracy());
o.put("externalSource", true);
LOG.debug("Sending gps valu: " + o.toString());
uartTxJSON("gps", o);
} catch (JSONException e) {
GB.toast(getContext(), "uartTxJSONError: " + e.getLocalizedMessage(), Toast.LENGTH_LONG, GB.ERROR);
}
}
@Override
public boolean useAutoConnect() {
return true;

View File

@ -1,5 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<SwitchPreference
android:defaultValue="false"
android:icon="@drawable/ic_gps_location"
android:key="banglejs_gps_update"
android:summary="Use the gps data of the phone to overwrite the gps data of the bangle device"
android:title="Use phone gps data" />
<EditTextPreference
android:defaultValue="10000"
android:inputType="number"
android:icon="@drawable/ic_access_time"
android:key="banglejs_gps_update_interval"
android:summary="This option is only active, if the gps data of the phone is being used. This option sets the interval in ms how often the gps position is being updated"
android:title="GPS data update interval in ms" />
<SwitchPreference
android:defaultValue="false"
android:icon="@drawable/ic_translate"