diff --git a/app/src/main/java/org/traccar/client/MainActivity.java b/app/src/main/java/org/traccar/client/MainActivity.java
index 03f39f3..e07f50c 100644
--- a/app/src/main/java/org/traccar/client/MainActivity.java
+++ b/app/src/main/java/org/traccar/client/MainActivity.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.PackageManager;
+import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
@@ -35,7 +36,11 @@ import android.preference.TwoStatePreference;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
+import android.webkit.URLUtil;
+import android.widget.Toast;
+import java.net.MalformedURLException;
+import java.net.URL;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
@@ -46,9 +51,7 @@ public class MainActivity extends PreferenceActivity implements OnSharedPreferen
private static final String TAG = MainActivity.class.getSimpleName();
public static final String KEY_DEVICE = "id";
- public static final String KEY_ADDRESS = "address";
- public static final String KEY_PORT = "port";
- public static final String KEY_SECURE = "secure";
+ public static final String KEY_URL = "url";
public static final String KEY_INTERVAL = "interval";
public static final String KEY_DISTANCE = "distance";
public static final String KEY_ANGLE = "angle";
@@ -65,12 +68,12 @@ public class MainActivity extends PreferenceActivity implements OnSharedPreferen
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
if (BuildConfig.HIDDEN_APP) {
removeLauncherIcon();
}
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+ migratePreferencesIfNecessary(sharedPreferences);
addPreferencesFromResource(R.xml.preferences);
initPreferences();
@@ -80,30 +83,13 @@ public class MainActivity extends PreferenceActivity implements OnSharedPreferen
return newValue != null && !newValue.equals("");
}
});
- findPreference(KEY_ADDRESS).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
+ findPreference(KEY_URL).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
- return newValue != null && Patterns.DOMAIN_NAME.matcher((String) newValue).matches();
- } else {
- return newValue != null && !((String) newValue).isEmpty();
- }
- }
- });
- findPreference(KEY_PORT).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
- @Override
- public boolean onPreferenceChange(Preference preference, Object newValue) {
- if (newValue != null) {
- try {
- int value = Integer.parseInt((String) newValue);
- return value > 0 && value <= 65536;
- } catch (NumberFormatException e) {
- Log.w(TAG, e);
- }
- }
- return false;
+ return (newValue != null) && setServerURL(newValue.toString());
}
});
+
findPreference(KEY_INTERVAL).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
@@ -194,9 +180,7 @@ public class MainActivity extends PreferenceActivity implements OnSharedPreferen
private void setPreferencesEnabled(boolean enabled) {
findPreference(KEY_DEVICE).setEnabled(enabled);
- findPreference(KEY_ADDRESS).setEnabled(enabled);
- findPreference(KEY_PORT).setEnabled(enabled);
- findPreference(KEY_SECURE).setEnabled(enabled);
+ findPreference(KEY_URL).setEnabled(enabled);
findPreference(KEY_INTERVAL).setEnabled(enabled);
findPreference(KEY_DISTANCE).setEnabled(enabled);
findPreference(KEY_ANGLE).setEnabled(enabled);
@@ -307,4 +291,47 @@ public class MainActivity extends PreferenceActivity implements OnSharedPreferen
}
}
+ private boolean setServerURL(String userUrl) {
+ EditTextPreference preference = (EditTextPreference) findPreference(KEY_URL);
+
+ if (userUrl == null || userUrl.trim().length() == 0) {
+ preference.setText(getString(R.string.settings_url_default_value));
+ preference.setSummary(R.string.settings_url_summary);
+ findPreference(KEY_STATUS).setEnabled(true);
+ return false;
+ }
+ if (URLUtil.isValidUrl(userUrl) && (URLUtil.isHttpUrl(userUrl) || URLUtil.isHttpsUrl(userUrl))) {
+ preference.setSummary(R.string.settings_url_summary);
+ findPreference(KEY_STATUS).setEnabled(true);
+ } else {
+ preference.setSummary(R.string.settings_invalid_url_summary);
+ findPreference(KEY_STATUS).setEnabled(false);
+ Toast.makeText(MainActivity.this, R.string.msg_invalid_url, Toast.LENGTH_LONG).show();
+ }
+ return true;
+ }
+
+ private void migratePreferencesIfNecessary(SharedPreferences preferences) {
+ String port = preferences.getString("port", null);
+ if (port != null) {
+ Log.d(TAG, "migratePreferencesIfNecessary: migrating to URL preference");
+
+ String host = preferences.getString("address", getString(R.string.settings_url_default_value));
+ String scheme = preferences.getBoolean("secure", false) ? "https" : "http";
+
+ Uri.Builder builder = new Uri.Builder();
+ builder.scheme(scheme).encodedAuthority(host + ":" + port).build();
+ SharedPreferences.Editor editor = preferences.edit();
+ editor.putString(KEY_URL, builder.toString());
+
+ editor.remove("port");
+ editor.remove("address");
+ editor.remove("secure");
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+ }
}
diff --git a/app/src/main/java/org/traccar/client/Patterns.java b/app/src/main/java/org/traccar/client/Patterns.java
deleted file mode 100644
index 84f8857..0000000
--- a/app/src/main/java/org/traccar/client/Patterns.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton.tananaev@gmail.com)
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.traccar.client;
-
-import java.util.regex.Pattern;
-
-public class Patterns {
-
- private static final String IP_ADDRESS_STRING =
- "((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
- + "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
- + "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
- + "|[1-9][0-9]|[0-9]))";
-
- private static final String UCS_CHAR = "[" +
- "\u00A0-\uD7FF" +
- "\uF900-\uFDCF" +
- "\uFDF0-\uFFEF" +
- "\uD800\uDC00-\uD83F\uDFFD" +
- "\uD840\uDC00-\uD87F\uDFFD" +
- "\uD880\uDC00-\uD8BF\uDFFD" +
- "\uD8C0\uDC00-\uD8FF\uDFFD" +
- "\uD900\uDC00-\uD93F\uDFFD" +
- "\uD940\uDC00-\uD97F\uDFFD" +
- "\uD980\uDC00-\uD9BF\uDFFD" +
- "\uD9C0\uDC00-\uD9FF\uDFFD" +
- "\uDA00\uDC00-\uDA3F\uDFFD" +
- "\uDA40\uDC00-\uDA7F\uDFFD" +
- "\uDA80\uDC00-\uDABF\uDFFD" +
- "\uDAC0\uDC00-\uDAFF\uDFFD" +
- "\uDB00\uDC00-\uDB3F\uDFFD" +
- "\uDB44\uDC00-\uDB7F\uDFFD" +
- "&&[^\u00A0[\u2000-\u200A]\u2028\u2029\u202F\u3000]]";
-
- private static final String LABEL_CHAR = "a-zA-Z0-9" + UCS_CHAR;
-
- private static final String IRI_LABEL =
- "[" + LABEL_CHAR + "](?:[" + LABEL_CHAR + "\\-]{0,61}[" + LABEL_CHAR + "]){0,1}";
-
- private static final String RELAXED_DOMAIN_NAME =
- "(?:" + "(?:" + IRI_LABEL + "(?:\\.(?=\\S))" +"?)+" + "|" + IP_ADDRESS_STRING + ")";
-
- public static final Pattern DOMAIN_NAME = Pattern.compile(RELAXED_DOMAIN_NAME);
-
-}
diff --git a/app/src/main/java/org/traccar/client/ProtocolFormatter.java b/app/src/main/java/org/traccar/client/ProtocolFormatter.java
index 17e47a1..aecf737 100644
--- a/app/src/main/java/org/traccar/client/ProtocolFormatter.java
+++ b/app/src/main/java/org/traccar/client/ProtocolFormatter.java
@@ -19,14 +19,12 @@ import android.net.Uri;
public class ProtocolFormatter {
- public static String formatRequest(String address, int port, boolean secure, Position position) {
- return formatRequest(address, port, secure, position, null);
+ public static String formatRequest(String url, Position position) {
+ return formatRequest(url, position, null);
}
- public static String formatRequest(String address, int port, boolean secure, Position position, String alarm) {
-
- Uri.Builder builder = new Uri.Builder();
- builder.scheme(secure ? "https" : "http").encodedAuthority(address + ':' + port)
+ public static String formatRequest(String url, Position position, String alarm) {
+ Uri serverUrl = Uri.parse(url).buildUpon()
.appendQueryParameter("id", position.getDeviceId())
.appendQueryParameter("timestamp", String.valueOf(position.getTime().getTime() / 1000))
.appendQueryParameter("lat", String.valueOf(position.getLatitude()))
@@ -34,13 +32,19 @@ public class ProtocolFormatter {
.appendQueryParameter("speed", String.valueOf(position.getSpeed()))
.appendQueryParameter("bearing", String.valueOf(position.getCourse()))
.appendQueryParameter("altitude", String.valueOf(position.getAltitude()))
- .appendQueryParameter("batt", String.valueOf(position.getBattery()));
+ .appendQueryParameter("batt", String.valueOf(position.getBattery()))
+ .build();
- if (alarm != null) {
- builder.appendQueryParameter("alarm", alarm);
+ if (alarm != null && alarm.trim().length() != 0) {
+ serverUrl = serverUrl.buildUpon().appendQueryParameter("alarm", alarm).build();
}
-
- return builder.build().toString();
+ int port = serverUrl.getPort();
+ if (port < 0 || port > 65535) {
+ port = 5055;
+ String host = serverUrl.getHost();
+ serverUrl = serverUrl.buildUpon().encodedAuthority(host + ":" + port).build();
+ }
+ return serverUrl.toString();
}
}
diff --git a/app/src/main/java/org/traccar/client/ShortcutActivity.java b/app/src/main/java/org/traccar/client/ShortcutActivity.java
index 27fcb68..ac3ddd8 100644
--- a/app/src/main/java/org/traccar/client/ShortcutActivity.java
+++ b/app/src/main/java/org/traccar/client/ShortcutActivity.java
@@ -64,10 +64,7 @@ public class ShortcutActivity extends Activity {
location, PositionProvider.getBatteryLevel(this));
String request = ProtocolFormatter.formatRequest(
- preferences.getString(MainActivity.KEY_ADDRESS, null),
- Integer.parseInt(preferences.getString(MainActivity.KEY_PORT, null)),
- preferences.getBoolean(MainActivity.KEY_SECURE, false),
- position, ALARM_SOS);
+ preferences.getString(MainActivity.KEY_URL, null), position, ALARM_SOS);
RequestManager.sendRequestAsync(request, new RequestManager.RequestHandler() {
@Override
diff --git a/app/src/main/java/org/traccar/client/TrackingController.java b/app/src/main/java/org/traccar/client/TrackingController.java
index 6e42ef8..9ffbf3d 100644
--- a/app/src/main/java/org/traccar/client/TrackingController.java
+++ b/app/src/main/java/org/traccar/client/TrackingController.java
@@ -36,9 +36,7 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
private Handler handler;
private SharedPreferences preferences;
- private String address;
- private int port;
- private boolean secure;
+ private String url;
private PositionProvider positionProvider;
private DatabaseHelper databaseHelper;
@@ -73,9 +71,7 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
networkManager = new NetworkManager(context, this);
isOnline = networkManager.isOnline();
- address = preferences.getString(MainActivity.KEY_ADDRESS, null);
- port = Integer.parseInt(preferences.getString(MainActivity.KEY_PORT, null));
- secure = preferences.getBoolean(MainActivity.KEY_SECURE, false);
+ url = preferences.getString(MainActivity.KEY_URL, null);
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
@@ -199,7 +195,7 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
private void send(final Position position) {
log("send", position);
lock();
- String request = ProtocolFormatter.formatRequest(address, port, secure, position);
+ String request = ProtocolFormatter.formatRequest(url, position);
RequestManager.sendRequestAsync(request, new RequestManager.RequestHandler() {
@Override
public void onComplete(boolean success) {
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 790d8c0..f317354 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -6,10 +6,9 @@
Traccar - Stop
Traccar - SOS
Device identifier
- Server address
- Domain name or IP address
- Server port
- Tracking server TCP port
+ Server URL
+ Tracking server URL
+ http://demo.traccar.org
Frequency
Reporting interval in seconds
Distance
@@ -21,11 +20,6 @@
Stop
Service stopped
Service running
- Encryption
- Enable
- Disable
- Encryption disabled
- Encryption enabled
Location provider
Source of location data
GPS provider
@@ -33,9 +27,7 @@
Mixed provider
Foreground service
Increase service priority
- Invalid server address
- Invalid server port
- Invalid frequency value
+ Invalid server URL
Status
About
Add shortcuts
@@ -51,4 +43,5 @@
Connectivity change
Device Settings
The app has been hidden. To open it again please dial 8722227 (TRACCAR).
+ Please enter a valid http:// or https:// URL
diff --git a/app/src/main/res/xml-v14/preferences.xml b/app/src/main/res/xml-v14/preferences.xml
index a402b81..941eae5 100644
--- a/app/src/main/res/xml-v14/preferences.xml
+++ b/app/src/main/res/xml-v14/preferences.xml
@@ -15,26 +15,10 @@
android:title="@string/settings_id_title" />
-
-
-
-
+ android:defaultValue="@string/settings_url_default_value"
+ android:key="url"
+ android:summary="@string/settings_url_summary"
+ android:title="@string/settings_url_title" />
-
-
-
-
+ android:defaultValue="@string/settings_url_default_value"
+ android:key="url"
+ android:summary="@string/settings_url_summary"
+ android:title="@string/settings_url_title" />