diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 4de6905..40f5e88 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -14,8 +14,7 @@ + android:label="@string/app_name"> @@ -24,7 +23,17 @@ - + + + + + + + diff --git a/res/layout/about.xml b/res/layout/about.xml new file mode 100644 index 0000000..f7b419a --- /dev/null +++ b/res/layout/about.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + diff --git a/res/layout/main.xml b/res/layout/main.xml deleted file mode 100644 index e327941..0000000 --- a/res/layout/main.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/res/layout/status.xml b/res/layout/status.xml new file mode 100644 index 0000000..a659a35 --- /dev/null +++ b/res/layout/status.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/res/menu/main.xml b/res/menu/main.xml index c5391c5..4cfe5b2 100644 --- a/res/menu/main.xml +++ b/res/menu/main.xml @@ -1,7 +1,14 @@ - - + + + + + diff --git a/res/menu/status.xml b/res/menu/status.xml new file mode 100644 index 0000000..3e977f4 --- /dev/null +++ b/res/menu/status.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml new file mode 100644 index 0000000..dd5b0f3 --- /dev/null +++ b/res/values/dimens.xml @@ -0,0 +1,5 @@ + + + 20dp + 15dp + diff --git a/res/values/strings.xml b/res/values/strings.xml index 1070fbe..ea09ede 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -1,8 +1,39 @@ + Traccar Client - Invalid input parameters. - About - Android software GPS tracker. For more information visit:\n\nhttp://www.traccar.org - Close + Traccar + + Device identifier + Server address + Domain name or IP address + Server port + Tracking server TCP port + Frequency + Messages interval in seconds + Debug mode + Additional status messages + Service status + Start + Stop + Service stopped + Service running + + Status + About + Clear + + Real time GPS tracker for Android devices. Compatible with Traccar Server and other tracking systems. + This application is free and open source, source code is licensed under Apache License Version 2.0 and available on GitHub. + For more information visit\nwww.traccar.org/client + + Service created + Service started + Service destroyed + Connection succeeded + Connection failed + Send failed + Location update + Preference update + diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml new file mode 100644 index 0000000..7d02d68 --- /dev/null +++ b/res/xml/preferences.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + diff --git a/src/org/traccar/client/AboutActivity.java b/src/org/traccar/client/AboutActivity.java new file mode 100644 index 0000000..eaf9e07 --- /dev/null +++ b/src/org/traccar/client/AboutActivity.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012 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 android.app.Activity; +import android.os.Bundle; + +public class AboutActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.about); + } + +} diff --git a/src/org/traccar/client/Connection.java b/src/org/traccar/client/Connection.java index 23fb577..401ef34 100644 --- a/src/org/traccar/client/Connection.java +++ b/src/org/traccar/client/Connection.java @@ -15,139 +15,119 @@ */ package org.traccar.client; +import java.io.Closeable; import java.io.OutputStream; +import java.net.InetSocketAddress; import java.net.Socket; +import java.net.SocketAddress; -import android.content.Context; -import android.content.Intent; -import android.os.Handler; +import android.os.AsyncTask; +import android.util.Log; /** - * Connection with autoreconnect + * Asynchronous connection + * + * All methods should be called from UI thread only. */ -public class Connection { +public class Connection implements Closeable { - private String address; - private int port; + public static final String LOG_TAG = "Traccar.Connection"; + public static final int SOCKET_TIMEOUT = 10 * 1000; - private String connectMessage; + /** + * Callback interface + */ + public interface ConnectionHandler { + void onConnected(boolean result); + void onSent(boolean result); + } + + private ConnectionHandler handler; private Socket socket; private OutputStream socketStream; - private String status; - - private Context context; - - /** - * Initialize connection parameters - */ - public Connection(String address, int port, String message) { - this.address = address; - this.port = port; - connectMessage = message; - setStatus(Traccar.STATUS_DISCONNECTED); + public Connection(ConnectionHandler handler) { + this.handler = handler; } - /** - * Get address - */ - public String getAddress() { - return address; - } + public void connect(String address, int port) { - /** - * Get port - */ - public int getPort() { - return port; - } + new AsyncTask() { - /** - * Set context - */ - public void setContext(Context context) { - this.context = context; - } - - /** - * Set connection status - */ - private void setStatus(String status) { - if (!status.equals(this.status)) { - this.status = status; - if (context != null) { - Intent intent = new Intent(Traccar.MSG_CONNECTION_STATUS); - intent.putExtra(Traccar.EXTRA_STATUS, status); - context.sendBroadcast(intent); + @Override + protected Boolean doInBackground(SocketAddress... params) { + try { + socket = new Socket(); + socket.connect(params[0]); + socket.setSoTimeout(SOCKET_TIMEOUT); + socketStream = socket.getOutputStream(); + handler.onConnected(true); + } catch (Exception e) { + close(); + return false; + } + return true; } - } + + @Override + protected void onCancelled(Boolean result) { + handler.onConnected(false); + } + + @Override + protected void onPostExecute(Boolean result) { + handler.onConnected(result); + } + + }.execute(InetSocketAddress.createUnresolved(address, port)); + } - /** - * Get connection status - */ - public String getStatus() { - return status; - } - - /** - * Establish connection - */ - public void connect() { - try { - socket = new Socket(address, port); - socket.setSoTimeout(Traccar.SOCKET_TIMEOUT); - socketStream = socket.getOutputStream(); - setStatus(Traccar.STATUS_CONNECTED); - send(connectMessage); - } catch (Exception e) { - reconnect(); - } - } - - /** - * Send message - */ public void send(String message) { + + new AsyncTask() { + + @Override + protected Boolean doInBackground(String... params) { + try { + socketStream.write(params[0].getBytes()); + socketStream.flush(); + } catch (Exception e) { + close(); + return false; + } + return true; + } + + @Override + protected void onCancelled(Boolean result) { + handler.onSent(false); + } + + @Override + protected void onPostExecute(Boolean result) { + handler.onSent(result); + } + + }.execute(message); + + } + + @Override + public void close() { try { if (socketStream != null) { - socketStream.write(message.getBytes()); - socketStream.flush(); + socketStream.close(); + socketStream = null; + } + if (socket != null) { + socket.close(); + socket = null; } } catch (Exception e) { - reconnect(); + Log.e(LOG_TAG, e.getMessage()); } } - /** - * Close connection - */ - public void close() { - handler.removeCallbacks(task); - if (socket != null) { - try { - socket.close(); - } catch (Exception e) { - } - socket = null; - } - socketStream = null; - setStatus(Traccar.STATUS_DISCONNECTED); - } - - private void reconnect() { - close(); - handler.postDelayed(task, Traccar.RECONNECT_DELAY); - } - - private Handler handler = new Handler(); - private ReconnectTask task = new ReconnectTask(); - - class ReconnectTask implements Runnable { - @Override - public void run() { - connect(); - } - } } diff --git a/src/org/traccar/client/Protocol.java b/src/org/traccar/client/Protocol.java index ba91e96..0481f4f 100644 --- a/src/org/traccar/client/Protocol.java +++ b/src/org/traccar/client/Protocol.java @@ -28,7 +28,7 @@ public class Protocol { /** * Format device id message */ - public static String createId(String id) { + public static String createLoginMessage(String id) { StringBuilder s = new StringBuilder("$PGID,"); Formatter f = new Formatter(s, Locale.ENGLISH); @@ -47,9 +47,9 @@ public class Protocol { /** * Format location message */ - public static String createNmea(Location l) { + public static String createLocationMessage(Location l) { StringBuilder s = new StringBuilder("$GPRMC,"); - Formatter f = new Formatter(s, Locale.ENGLISH); // Should use DecimalFormat instead + Formatter f = new Formatter(s, Locale.ENGLISH); f.format("%1$tH%1$tM%1$tS.%1$tL,A,", l.getTime()); diff --git a/src/org/traccar/client/StatusActivity.java b/src/org/traccar/client/StatusActivity.java new file mode 100644 index 0000000..29d4eed --- /dev/null +++ b/src/org/traccar/client/StatusActivity.java @@ -0,0 +1,88 @@ +/* + * Copyright 2012 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.text.DateFormat; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +import android.app.ListActivity; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.widget.ArrayAdapter; + +public class StatusActivity extends ListActivity { + + private static final List messages = new LinkedList(); + private static final Set> adapters = new HashSet>(); + + private static void notifyAdapters() { + for (ArrayAdapter adapter : adapters) { + adapter.notifyDataSetChanged(); + } + } + + public static void addMessage(String message) { + DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT); + message = format.format(new Date()) + " - " + message; + messages.add(message); + notifyAdapters(); + } + + public static void clearMessages() { + messages.clear(); + notifyAdapters(); + } + + private ArrayAdapter adapter; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.status); + adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, android.R.id.text1, messages); + setListAdapter(adapter); + adapters.add(adapter); + } + + @Override + protected void onDestroy() { + adapters.remove(adapter); + super.onDestroy(); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.status, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.clear) { + clearMessages(); + return true; + } + return super.onOptionsItemSelected(item); + } + +} diff --git a/src/org/traccar/client/TraccarActivity.java b/src/org/traccar/client/TraccarActivity.java index e1a4ff0..5dc9bc5 100644 --- a/src/org/traccar/client/TraccarActivity.java +++ b/src/org/traccar/client/TraccarActivity.java @@ -15,209 +15,106 @@ */ package org.traccar.client; -import java.util.*; -import android.app.*; -import android.content.*; -import android.os.*; -import android.text.*; -import android.text.method.*; -import android.text.util.*; -import android.view.*; -import android.widget.*; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.os.Bundle; +import android.preference.PreferenceActivity; import android.telephony.TelephonyManager; - -/** - * Global parameters - */ -class Traccar { - public static final String EXTRA_ADDRESS = "address"; - public static final String EXTRA_PORT = "port"; - public static final String EXTRA_PERIOD = "period"; - public static final String EXTRA_STATUS = "status"; - - public static final String DEFAULT_ADDRESS = "193.193.165.166"; - public static final String DEFAULT_PORT = "20100"; - public static final String DEFAULT_PERIOD = "60"; - - public static final String TRACCAR_SETTINGS = "traccar_settings"; - - public static final long RECONNECT_DELAY = 10 * 1000; - public static final int SOCKET_TIMEOUT = 2000; - - public static final String MSG_UPDATE = "org.traccar.client.MSG_UPDATE"; - public static final String MSG_SERVICE_CONFIG = "org.traccar.client.MSG_SERVICE_CONFIG"; - public static final String MSG_SERVICE_STATUS = "org.traccar.client.SERVICE_STATUS"; - public static final String MSG_CONNECTION_STATUS = "org.traccar.client.CONNECTION_STATUS"; - - public static final String STATUS_STOPPED = "Stopped"; - public static final String STATUS_RUNNING = "Running"; - - public static final String STATUS_CONNECTED = "Connected"; - public static final String STATUS_DISCONNECTED = "Disconnected"; -} +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; /** * Main user interface */ -public class TraccarActivity extends Activity { +@SuppressWarnings("deprecation") +public class TraccarActivity extends PreferenceActivity { - private EditText editAddress; - private EditText editPort; - private EditText editPeriod; - private EditText editDevice; - private EditText editService; - private EditText editConnection; - private ToggleButton button; + public static final String KEY_ID = "id"; + public static final String KEY_ADDRESS = "address"; + public static final String KEY_PORT = "port"; + public static final String KEY_INTERVAL = "interval"; + public static final String KEY_DEBUG = "debug"; + public static final String KEY_STATUS = "status"; - public boolean isServiceRunning() { - ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); - List services = activityManager.getRunningServices(Integer.MAX_VALUE); - for (ActivityManager.RunningServiceInfo runningServiceInfo : services) { - if (runningServiceInfo.service.getClassName().equals(TraccarService.class.getName())){ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + initPreferences(); + } + + @Override + protected void onResume() { + super.onResume(); + getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener( + preferenceChangeListener); + } + + @Override + protected void onPause() { + getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener( + preferenceChangeListener); + super.onPause(); + } + + OnSharedPreferenceChangeListener preferenceChangeListener = new OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + if (key.equals(KEY_STATUS)) { + if (sharedPreferences.getBoolean(KEY_STATUS, false)) { + startService(new Intent(TraccarActivity.this, TraccarService.class)); + } else { + stopService(new Intent(TraccarActivity.this, TraccarService.class)); + } + } + } + }; + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main, menu); + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.status) { + startActivity(new Intent(this, StatusActivity.class)); + return true; + } else if (item.getItemId() == R.id.about) { + startActivity(new Intent(this, AboutActivity.class)); + return true; + } + return super.onOptionsItemSelected(item); + } + + private boolean isServiceRunning() { + ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if (TraccarService.class.getName().equals(service.service.getClassName())) { return true; } } return false; } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.main); + private void initPreferences() { - // DO SOMETHING WITH IT - try { - StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); - StrictMode.setThreadPolicy(policy); - } catch(Throwable e) { - } - - // Bind elements - editAddress = (EditText) findViewById(R.id.edit_address); - editPort = (EditText) findViewById(R.id.edit_port); - editPeriod = (EditText) findViewById(R.id.edit_period); - editDevice = (EditText) findViewById(R.id.edit_device); - editService = (EditText) findViewById(R.id.edit_service); - editConnection = (EditText) findViewById(R.id.edit_connection); - button = (ToggleButton) findViewById(R.id.button); - - // Set device identifier TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); - editDevice.setText(telephonyManager.getDeviceId()); + String id = telephonyManager.getDeviceId(); - editService.setText(Traccar.STATUS_STOPPED); - editConnection.setText(Traccar.STATUS_DISCONNECTED); - button.setChecked(isServiceRunning()); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - //super.onCreateOptionsMenu(menu); - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId() == R.id.about){ - showAboutDialog(); - return true; - } - return false; - } - - public void showAboutDialog() { - TextView message = new TextView(this); - SpannableString str = new SpannableString(getString(R.string.about_text)); - Linkify.addLinks(str, Linkify.WEB_URLS); - message.setText(str); - message.setMovementMethod(LinkMovementMethod.getInstance()); - int padding = (int) (10 * getResources().getDisplayMetrics().scaledDensity); - message.setPadding(padding, padding, padding, padding); + SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences(); - AlertDialog.Builder dialog = new AlertDialog.Builder(this); - dialog.setTitle(R.string.about_option); - dialog.setView(message); - dialog.setPositiveButton(R.string.about_close, null); - dialog.show(); + sharedPreferences.edit().putString(KEY_ID, id).commit(); + findPreference(KEY_ID).setSummary(id); + + sharedPreferences.edit().putBoolean(KEY_STATUS, isServiceRunning()).commit(); } - private BroadcastReceiver serviceConfigReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - editAddress.setText(intent.getStringExtra(Traccar.EXTRA_ADDRESS)); - editPort.setText(String.valueOf(intent.getIntExtra(Traccar.EXTRA_PORT, 0))); - editPeriod.setText(String.valueOf(intent.getIntExtra(Traccar.EXTRA_PERIOD, 0))); - } - }; - - private BroadcastReceiver serviceStatusReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - editService.setText(intent.getStringExtra(Traccar.EXTRA_STATUS)); - } - }; - - private BroadcastReceiver connectionStatusReceiver = new BroadcastReceiver() { - public void onReceive(Context context, Intent intent) { - editConnection.setText(intent.getStringExtra(Traccar.EXTRA_STATUS)); - } - }; - - @Override - protected void onStart() { - super.onStart(); - loadSettings(); - - // Register receivers - registerReceiver(serviceConfigReceiver, new IntentFilter(Traccar.MSG_SERVICE_CONFIG)); - registerReceiver(serviceStatusReceiver, new IntentFilter(Traccar.MSG_SERVICE_STATUS)); - registerReceiver(connectionStatusReceiver, new IntentFilter(Traccar.MSG_CONNECTION_STATUS)); - - // Request update - sendBroadcast(new Intent(Traccar.MSG_UPDATE)); - } - - @Override - protected void onStop() { - super.onStop(); - saveSettings(); - - // Unregister receivers - unregisterReceiver(serviceConfigReceiver); - unregisterReceiver(serviceStatusReceiver); - unregisterReceiver(connectionStatusReceiver); - } - - public void onButtonClick(View v) { - if (button.isChecked()) { - try { - Intent serviceIntent = new Intent(this, TraccarService.class); - serviceIntent.putExtra(Traccar.EXTRA_ADDRESS, editAddress.getText().toString()); - serviceIntent.putExtra(Traccar.EXTRA_PORT, Integer.parseInt(editPort.getText().toString())); - serviceIntent.putExtra(Traccar.EXTRA_PERIOD, Integer.parseInt(editPeriod.getText().toString())); - startService(serviceIntent); - } catch (NumberFormatException e) { - Toast.makeText(this, R.string.error_input, Toast.LENGTH_SHORT).show(); - button.setChecked(false); - } - } else { - stopService(new Intent(this, TraccarService.class)); - } - } - - public void saveSettings() { - SharedPreferences settings = getSharedPreferences(Traccar.TRACCAR_SETTINGS, 0); - SharedPreferences.Editor editor = settings.edit(); - editor.putString(Traccar.EXTRA_ADDRESS, editAddress.getText().toString()); - editor.putString(Traccar.EXTRA_PORT, editPort.getText().toString()); - editor.putString(Traccar.EXTRA_PERIOD, editPeriod.getText().toString()); - editor.commit(); - } - - public void loadSettings() { - SharedPreferences settings = getSharedPreferences(Traccar.TRACCAR_SETTINGS, 0); - editAddress.setText(settings.getString(Traccar.EXTRA_ADDRESS, Traccar.DEFAULT_ADDRESS)); - editPort.setText(settings.getString(Traccar.EXTRA_PORT, Traccar.DEFAULT_PORT)); - editPeriod.setText(settings.getString(Traccar.EXTRA_PERIOD, Traccar.DEFAULT_PERIOD)); - } } diff --git a/src/org/traccar/client/TraccarService.java b/src/org/traccar/client/TraccarService.java index e86cc90..16c02f3 100644 --- a/src/org/traccar/client/TraccarService.java +++ b/src/org/traccar/client/TraccarService.java @@ -16,133 +16,193 @@ package org.traccar.client; import android.app.Service; -import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; -import android.telephony.TelephonyManager; +import android.preference.PreferenceManager; /** * Background service */ -public class TraccarService extends Service implements LocationListener { +public class TraccarService extends Service { - private int period; - private String deviceId; + public static final long RECONNECT_DELAY = 10 * 1000; + + private String id; + private String address; + private int port; + private int interval; + + private Handler handler; private Connection connection; - private LocationManager locationManager; + LocationManager locationManager; - /* - * Location methods - */ - - @Override - public void onLocationChanged(Location location) { - connection.send(Protocol.createNmea(location)); + private void statusMessage(int message) { + StatusActivity.addMessage(getString(message)); } @Override - public void onProviderDisabled(String provider) { + public void onCreate() { + statusMessage(R.string.status_service_create); + + handler = new Handler(); + connection = new Connection(connectionHandler); } - @Override - public void onProviderEnabled(String provider) { - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) { - } - - /* - * Status methods - */ - - private String status; - - private void setStatus(String status) { - if (!status.equals(this.status)) { - this.status = status; - Intent intent = new Intent(Traccar.MSG_SERVICE_STATUS); - intent.putExtra(Traccar.EXTRA_STATUS, status); - sendBroadcast(intent); - } - } - - private BroadcastReceiver updateReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // Send config - intent = new Intent(Traccar.MSG_SERVICE_CONFIG); - intent.putExtra(Traccar.EXTRA_ADDRESS, connection.getAddress()); - intent.putExtra(Traccar.EXTRA_PORT, connection.getPort()); - intent.putExtra(Traccar.EXTRA_PERIOD, period); - sendBroadcast(intent); - - // Send service status - intent = new Intent(Traccar.MSG_SERVICE_STATUS); - intent.putExtra(Traccar.EXTRA_STATUS, status); - sendBroadcast(intent); - - // Send connection status - intent = new Intent(Traccar.MSG_CONNECTION_STATUS); - intent.putExtra(Traccar.EXTRA_STATUS, connection.getStatus()); - sendBroadcast(intent); - } - }; - - /* - * Service methods - */ - @Override public int onStartCommand(Intent intent, int flags, int startId) { - // Read device id - TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); - deviceId = telephonyManager.getDeviceId(); + statusMessage(R.string.status_service_start); - // Create connection - connection = new Connection( - intent.getStringExtra(Traccar.EXTRA_ADDRESS), - intent.getIntExtra(Traccar.EXTRA_PORT, 0), - Protocol.createId(deviceId)); - connection.setContext(this); - connection.connect(); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener); + updateServerPreferences(sharedPreferences); + updateIntervalPreferences(sharedPreferences); + updateOtherPreferences(sharedPreferences); + + connection.close(); + connection.connect(address, port); - // Request location updates locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); - period = intent.getIntExtra(Traccar.EXTRA_PERIOD, 0); - locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, period * 1000, 0, this); + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval * 1000, 0, locationListener); - // Report status - registerReceiver(updateReceiver, new IntentFilter(Traccar.MSG_UPDATE)); - setStatus(Traccar.STATUS_RUNNING); return START_STICKY; } - @Override - public void onDestroy() { - // Close connection - if (connection != null) { - connection.close(); - } - - // Stop location updates - if (locationManager != null) { - locationManager.removeUpdates(this); - } - - // Report status - unregisterReceiver(updateReceiver); - setStatus(Traccar.STATUS_STOPPED); - } - @Override public IBinder onBind(Intent intent) { return null; } + + @Override + public void onDestroy() { + statusMessage(R.string.status_service_destroy); + + locationManager.removeUpdates(locationListener); + + handler.removeCallbacksAndMessages(null); + connection.close(); + connection = null; + + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); + sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener); + } + + private boolean updateServerPreferences(SharedPreferences sharedPreferences) { + boolean changed = false; + + String address = sharedPreferences.getString(TraccarActivity.KEY_ADDRESS, null); + if (!address.equals(this.address)) { + this.address = address; + changed = true; + } + + int port = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_PORT, null)); + if (port != this.port) { + this.port = port; + changed = true; + } + + return changed; + } + + private boolean updateIntervalPreferences(SharedPreferences sharedPreferences) { + boolean changed = false; + + int interval = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_INTERVAL, null)); + if (interval != this.interval) { + this.interval = interval; + changed = true; + } + + return changed; + } + + private boolean updateOtherPreferences(SharedPreferences sharedPreferences) { + id = sharedPreferences.getString(TraccarActivity.KEY_ID, null); + return false; + } + + private void reconnect() { + handler.postDelayed(new Runnable() { + @Override + public void run() { + connection.close(); + connection.connect(address, port); + } + }, RECONNECT_DELAY); + } + + private Connection.ConnectionHandler connectionHandler = new Connection.ConnectionHandler() { + + @Override + public void onConnected(boolean result) { + if (result) { + statusMessage(R.string.status_connection_success); + connection.send(Protocol.createLoginMessage(id)); + } else { + statusMessage(R.string.status_connection_fail); + reconnect(); + } + } + + @Override + public void onSent(boolean result) { + if (!result) { + statusMessage(R.string.status_send_fail); + reconnect(); + } + } + + }; + + private LocationListener locationListener = new LocationListener() { + + @Override + public void onLocationChanged(Location location) { + statusMessage(R.string.status_location_update); + connection.send(Protocol.createLocationMessage(location)); + } + + @Override + public void onProviderDisabled(String provider) { + } + + @Override + public void onProviderEnabled(String provider) { + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + } + + }; + + OnSharedPreferenceChangeListener preferenceChangeListener = new OnSharedPreferenceChangeListener() { + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + statusMessage(R.string.status_preference_update); + + if (updateServerPreferences(sharedPreferences)) { + connection.close(); + connection.connect(address, port); + } + + if (updateIntervalPreferences(sharedPreferences)) { + locationManager.removeUpdates(locationListener); + locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval * 1000, 0, locationListener); + } + + updateOtherPreferences(sharedPreferences); + } + + }; + }