From 7fdd7e5feb6023177d39291568117d2659bcd972 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 13 Jan 2013 16:44:28 +1300 Subject: [PATCH] Rewrite network controller --- res/xml-v14/preferences.xml | 45 ++++++ res/xml/preferences.xml | 8 +- src/org/traccar/client/ClientController.java | 118 +++++++++++++++ src/org/traccar/client/Connection.java | 64 +++++--- src/org/traccar/client/TraccarService.java | 149 ++++++------------- 5 files changed, 253 insertions(+), 131 deletions(-) create mode 100644 res/xml-v14/preferences.xml create mode 100644 src/org/traccar/client/ClientController.java diff --git a/res/xml-v14/preferences.xml b/res/xml-v14/preferences.xml new file mode 100644 index 0000000..3cb1472 --- /dev/null +++ b/res/xml-v14/preferences.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + diff --git a/res/xml/preferences.xml b/res/xml/preferences.xml index 3cb1472..d0df23e 100644 --- a/res/xml/preferences.xml +++ b/res/xml/preferences.xml @@ -33,13 +33,11 @@ android:defaultValue="true" android:enabled="false" /> - diff --git a/src/org/traccar/client/ClientController.java b/src/org/traccar/client/ClientController.java new file mode 100644 index 0000000..5c7c856 --- /dev/null +++ b/src/org/traccar/client/ClientController.java @@ -0,0 +1,118 @@ +/* + * Copyright 2013 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.LinkedList; +import java.util.Queue; + +import android.content.Context; +import android.os.Handler; + + +public class ClientController implements Connection.ConnectionHandler { + + public static final long RECONNECT_DELAY = 10 * 1000; + + private Context context; + + private Handler handler; + private Queue messageQueue; + + private Connection connection; + + private String address; + private int port; + private String loginMessage; + + public ClientController(Context context, String address, int port, String loginMessage) { + this.context = context; + messageQueue = new LinkedList(); + this.address = address; + this.port = port; + this.loginMessage = loginMessage; + } + + public void start() { + handler = new Handler(); + connection = new Connection(this); + connection.connect(address, port); + } + + public void stop() { + connection.close(); + handler.removeCallbacksAndMessages(null); + } + + private void reconnect() { + handler.removeCallbacksAndMessages(null); + connection.close(); + connection = new Connection(this); + connection.connect(address, port); + } + + private void delayedReconnect() { + connection.close(); + handler.postDelayed(new Runnable() { + @Override + public void run() { + connection = new Connection(ClientController.this); + connection.connect(address, port); + } + }, RECONNECT_DELAY); + } + + public void setNewServer(String address, int port) { + this.address = address; + this.port = port; + reconnect(); + } + + public void setNewLogin(String loginMessage) { + this.loginMessage = loginMessage; + reconnect(); + } + + public void setNewLocation(String locationMessage) { + messageQueue.offer(locationMessage); + if (!connection.isClosed() && !connection.isBusy()) { + connection.send(messageQueue.poll()); + } + } + + @Override + public void onConnected(boolean result) { + if (result) { + StatusActivity.addMessage(context.getString((R.string.status_connection_success))); + connection.send(loginMessage); + } else { + StatusActivity.addMessage(context.getString((R.string.status_connection_fail))); + delayedReconnect(); + } + } + + @Override + public void onSent(boolean result) { + if (result) { + if (!messageQueue.isEmpty()) { + connection.send(messageQueue.poll()); + } + } else { + StatusActivity.addMessage(context.getString((R.string.status_send_fail))); + delayedReconnect(); + } + } + +} diff --git a/src/org/traccar/client/Connection.java b/src/org/traccar/client/Connection.java index 401ef34..0d4abd8 100644 --- a/src/org/traccar/client/Connection.java +++ b/src/org/traccar/client/Connection.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2012 - 2013 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. @@ -19,7 +19,6 @@ import java.io.Closeable; import java.io.OutputStream; import java.net.InetSocketAddress; import java.net.Socket; -import java.net.SocketAddress; import android.os.AsyncTask; import android.util.Log; @@ -47,44 +46,64 @@ public class Connection implements Closeable { private Socket socket; private OutputStream socketStream; - public Connection(ConnectionHandler handler) { - this.handler = handler; + private boolean closed; + private boolean busy; + + public boolean isClosed() { + return closed; } - public void connect(String address, int port) { + public boolean isBusy() { + return busy; + } - new AsyncTask() { + public Connection(ConnectionHandler handler) { + this.handler = handler; + closed = false; + busy = false; + } + + public void connect(final String address, final int port) { + busy = true; + + new AsyncTask() { @Override - protected Boolean doInBackground(SocketAddress... params) { + protected Boolean doInBackground(Void... params) { try { socket = new Socket(); - socket.connect(params[0]); + socket.connect(new InetSocketAddress(address, port)); socket.setSoTimeout(SOCKET_TIMEOUT); socketStream = socket.getOutputStream(); - handler.onConnected(true); + return true; } catch (Exception e) { - close(); + Log.w(LOG_TAG, e.getMessage()); return false; } - return true; } @Override protected void onCancelled(Boolean result) { - handler.onConnected(false); + if (!closed) { + busy = false; + handler.onConnected(false); + } } @Override protected void onPostExecute(Boolean result) { - handler.onConnected(result); + if (!closed) { + busy = false; + handler.onConnected(result); + } } - }.execute(InetSocketAddress.createUnresolved(address, port)); + }.execute(); } public void send(String message) { + busy = true; new AsyncTask() { @@ -93,21 +112,27 @@ public class Connection implements Closeable { try { socketStream.write(params[0].getBytes()); socketStream.flush(); + return true; } catch (Exception e) { - close(); + Log.w(LOG_TAG, e.getMessage()); return false; } - return true; } @Override protected void onCancelled(Boolean result) { - handler.onSent(false); + if (!closed) { + busy = false; + handler.onSent(false); + } } @Override protected void onPostExecute(Boolean result) { - handler.onSent(result); + if (!closed) { + busy = false; + handler.onSent(result); + } } }.execute(message); @@ -116,14 +141,13 @@ public class Connection implements Closeable { @Override public void close() { + closed = true; try { if (socketStream != null) { socketStream.close(); - socketStream = null; } if (socket != null) { socket.close(); - socket = null; } } catch (Exception e) { Log.e(LOG_TAG, e.getMessage()); diff --git a/src/org/traccar/client/TraccarService.java b/src/org/traccar/client/TraccarService.java index 16c02f3..4d2e4e3 100644 --- a/src/org/traccar/client/TraccarService.java +++ b/src/org/traccar/client/TraccarService.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 Anton Tananaev (anton.tananaev@gmail.com) + * Copyright 2012 - 2013 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. @@ -24,7 +24,6 @@ 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.preference.PreferenceManager; @@ -33,45 +32,39 @@ import android.preference.PreferenceManager; */ public class TraccarService extends Service { - 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; - LocationManager locationManager; - - private void statusMessage(int message) { - StatusActivity.addMessage(getString(message)); - } + private SharedPreferences sharedPreferences; + private ClientController clientController; + private LocationManager locationManager; @Override public void onCreate() { - statusMessage(R.string.status_service_create); - - handler = new Handler(); - connection = new Connection(connectionHandler); + StatusActivity.addMessage(getString((R.string.status_service_create))); } @Override public int onStartCommand(Intent intent, int flags, int startId) { - statusMessage(R.string.status_service_start); + StatusActivity.addMessage(getString((R.string.status_service_start))); - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener); - updateServerPreferences(sharedPreferences); - updateIntervalPreferences(sharedPreferences); - updateOtherPreferences(sharedPreferences); + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - connection.close(); - connection.connect(address, port); + address = sharedPreferences.getString(TraccarActivity.KEY_ADDRESS, null); + port = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_PORT, null)); + interval = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_INTERVAL, null)); + id = sharedPreferences.getString(TraccarActivity.KEY_ID, null); + + clientController = new ClientController(this, address, port, Protocol.createLoginMessage(id)); + clientController.start(); locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval * 1000, 0, locationListener); + sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener); + return START_STICKY; } @@ -82,92 +75,21 @@ public class TraccarService extends Service { @Override public void onDestroy() { - statusMessage(R.string.status_service_destroy); + StatusActivity.addMessage(getString((R.string.status_service_destroy))); + + sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener); locationManager.removeUpdates(locationListener); - handler.removeCallbacksAndMessages(null); - connection.close(); - connection = null; - - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); - sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener); + clientController.stop(); } - 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)); + StatusActivity.addMessage(getString((R.string.status_location_update))); + clientController.setNewLocation(Protocol.createLocationMessage(location)); } @Override @@ -188,19 +110,34 @@ public class TraccarService extends Service { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - statusMessage(R.string.status_preference_update); + StatusActivity.addMessage(getString((R.string.status_preference_update))); - if (updateServerPreferences(sharedPreferences)) { - connection.close(); - connection.connect(address, port); + boolean serverChanged = false; + + if (key.equals(TraccarActivity.KEY_ADDRESS)) { + address = sharedPreferences.getString(TraccarActivity.KEY_ADDRESS, null); + serverChanged = true; } - if (updateIntervalPreferences(sharedPreferences)) { + if (key.equals(TraccarActivity.KEY_PORT)) { + port = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_PORT, null)); + serverChanged = true; + } + + if (serverChanged) { + clientController.setNewServer(address, port); + } + + if (key.equals(TraccarActivity.KEY_INTERVAL)) { + interval = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_INTERVAL, null)); locationManager.removeUpdates(locationListener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval * 1000, 0, locationListener); } - updateOtherPreferences(sharedPreferences); + if (key.equals(TraccarActivity.KEY_ID)) { + id = sharedPreferences.getString(TraccarActivity.KEY_ID, null); + clientController.setNewLogin(Protocol.createLoginMessage(id)); + } } };