Этот коммит содержится в:
Anton Tananaev
2013-01-13 16:44:28 +13:00
родитель 7e11615de2
Коммит 7fdd7e5feb
5 изменённых файлов: 253 добавлений и 131 удалений
+45
Просмотреть файл
@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference
android:key="id"
android:title="@string/settings_id_title"
android:enabled="false" />
<EditTextPreference
android:key="address"
android:title="@string/settings_address_title"
android:summary="@string/settings_address_summary"
android:defaultValue="demo.traccar.org" />
<EditTextPreference
android:key="port"
android:title="@string/settings_port_title"
android:summary="@string/settings_port_summary"
android:numeric="integer"
android:defaultValue="5005" />
<EditTextPreference
android:key="interval"
android:title="@string/settings_interval_title"
android:summary="@string/settings_interval_summary"
android:numeric="integer"
android:defaultValue="60" />
<CheckBoxPreference
android:key="debug"
android:title="@string/settings_debug_title"
android:summary="@string/settings_debug_summary"
android:defaultValue="true"
android:enabled="false" />
<SwitchPreference
android:key="status"
android:title="@string/settings_status_title"
android:summaryOff="@string/settings_status_off_summary"
android:summaryOn="@string/settings_status_on_summary"
android:switchTextOff="@string/settings_status_off"
android:switchTextOn="@string/settings_status_on"
android:defaultValue="false" />
</PreferenceScreen>
+3 -5
Просмотреть файл
@@ -33,13 +33,11 @@
android:defaultValue="true" android:defaultValue="true"
android:enabled="false" /> android:enabled="false" />
<SwitchPreference <CheckBoxPreference
android:key="status" android:key="status"
android:title="@string/settings_status_title" android:title="@string/settings_status_title"
android:summaryOff="@string/settings_status_off_summary" android:summaryOff="@string/settings_status_off"
android:summaryOn="@string/settings_status_on_summary" android:summaryOn="@string/settings_status_on"
android:switchTextOff="@string/settings_status_off"
android:switchTextOn="@string/settings_status_on"
android:defaultValue="false" /> android:defaultValue="false" />
</PreferenceScreen> </PreferenceScreen>
+118
Просмотреть файл
@@ -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<String> 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<String>();
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();
}
}
}
+38 -14
Просмотреть файл
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.io.OutputStream;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.net.SocketAddress;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.util.Log; import android.util.Log;
@@ -47,44 +46,64 @@ public class Connection implements Closeable {
private Socket socket; private Socket socket;
private OutputStream socketStream; private OutputStream socketStream;
private boolean closed;
private boolean busy;
public boolean isClosed() {
return closed;
}
public boolean isBusy() {
return busy;
}
public Connection(ConnectionHandler handler) { public Connection(ConnectionHandler handler) {
this.handler = handler; this.handler = handler;
closed = false;
busy = false;
} }
public void connect(String address, int port) { public void connect(final String address, final int port) {
busy = true;
new AsyncTask<SocketAddress, Void, Boolean>() { new AsyncTask<Void, Void, Boolean>() {
@Override @Override
protected Boolean doInBackground(SocketAddress... params) { protected Boolean doInBackground(Void... params) {
try { try {
socket = new Socket(); socket = new Socket();
socket.connect(params[0]); socket.connect(new InetSocketAddress(address, port));
socket.setSoTimeout(SOCKET_TIMEOUT); socket.setSoTimeout(SOCKET_TIMEOUT);
socketStream = socket.getOutputStream(); socketStream = socket.getOutputStream();
handler.onConnected(true); return true;
} catch (Exception e) { } catch (Exception e) {
close(); Log.w(LOG_TAG, e.getMessage());
return false; return false;
} }
return true;
} }
@Override @Override
protected void onCancelled(Boolean result) { protected void onCancelled(Boolean result) {
if (!closed) {
busy = false;
handler.onConnected(false); handler.onConnected(false);
} }
}
@Override @Override
protected void onPostExecute(Boolean result) { protected void onPostExecute(Boolean result) {
if (!closed) {
busy = false;
handler.onConnected(result); handler.onConnected(result);
} }
}
}.execute(InetSocketAddress.createUnresolved(address, port)); }.execute();
} }
public void send(String message) { public void send(String message) {
busy = true;
new AsyncTask<String, Void, Boolean>() { new AsyncTask<String, Void, Boolean>() {
@@ -93,22 +112,28 @@ public class Connection implements Closeable {
try { try {
socketStream.write(params[0].getBytes()); socketStream.write(params[0].getBytes());
socketStream.flush(); socketStream.flush();
return true;
} catch (Exception e) { } catch (Exception e) {
close(); Log.w(LOG_TAG, e.getMessage());
return false; return false;
} }
return true;
} }
@Override @Override
protected void onCancelled(Boolean result) { protected void onCancelled(Boolean result) {
if (!closed) {
busy = false;
handler.onSent(false); handler.onSent(false);
} }
}
@Override @Override
protected void onPostExecute(Boolean result) { protected void onPostExecute(Boolean result) {
if (!closed) {
busy = false;
handler.onSent(result); handler.onSent(result);
} }
}
}.execute(message); }.execute(message);
@@ -116,14 +141,13 @@ public class Connection implements Closeable {
@Override @Override
public void close() { public void close() {
closed = true;
try { try {
if (socketStream != null) { if (socketStream != null) {
socketStream.close(); socketStream.close();
socketStream = null;
} }
if (socket != null) { if (socket != null) {
socket.close(); socket.close();
socket = null;
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(LOG_TAG, e.getMessage()); Log.e(LOG_TAG, e.getMessage());
+43 -106
Просмотреть файл
@@ -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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.LocationListener;
import android.location.LocationManager; import android.location.LocationManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
@@ -33,45 +32,39 @@ import android.preference.PreferenceManager;
*/ */
public class TraccarService extends Service { public class TraccarService extends Service {
public static final long RECONNECT_DELAY = 10 * 1000;
private String id; private String id;
private String address; private String address;
private int port; private int port;
private int interval; private int interval;
private Handler handler; private SharedPreferences sharedPreferences;
private Connection connection; private ClientController clientController;
LocationManager locationManager; private LocationManager locationManager;
private void statusMessage(int message) {
StatusActivity.addMessage(getString(message));
}
@Override @Override
public void onCreate() { public void onCreate() {
statusMessage(R.string.status_service_create); StatusActivity.addMessage(getString((R.string.status_service_create)));
handler = new Handler();
connection = new Connection(connectionHandler);
} }
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { 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 = PreferenceManager.getDefaultSharedPreferences(this);
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener);
updateServerPreferences(sharedPreferences);
updateIntervalPreferences(sharedPreferences);
updateOtherPreferences(sharedPreferences);
connection.close(); address = sharedPreferences.getString(TraccarActivity.KEY_ADDRESS, null);
connection.connect(address, port); 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 = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval * 1000, 0, locationListener); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval * 1000, 0, locationListener);
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener);
return START_STICKY; return START_STICKY;
} }
@@ -82,92 +75,21 @@ public class TraccarService extends Service {
@Override @Override
public void onDestroy() { public void onDestroy() {
statusMessage(R.string.status_service_destroy); StatusActivity.addMessage(getString((R.string.status_service_destroy)));
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
locationManager.removeUpdates(locationListener); locationManager.removeUpdates(locationListener);
handler.removeCallbacksAndMessages(null); clientController.stop();
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() { private LocationListener locationListener = new LocationListener() {
@Override @Override
public void onLocationChanged(Location location) { public void onLocationChanged(Location location) {
statusMessage(R.string.status_location_update); StatusActivity.addMessage(getString((R.string.status_location_update)));
connection.send(Protocol.createLocationMessage(location)); clientController.setNewLocation(Protocol.createLocationMessage(location));
} }
@Override @Override
@@ -188,19 +110,34 @@ public class TraccarService extends Service {
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
statusMessage(R.string.status_preference_update); StatusActivity.addMessage(getString((R.string.status_preference_update)));
if (updateServerPreferences(sharedPreferences)) { boolean serverChanged = false;
connection.close();
connection.connect(address, port); 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.removeUpdates(locationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval * 1000, 0, 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));
}
} }
}; };