Сравнить коммиты

...
40 Коммитов
Автор SHA1 Сообщение Дата
Anton Tananaev 8027c5be9f Update app version number 2015-08-16 12:33:25 +12:00
Anton Tananaev 6084bfdfbe Implement optional foreground service 2015-08-16 12:15:04 +12:00
Anton Tananaev b560577d96 Simplify position provider class 2015-08-15 21:55:53 +12:00
Anton Tananaev 92137c83bd Move wake lock to controller 2015-08-15 20:53:51 +12:00
Anton Tananaev 3617700351 Add wake lock to receiver 2015-08-14 19:49:17 +12:00
Anton Tananaev c803eb7bff Reduce default send frequency 2015-08-14 19:16:17 +12:00
Anton Tananaev 7fe765d124 Re-implement status logging 2015-08-14 18:52:28 +12:00
Anton Tananaev 3235229d1e Implement connectivity listener 2015-08-14 16:53:43 +12:00
Anton Tananaev 25e035e59d Implement buffering logic 2015-08-13 16:00:57 +12:00
Anton Tananaev b63bf4779e Implement async database calls 2015-08-13 13:29:03 +12:00
Anton Tananaev 2cf1213535 Create sync version of request 2015-08-13 11:58:59 +12:00
Anton Tananaev 03266a8c78 Implement database for buffer 2015-08-13 11:49:46 +12:00
Anton Tananaev 3782fd0003 Rename id to device id 2015-08-13 10:53:53 +12:00
Anton Tananaev fc83e7525a Start service as sticky 2015-08-12 22:30:39 +12:00
Anton Tananaev 596ede019c Use position in formatter 2015-08-12 22:14:24 +12:00
Anton Tananaev 2593ec7d2e Add port change dialog box 2015-08-12 21:53:39 +12:00
Anton Tananaev 14894c294e Change default port to 5055 2015-08-12 21:28:03 +12:00
Anton Tananaev fe9132e46a Remove old unused code 2015-08-12 20:32:42 +12:00
Anton Tananaev 26bc00f5fd Create new tracking controller 2015-08-12 20:31:09 +12:00
Anton Tananaev d5e2a3155c Refactor tracking service more 2015-08-12 20:13:04 +12:00
Anton Tananaev d49bc6ad28 Remove extended client protocol 2015-08-12 20:06:18 +12:00
Anton Tananaev c008c5f65e Refactor position provider class 2015-08-12 20:00:21 +12:00
Anton Tananaev e4f167f17b Create position model class 2015-08-12 19:52:49 +12:00
Anton Tananaev 346ad93ca0 Minor cleanup of service class 2015-08-12 19:44:04 +12:00
Anton Tananaev 3f4663c570 Remove preferences listener from service 2015-08-12 19:41:38 +12:00
Anton Tananaev 7396e9c436 Rename tracking service class 2015-08-12 19:39:10 +12:00
Anton Tananaev 59037d5fb1 Rename main activity class 2015-08-12 19:36:31 +12:00
Anton Tananaev 5591bec9e9 Minor activity class cleanup 2015-08-12 19:29:50 +12:00
Anton Tananaev e4151ac228 Disable settings when running 2015-08-12 19:28:47 +12:00
Anton Tananaev 630cf8eb86 Rename protocol formatter class 2015-08-12 19:17:18 +12:00
Anton Tananaev 222497d6ff Add new protocol formatter 2015-08-12 19:11:10 +12:00
Anton Tananaev 0f9645120b Use robolectric for unit tests 2015-08-12 16:54:47 +12:00
Anton Tananaev 9ffc0aa773 Rename main app module 2015-08-12 13:52:38 +12:00
Anton Tananaev 9d93c1d001 Update gradle wrapper props 2015-08-12 13:42:26 +12:00
Anton Tananaev ac6f648062 Create dummy request manager 2015-08-12 13:42:08 +12:00
Anton Tananaev 06c741e6b5 Add missing gradle files 2015-08-11 13:38:24 +12:00
Anton Tananaev ceaf4d526c Update gradle files 2015-08-11 13:12:48 +12:00
Anton Tananaev 6d4d0d74cd Add gradle wrapper properties 2015-08-11 13:05:55 +12:00
Anton Tananaev 0186b8fc6e Update git ignore list 2015-08-11 12:54:38 +12:00
Anton Tananaev 16c634b9f5 Cleanup project repository 2015-08-11 11:50:29 +12:00
71 изменённых файлов: 1320 добавлений и 1384 удалений
+6 -3
Просмотреть файл
@@ -1,4 +1,7 @@
.gradle
/local.properties
/.idea/workspace.xml
.DS_Store
.idea/
local.properties
traccar-client-android.iml
app/app.iml
build/
app/build/
Generated
-1
Просмотреть файл
@@ -1 +0,0 @@
traccar-client-android
-22
Просмотреть файл
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
</project>
-3
Просмотреть файл
@@ -1,3 +0,0 @@
<component name="CopyrightManager">
<settings default="" />
</component>
-19
Просмотреть файл
@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="LOCAL" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="$APPLICATION_HOME_DIR$/gradle/gradle-2.2.1" />
<option name="gradleJvm" value="1.7" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/traccar-client" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>
-22
Просмотреть файл
@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="Android API 22 Platform" project-jdk-type="Android SDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
-9
Просмотреть файл
@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/traccar-client/traccar-client.iml" filepath="$PROJECT_DIR$/traccar-client/traccar-client.iml" />
<module fileurl="file://$PROJECT_DIR$/traccar-client-android.iml" filepath="$PROJECT_DIR$/traccar-client-android.iml" />
</modules>
</component>
</project>
Generated
-6
Просмотреть файл
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>
+4 -7
Просмотреть файл
@@ -7,8 +7,8 @@ android {
defaultConfig {
minSdkVersion 3
targetSdkVersion 22
versionCode 22
versionName "3.2"
versionCode 23
versionName "3.3"
}
signingConfigs {
@@ -23,15 +23,12 @@ android {
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.release
}
}
lintOptions {
checkReleaseBuilds false
}
}
dependencies {
testCompile 'junit:junit:4.12'
testCompile "org.robolectric:robolectric:3.0"
}
+7 -6
Просмотреть файл
@@ -5,28 +5,29 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:allowBackup="true" android:theme="@style/TraccarTheme">
<activity android:name="TraccarActivity">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="StatusActivity">
<activity android:name=".StatusActivity">
</activity>
<activity android:name="AboutActivity">
<activity android:name=".AboutActivity">
</activity>
<service android:name="TraccarService" />
<service android:name=".TrackingService" />
<receiver android:name="AutostartReceiver">
<receiver android:name=".AutostartReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
+134
Просмотреть файл
@@ -0,0 +1,134 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* 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 android.support.v4.content;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import android.util.Log;
import android.util.SparseArray;
/**
* Helper for the common pattern of implementing a {@link BroadcastReceiver}
* that receives a device wakeup event and then passes the work off
* to a {@link android.app.Service}, while ensuring that the
* device does not go back to sleep during the transition.
*
* <p>This class takes care of creating and managing a partial wake lock
* for you; you must request the {@link android.Manifest.permission#WAKE_LOCK}
* permission to use it.</p>
*
* <h3>Example</h3>
*
* <p>A {@link WakefulBroadcastReceiver} uses the method
* {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()}
* to start the service that does the work. This method is comparable to
* {@link android.content.Context#startService startService()}, except that
* the {@link WakefulBroadcastReceiver} is holding a wake lock when the service
* starts. The intent that is passed with
* {@link WakefulBroadcastReceiver#startWakefulService startWakefulService()}
* holds an extra identifying the wake lock.</p>
*
* {@sample development/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulReceiver.java complete}
*
* <p>The service (in this example, an {@link android.app.IntentService}) does
* some work. When it is finished, it releases the wake lock by calling
* {@link WakefulBroadcastReceiver#completeWakefulIntent
* completeWakefulIntent(intent)}. The intent it passes as a parameter
* is the same intent that the {@link WakefulBroadcastReceiver} originally
* passed in.</p>
*
* {@sample development/samples/Support4Demos/src/com/example/android/supportv4/content/SimpleWakefulService.java complete}
*/
public abstract class WakefulBroadcastReceiver extends BroadcastReceiver {
private static final String EXTRA_WAKE_LOCK_ID = "android.support.content.wakelockid";
private static final SparseArray<PowerManager.WakeLock> mActiveWakeLocks
= new SparseArray<PowerManager.WakeLock>();
private static int mNextId = 1;
/**
* Do a {@link android.content.Context#startService(android.content.Intent)
* Context.startService}, but holding a wake lock while the service starts.
* This will modify the Intent to hold an extra identifying the wake lock;
* when the service receives it in {@link android.app.Service#onStartCommand
* Service.onStartCommand}, it should pass back the Intent it receives there to
* {@link #completeWakefulIntent(android.content.Intent)} in order to release
* the wake lock.
*
* @param context The Context in which it operate.
* @param intent The Intent with which to start the service, as per
* {@link android.content.Context#startService(android.content.Intent)
* Context.startService}.
*/
public static ComponentName startWakefulService(Context context, Intent intent) {
synchronized (mActiveWakeLocks) {
int id = mNextId;
mNextId++;
if (mNextId <= 0) {
mNextId = 1;
}
intent.putExtra(EXTRA_WAKE_LOCK_ID, id);
ComponentName comp = context.startService(intent);
if (comp == null) {
return null;
}
PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"wake:" + comp.flattenToShortString());
wl.setReferenceCounted(false);
wl.acquire(60*1000);
mActiveWakeLocks.put(id, wl);
return comp;
}
}
/**
* Finish the execution from a previous {@link #startWakefulService}. Any wake lock
* that was being held will now be released.
*
* @param intent The Intent as originally generated by {@link #startWakefulService}.
* @return Returns true if the intent is associated with a wake lock that is
* now released; returns false if there was no wake lock specified for it.
*/
public static boolean completeWakefulIntent(Intent intent) {
final int id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0);
if (id == 0) {
return false;
}
synchronized (mActiveWakeLocks) {
PowerManager.WakeLock wl = mActiveWakeLocks.get(id);
if (wl != null) {
wl.release();
mActiveWakeLocks.remove(id);
return true;
}
// We return true whether or not we actually found the wake lock
// the return code is defined to indicate whether the Intent contained
// an identifier for a wake lock that it was supposed to match.
// We just log a warning here if there is no wake lock found, which could
// happen for example if this function is called twice on the same
// intent or the process is killed and restarted before processing the intent.
Log.w("WakefulBroadcastReceive", "No active wake lock id #" + id);
return true;
}
}
}
@@ -15,21 +15,19 @@
*/
package org.traccar.client;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.support.v4.content.WakefulBroadcastReceiver;
public class AutostartReceiver extends BroadcastReceiver {
public class AutostartReceiver extends WakefulBroadcastReceiver {
public static final String LOG_TAG = "Traccar.AutostartReceiver";
@Override
public void onReceive(Context context, Intent intent) {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
if (sharedPreferences.getBoolean(TraccarActivity.KEY_STATUS, false)) {
context.startService(new Intent(context, TraccarService.class));
if (sharedPreferences.getBoolean(MainActivity.KEY_STATUS, false)) {
context.startService(new Intent(context, TrackingService.class));
}
}
+174
Просмотреть файл
@@ -0,0 +1,174 @@
/*
* Copyright 2015 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.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.AsyncTask;
import java.util.Date;
public class DatabaseHelper extends SQLiteOpenHelper {
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "traccar.db";
public interface DatabaseHandler<T> {
void onSuccess(T result);
void onFailure(RuntimeException error);
}
private static abstract class DatabaseAsyncTask<T> extends AsyncTask<Void, Void, T> {
private DatabaseHandler<T> handler;
private RuntimeException error;
public DatabaseAsyncTask(DatabaseHandler<T> handler) {
this.handler = handler;
}
@Override
protected T doInBackground(Void... params) {
try {
return executeMethod();
} catch (RuntimeException error) {
this.error = error;
return null;
}
}
protected abstract T executeMethod();
@Override
protected void onPostExecute(T result) {
if (error == null) {
handler.onSuccess(result);
} else {
handler.onFailure(error);
}
}
}
private SQLiteDatabase db;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
db = getWritableDatabase();
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE position (" +
"id INTEGER PRIMARY KEY AUTOINCREMENT," +
"deviceId TEXT," +
"time INTEGER," +
"latitude REAL," +
"longitude REAL," +
"altitude REAL," +
"speed REAL," +
"course REAL," +
"battery REAL)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS position;");
onCreate(db);
}
public void insertPosition(Position position) {
ContentValues values = new ContentValues();
values.put("deviceId", position.getDeviceId());
values.put("time", position.getTime().getTime());
values.put("latitude", position.getLatitude());
values.put("longitude", position.getLongitude());
values.put("altitude", position.getAltitude());
values.put("speed", position.getSpeed());
values.put("course", position.getCourse());
values.put("battery", position.getBattery());
db.insertOrThrow("position", null, values);
}
public void insertPositionAsync(final Position position, DatabaseHandler<Void> handler) {
new DatabaseAsyncTask<Void>(handler) {
@Override
protected Void executeMethod() {
insertPosition(position);
return null;
}
}.execute();
}
public Position selectPosition() {
Position position = new Position();
Cursor cursor = db.rawQuery("SELECT * FROM position ORDER BY id LIMIT 1", null);
try {
if (cursor.getCount() > 0) {
cursor.moveToFirst();
position.setId(cursor.getLong(cursor.getColumnIndex("id")));
position.setDeviceId(cursor.getString(cursor.getColumnIndex("deviceId")));
position.setTime(new Date(cursor.getLong(cursor.getColumnIndex("time"))));
position.setLatitude(cursor.getDouble(cursor.getColumnIndex("latitude")));
position.setLongitude(cursor.getDouble(cursor.getColumnIndex("longitude")));
position.setAltitude(cursor.getDouble(cursor.getColumnIndex("altitude")));
position.setSpeed(cursor.getDouble(cursor.getColumnIndex("speed")));
position.setCourse(cursor.getDouble(cursor.getColumnIndex("course")));
position.setBattery(cursor.getDouble(cursor.getColumnIndex("battery")));
} else {
return null;
}
} finally {
cursor.close();
}
return position;
}
public void selectPositionAsync(DatabaseHandler<Position> handler) {
new DatabaseAsyncTask<Position>(handler) {
@Override
protected Position executeMethod() {
return selectPosition();
}
}.execute();
}
public void deletePosition(long id) {
if (db.delete("position", "id = ?", new String[] { String.valueOf(id) }) != 1) {
throw new SQLException();
}
}
public void deletePositionAsync(final long id, DatabaseHandler<Void> handler) {
new DatabaseAsyncTask<Void>(handler) {
@Override
protected Void executeMethod() {
deletePosition(id);
return null;
}
}.execute();
}
}
+166
Просмотреть файл
@@ -0,0 +1,166 @@
/*
* Copyright 2012 - 2015 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.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.MenuItem;
@SuppressWarnings("deprecation")
public class MainActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
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_INTERVAL = "interval";
public static final String KEY_PROVIDER = "provider";
public static final String KEY_STATUS = "status";
public static final String KEY_FOREGROUND = "foreground";
private boolean firstLaunch; // DELME
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
firstLaunch = !PreferenceManager.getDefaultSharedPreferences(this).contains(KEY_PORT);
addPreferencesFromResource(R.xml.preferences);
initPreferences();
// DELME
if (PreferenceManager.getDefaultSharedPreferences(this).getString(KEY_PROVIDER, null).equals("mixed")) {
PreferenceManager.getDefaultSharedPreferences(this).edit().putString(KEY_PROVIDER, LocationManager.GPS_PROVIDER).commit();
}
if (getPreferenceScreen().getSharedPreferences().getBoolean(KEY_STATUS, false)) {
setPreferencesEnabled(false);
startService(new Intent(this, TrackingService.class));
}
}
@Override
protected void onResume() {
super.onResume();
checkAndShowPortDialog(); // DELME
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
private void setPreferencesEnabled(boolean enabled) {
PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.findPreference(KEY_DEVICE).setEnabled(enabled);
preferenceScreen.findPreference(KEY_ADDRESS).setEnabled(enabled);
preferenceScreen.findPreference(KEY_PORT).setEnabled(enabled);
preferenceScreen.findPreference(KEY_INTERVAL).setEnabled(enabled);
preferenceScreen.findPreference(KEY_PROVIDER).setEnabled(enabled);
preferenceScreen.findPreference(KEY_FOREGROUND).setEnabled(enabled);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (key.equals(KEY_STATUS)) {
if (sharedPreferences.getBoolean(KEY_STATUS, false)) {
setPreferencesEnabled(false);
startService(new Intent(this, TrackingService.class));
} else {
stopService(new Intent(this, TrackingService.class));
setPreferencesEnabled(true);
}
} else if (key.equals(KEY_DEVICE)) {
findPreference(KEY_DEVICE).setSummary(sharedPreferences.getString(KEY_DEVICE, null));
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().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 void initPreferences() {
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String id = telephonyManager.getDeviceId();
SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
if (!sharedPreferences.contains(KEY_DEVICE)) {
sharedPreferences.edit().putString(KEY_DEVICE, id).commit();
}
findPreference(KEY_DEVICE).setSummary(sharedPreferences.getString(KEY_DEVICE, id));
}
// TEMPORARY PORT CHANGE DIALOG (DELME)
private void checkAndShowPortDialog() {
String KEY_SHOWN_PORT_DIALOG = "portDialogHasBeenShown";
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
if (!firstLaunch) {
if (!preferences.contains(KEY_SHOWN_PORT_DIALOG)) {
showDialog(0);
}
}
preferences.edit().putBoolean(KEY_SHOWN_PORT_DIALOG, true).commit();
}
@Override
protected Dialog onCreateDialog(int id) {
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setMessage("Communication protocol used by the app has changed. Now it uses port 5055 on Traccar server. Do you want to change port to 5055?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
PreferenceManager.getDefaultSharedPreferences(MainActivity.this).edit().putString(KEY_PORT, "5055").commit();
}
})
.setNegativeButton("No", null);
return builder.create();
}
}
+68
Просмотреть файл
@@ -0,0 +1,68 @@
/*
* Copyright 2015 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.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
public class NetworkManager extends BroadcastReceiver {
private static final String TAG = NetworkManager.class.getSimpleName();
private Context context;
private NetworkHandler handler;
private ConnectivityManager connectivityManager;
public NetworkManager(Context context, NetworkHandler handler) {
this.context = context;
this.handler = handler;
connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
public interface NetworkHandler {
void onNetworkUpdate(boolean isOnline);
}
public boolean isOnline() {
NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
return activeNetwork != null && activeNetwork.isConnectedOrConnecting();
}
public void start() {
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(this, filter);
}
public void stop() {
context.unregisterReceiver(this);
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION) && handler != null) {
boolean isOnline = isOnline();
Log.i(TAG, "network " + (isOnline ? "on" : "off"));
handler.onNetworkUpdate(isOnline);
}
}
}
+74
Просмотреть файл
@@ -0,0 +1,74 @@
/*
* Copyright 2015 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.location.Location;
import java.util.Date;
public class Position {
public Position() {
}
public Position(String deviceId, Location location, double battery) {
this.deviceId = deviceId;
time = new Date(location.getTime());
latitude = location.getLatitude();
longitude = location.getLongitude();
altitude = location.getAltitude();
speed = location.getSpeed() * 1.943844; // speed in knots
course = location.getBearing();
this.battery = battery;
}
private long id;
public long getId() { return id; }
public void setId(long id) { this.id = id; }
private String deviceId;
public String getDeviceId() { return deviceId; }
public void setDeviceId(String deviceId) { this.deviceId = deviceId; }
private Date time;
public Date getTime() { return time; }
public void setTime(Date time) { this.time = time; }
private double latitude;
public double getLatitude() { return latitude; }
public void setLatitude(double latitude) { this.latitude = latitude; }
private double longitude;
public double getLongitude() { return longitude; }
public void setLongitude(double longitude) { this.longitude = longitude; }
private double altitude;
public double getAltitude() { return altitude; }
public void setAltitude(double altitude) { this.altitude = altitude; }
private double speed;
public double getSpeed() { return speed; }
public void setSpeed(double speed) { this.speed = speed; }
private double course;
public double getCourse() { return course; }
public void setCourse(double course) { this.course = course; }
private double battery;
public double getBattery() { return battery; }
public void setBattery(double battery) { this.battery = battery; }
}
+110
Просмотреть файл
@@ -0,0 +1,110 @@
/*
* Copyright 2013 - 2015 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.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.BatteryManager;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
public class PositionProvider implements LocationListener {
private static final String TAG = PositionProvider.class.getSimpleName();
public interface PositionListener {
void onPositionUpdate(Position position);
}
private final PositionListener listener;
private final Context context;
private final SharedPreferences preferences;
private final LocationManager locationManager;
private String deviceId;
private String type;
private final long period;
public PositionProvider(Context context, PositionListener listener) {
this.context = context;
this.listener = listener;
preferences = PreferenceManager.getDefaultSharedPreferences(context);
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
deviceId = preferences.getString(MainActivity.KEY_DEVICE, null);
type = preferences.getString(MainActivity.KEY_PROVIDER, null);
period = Integer.parseInt(preferences.getString(MainActivity.KEY_INTERVAL, null)) * 1000;
}
public void startUpdates() {
locationManager.requestLocationUpdates(type, period, 0, this);
}
public void stopUpdates() {
locationManager.removeUpdates(this);
}
private long lastTime;
@Override
public void onLocationChanged(Location location) {
if (location != null && location.getTime() != lastTime) {
Log.i(TAG, "location new");
lastTime = location.getTime();
listener.onPositionUpdate(new Position(deviceId, location, getBatteryLevel()));
} else {
Log.i(TAG, location != null ? "location old" : "location nil");
}
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.i(TAG, "provider status");
}
@Override
public void onProviderEnabled(String provider) {
Log.i(TAG, "provider enabled");
}
@Override
public void onProviderDisabled(String provider) {
Log.i(TAG, "provider disabled");
}
@TargetApi(Build.VERSION_CODES.ECLAIR)
public double getBatteryLevel() {
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.ECLAIR) {
Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
return (level * 100.0) / scale;
} else {
return 0;
}
}
}
+39
Просмотреть файл
@@ -0,0 +1,39 @@
/*
* Copyright 2012 - 2015 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.location.Location;
import android.net.Uri;
public class ProtocolFormatter {
public static String formatRequest(String address, int port, Position position) {
Uri.Builder builder = new Uri.Builder();
builder.scheme("http").encodedAuthority(address + ':' + port)
.appendQueryParameter("id", position.getDeviceId())
.appendQueryParameter("timestamp", String.valueOf(position.getTime().getTime() / 1000))
.appendQueryParameter("lat", String.valueOf(position.getLatitude()))
.appendQueryParameter("lon", String.valueOf(position.getLongitude()))
.appendQueryParameter("speed", String.valueOf(position.getSpeed() * 1.943844))
.appendQueryParameter("bearing", String.valueOf(position.getCourse()))
.appendQueryParameter("altitude", String.valueOf(position.getAltitude()))
.appendQueryParameter("batt", String.valueOf(position.getBattery()));
return builder.build().toString();
}
}
+86
Просмотреть файл
@@ -0,0 +1,86 @@
/*
* Copyright 2015 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.os.AsyncTask;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class RequestManager {
private static final int TIMEOUT = 15 * 1000;
public interface RequestHandler {
void onSuccess();
void onFailure();
}
private static class RequestAsyncTask extends AsyncTask<String, Void, Boolean> {
private RequestHandler handler;
public RequestAsyncTask(RequestHandler handler) {
this.handler = handler;
}
@Override
protected Boolean doInBackground(String... request) {
return sendRequest(request[0]);
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
handler.onSuccess();
} else {
handler.onFailure();
}
}
}
public static boolean sendRequest(String request) {
InputStream inputStream = null;
try {
URL url = new URL(request);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setReadTimeout(TIMEOUT);
connection.setConnectTimeout(TIMEOUT);
connection.connect();
inputStream = connection.getInputStream();
while (inputStream.read() != -1);
return true;
} catch (IOException error) {
return false;
} finally {
try {
if (inputStream != null) {
inputStream.close();
}
} catch (IOException secondError) {
return false;
}
}
}
public static void sendRequestAsync(String request, RequestHandler handler) {
RequestAsyncTask task = new RequestAsyncTask(handler);
task.execute(request);
}
}
@@ -23,7 +23,6 @@ import java.util.Set;
import android.app.ListActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -43,7 +42,6 @@ public class StatusActivity extends ListActivity {
}
public static void addMessage(String message) {
Log.i(TraccarActivity.LOG_TAG, message);
DateFormat format = DateFormat.getTimeInstance(DateFormat.SHORT);
message = format.format(new Date()) + " - " + message;
messages.add(message);
+202
Просмотреть файл
@@ -0,0 +1,202 @@
/*
* Copyright 2015 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.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.util.Log;
public class TrackingController implements PositionProvider.PositionListener, NetworkManager.NetworkHandler {
private static final String TAG = TrackingController.class.getSimpleName();
private static final int RETRY_DELAY = 30 * 1000;
private static final int WAKE_LOCK_TIMEOUT = 60 * 1000;
private boolean isOnline;
private boolean isWaiting;
private Context context;
private Handler handler;
private SharedPreferences preferences;
private PositionProvider positionProvider;
private DatabaseHelper databaseHelper;
private NetworkManager networkManager;
private PowerManager.WakeLock wakeLock;
public TrackingController(Context context) {
this.context = context;
handler = new Handler();
preferences = PreferenceManager.getDefaultSharedPreferences(context);
positionProvider = new PositionProvider(context, this);
databaseHelper = new DatabaseHelper(context);
networkManager = new NetworkManager(context, this);
isOnline = networkManager.isOnline();
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
}
public void start() {
if (isOnline) {
read();
}
positionProvider.startUpdates();
networkManager.start();
}
public void stop() {
networkManager.stop();
positionProvider.stopUpdates();
handler.removeCallbacksAndMessages(null);
}
@Override
public void onPositionUpdate(Position position) {
if (position != null) {
StatusActivity.addMessage(context.getString(R.string.status_location_update));
write(position);
}
}
@Override
public void onNetworkUpdate(boolean isOnline) {
if (!this.isOnline && isOnline) {
read();
}
this.isOnline = isOnline;
}
//
// State transition examples:
//
// write -> read -> send -> delete -> read
//
// read -> send -> retry -> read -> send
//
private void log(String action, Position position) {
if (position != null) {
action += " (" +
"id:" + position.getId() +
" time:" + position.getTime().getTime() / 1000 +
" lat:" + position.getLatitude() +
" lon:" + position.getLongitude() + ")";
}
Log.d(TAG, action);
}
private void write(Position position) {
log("write", position);
wakeLock.acquire(WAKE_LOCK_TIMEOUT);
databaseHelper.insertPositionAsync(position, new DatabaseHelper.DatabaseHandler<Void>() {
@Override
public void onSuccess(Void result) {
if (isOnline && isWaiting) {
read();
isWaiting = false;
}
wakeLock.release();
}
@Override
public void onFailure(RuntimeException error) {
wakeLock.release();
}
});
}
private void read() {
log("read", null);
wakeLock.acquire(WAKE_LOCK_TIMEOUT);
databaseHelper.selectPositionAsync(new DatabaseHelper.DatabaseHandler<Position>() {
@Override
public void onSuccess(Position result) {
if (result != null) {
send(result);
} else {
isWaiting = true;
}
wakeLock.release();
}
@Override
public void onFailure(RuntimeException error) {
retry();
wakeLock.release();
}
});
}
private void delete(Position position) {
log("delete", position);
wakeLock.acquire(WAKE_LOCK_TIMEOUT);
databaseHelper.deletePositionAsync(position.getId(), new DatabaseHelper.DatabaseHandler<Void>() {
@Override
public void onSuccess(Void result) {
read();
wakeLock.release();
}
@Override
public void onFailure(RuntimeException error) {
retry();
wakeLock.release();
}
});
}
private void send(final Position position) {
log("send", position);
wakeLock.acquire(WAKE_LOCK_TIMEOUT);
String request = ProtocolFormatter.formatRequest(
preferences.getString(MainActivity.KEY_ADDRESS, null),
Integer.parseInt(preferences.getString(MainActivity.KEY_PORT, null)),
position);
RequestManager.sendRequestAsync(request, new RequestManager.RequestHandler() {
@Override
public void onSuccess() {
delete(position);
wakeLock.release();
}
@Override
public void onFailure() {
StatusActivity.addMessage(context.getString(R.string.status_send_fail));
retry();
wakeLock.release();
}
});
}
private void retry() {
log("retry", null);
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (isOnline) {
read();
}
}
}, RETRY_DELAY);
}
}
+91
Просмотреть файл
@@ -0,0 +1,91 @@
/*
* Copyright 2012 - 2015 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.annotation.TargetApi;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.util.Log;
public class TrackingService extends Service {
private static final String TAG = TrackingService.class.getSimpleName();
private static final int NOTIFICATION_ID = 1;
private TrackingController trackingController;
private boolean foreground;
@Override
public void onCreate() {
Log.i(TAG, "service create");
StatusActivity.addMessage(getString(R.string.status_service_create));
trackingController = new TrackingController(this);
trackingController.start();
foreground = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(MainActivity.KEY_FOREGROUND, false);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@SuppressWarnings("deprecation")
@Override
public void onStart(Intent intent, int startId) {
AutostartReceiver.completeWakefulIntent(intent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR && foreground) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification(android.R.drawable.stat_notify_sync_noanim, null, 0);
notification.setLatestEventInfo(
this, getString(R.string.app_name), getString(R.string.settings_status_on_summary), pendingIntent);
startForeground(NOTIFICATION_ID, notification);
}
}
@TargetApi(Build.VERSION_CODES.ECLAIR)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return START_STICKY;
}
@Override
public void onDestroy() {
Log.i(TAG, "service destroy");
StatusActivity.addMessage(getString(R.string.status_service_destroy));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR && foreground) {
stopForeground(true);
}
if (trackingController != null) {
trackingController.stop();
}
}
}

До

Ширина:  |  Высота:  |  Размер: 3.5 KiB

После

Ширина:  |  Высота:  |  Размер: 3.5 KiB

До

Ширина:  |  Высота:  |  Размер: 1.7 KiB

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

До

Ширина:  |  Высота:  |  Размер: 2.2 KiB

После

Ширина:  |  Высота:  |  Размер: 2.2 KiB

До

Ширина:  |  Высота:  |  Размер: 4.8 KiB

После

Ширина:  |  Высота:  |  Размер: 4.8 KiB

До

Ширина:  |  Высота:  |  Размер: 7.4 KiB

После

Ширина:  |  Высота:  |  Размер: 7.4 KiB

До

Ширина:  |  Высота:  |  Размер: 10 KiB

После

Ширина:  |  Высота:  |  Размер: 10 KiB

Просмотреть файл
Просмотреть файл
Просмотреть файл
Просмотреть файл
+2 -3
Просмотреть файл
@@ -16,15 +16,14 @@
<string name="settings_status_on">Stop</string>
<string name="settings_status_off_summary">Zastaveno</string>
<string name="settings_status_on_summary">Spuštěno</string>
<string name="settings_extended_title">Rozšířené formát</string>
<string name="settings_extended_summary">Použijte nový formát zprávy</string>
<string name="settings_provider_title">Poskytovatel zaměření</string>
<string name="settings_provider_summary">Zdroj zaměřovacích dat</string>
<string-array name="settings_provider_names">
<item>GPS</item>
<item>Mobilní síť</item>
<item>Obojí</item>
</string-array>
<string name="settings_foreground_title">Popředí služba</string>
<string name="settings_foreground_summary">Zvýšit prioritu služba</string>
<string name="menu_status">Stav</string>
<string name="menu_about">O aplikaci</string>
+2 -3
Просмотреть файл
@@ -16,15 +16,14 @@
<string name="settings_status_on">Stop</string>
<string name="settings_status_off_summary">Service stoppet</string>
<string name="settings_status_on_summary">Service er aktiv</string>
<string name="settings_extended_title">Udvidet format</string>
<string name="settings_extended_summary">Brug ny besked format</string>
<string name="settings_provider_title">Udbyder</string>
<string name="settings_provider_summary">Udbyder lokaliseringsdata</string>
<string-array name="settings_provider_names">
<item>GPS udbyder</item>
<item>Netværks udbyder</item>
<item>Mixet udbyder</item>
</string-array>
<string name="settings_foreground_title">Forgrunden tjeneste</string>
<string name="settings_foreground_summary">Øg tjeneste prioritet</string>
<string name="menu_status">Status</string>
<string name="menu_about">Om</string>
+3 -4
Просмотреть файл
@@ -16,16 +16,15 @@
<string name="settings_status_on">Stop</string>
<string name="settings_status_off_summary">Dienst inaktiv</string>
<string name="settings_status_on_summary">Dienst aktiv</string>
<string name="settings_extended_title">Erweitertes Format</string>
<string name="settings_extended_summary">Verwenden Sie das neue Nachrichtenformat</string>
<string name="settings_provider_title">Datenherkunft</string>
<string name="settings_provider_summary">Quelle der Positionen</string>
<string-array name="settings_provider_names">
<item>GPS</item>
<item>Netzwerk</item>
<item>Gemischt</item>
</string-array>
<string name="settings_foreground_title">Vordergrund service</string>
<string name="settings_foreground_summary">Erhöhen service priorität</string>
<string name="menu_status">Status</string>
<string name="menu_about">Über</string>
<string name="menu_clear">Leeren</string>
+2 -3
Просмотреть файл
@@ -16,15 +16,14 @@
<string name="settings_status_on">Desactivado</string>
<string name="settings_status_off_summary">Servicio parado</string>
<string name="settings_status_on_summary">Servicio activado</string>
<string name="settings_extended_title">Formato extendido</string>
<string name="settings_extended_summary">Utilice el nuevo formato de mensaje</string>
<string name="settings_provider_title">Proveedor de localización</string>
<string name="settings_provider_summary">Fuente de los datos de localización</string>
<string-array name="settings_provider_names">
<item>Proveedor GPS</item>
<item>Proveedor de red</item>
<item>Proveedor mixto</item>
</string-array>
<string name="settings_foreground_title">Servicio de primer plano</string>
<string name="settings_foreground_summary">Aumentar prioridad de servicio</string>
<string name="menu_status">Estado</string>
<string name="menu_about">Acerca de&#8230;</string>
+2 -3
Просмотреть файл
@@ -16,15 +16,14 @@
<string name="settings_status_on">Arrêter</string>
<string name="settings_status_off_summary">Arrêté</string>
<string name="settings_status_on_summary">En marche</string>
<string name="settings_extended_title">Format étendu</string>
<string name="settings_extended_summary">Utilisez un nouveau format de message</string>
<string name="settings_provider_title">Source de localisation</string>
<string name="settings_provider_summary">Source utilisée par le système afin d\'obtenir la localisation de l\'appareil</string>
<string-array name="settings_provider_names">
<item>Mode GPS uniquement</item>
<item>Mode cellulaire uniquement</item>
<item>Mode hybride</item>
</string-array>
<string name="settings_foreground_title">Un service de premier plan</string>
<string name="settings_foreground_summary">Augmenter la priorité de service</string>
<string name="menu_status">Etat</string>
<string name="menu_about">A propos</string>
+3 -4
Просмотреть файл
@@ -16,16 +16,15 @@
<string name="settings_status_on">Stopp</string>
<string name="settings_status_off_summary">Tjenesten stoppet</string>
<string name="settings_status_on_summary">Tjenesten kjører</string>
<string name="settings_extended_title">Utvidet format</string>
<string name="settings_extended_summary">Bruk det nye utvidede formatet</string>
<string name="settings_provider_title">Lokaliseringsleverandør</string>
<string name="settings_provider_summary">Kilde for lokaliseringsdata</string>
<string-array name="settings_provider_names">
<item>GPS-lokalisering</item>
<item>Nettverkslokalisering</item>
<item>Blandet lokalisering</item>
</string-array>
<string name="settings_foreground_title">Forgrunnen tjeneste</string>
<string name="settings_foreground_summary">Øk tjeneste prioritet</string>
<string name="menu_status">Status</string>
<string name="menu_about">Om</string>
<string name="menu_clear">Tøm</string>
+3 -4
Просмотреть файл
@@ -16,16 +16,15 @@
<string name="settings_status_on">Parar</string>
<string name="settings_status_off_summary">Serviço Parado</string>
<string name="settings_status_on_summary">Serviço em execução</string>
<string name="settings_extended_title">Formato prolongado</string>
<string name="settings_extended_summary">Use o formato de mensagem nova</string>
<string name="settings_provider_title">Provedor de localização</string>
<string name="settings_provider_summary">Fonte dos dados de localização</string>
<string-array name="settings_provider_names">
<item>Provedor GPS</item>
<item>Provedor Rede</item>
<item>Provedor Misto</item>
</string-array>
<string name="settings_foreground_title">Serviço primeiro plano</string>
<string name="settings_foreground_summary">Aumentar a prioridade de serviço</string>
<string name="menu_status">Status</string>
<string name="menu_about">Sobre</string>
<string name="menu_clear">Limpar</string>
+2 -3
Просмотреть файл
@@ -16,15 +16,14 @@
<string name="settings_status_on">Стоп</string>
<string name="settings_status_off_summary">Сервис остановлен</string>
<string name="settings_status_on_summary">Сервис запущен</string>
<string name="settings_extended_title">Расширенный формат</string>
<string name="settings_extended_summary">Использовать новый формат сообщений</string>
<string name="settings_provider_title">Провайдер местоположения</string>
<string name="settings_provider_summary">Источник данных о местоположении</string>
<string-array name="settings_provider_names">
<item>GPS провайдер</item>
<item>Сетевой провайдер</item>
<item>Смешанный провайдер</item>
</string-array>
<string name="settings_foreground_title">Приотитетный сервис</string>
<string name="settings_foreground_summary">Увеличить приоритет сервиса</string>
<string name="menu_status">Состояние</string>
<string name="menu_about">О программе</string>
+2 -3
Просмотреть файл
@@ -16,15 +16,14 @@
<string name="settings_status_on">Stop</string>
<string name="settings_status_off_summary">Servis zaustavljen</string>
<string name="settings_status_on_summary">Servis pokrenut</string>
<string name="settings_extended_title">Produžen format</string>
<string name="settings_extended_summary">Koristi novi format za poruke</string>
<string name="settings_provider_title">Provajder lokacije</string>
<string name="settings_provider_summary">Izvor lokacijskih podataka</string>
<string-array name="settings_provider_names">
<item>GPS provajder</item>
<item>Provajder Mreže</item>
<item>Oba zajedno provajdera</item>
</string-array>
<string name="settings_foreground_title">Prvi plan servis</string>
<string name="settings_foreground_summary">Povecanje usluga prioritet</string>
<string name="menu_status">Status</string>
<string name="menu_about">O klijentu</string>
Просмотреть файл
+3 -4
Просмотреть файл
@@ -16,16 +16,15 @@
<string name="settings_status_on">Stop</string>
<string name="settings_status_off_summary">Service stopped</string>
<string name="settings_status_on_summary">Service running</string>
<string name="settings_extended_title">Extended format</string>
<string name="settings_extended_summary">Use new message format</string>
<string name="settings_provider_title">Location provider</string>
<string name="settings_provider_summary">Source of location data</string>
<string-array name="settings_provider_names">
<item>GPS provider</item>
<item>Network provider</item>
<item>Mixed provider</item>
</string-array>
<string name="settings_foreground_title">Foreground service</string>
<string name="settings_foreground_summary">Increase service priority</string>
<string name="menu_status">Status</string>
<string name="menu_about">About</string>
<string name="menu_clear">Clear</string>
Просмотреть файл
-1
Просмотреть файл
@@ -4,7 +4,6 @@
<string-array name="settings_provider_values" translatable="false">
<item>gps</item>
<item>network</item>
<item>mixed</item>
</string-array>
</resources>
+15 -15
Просмотреть файл
@@ -1,6 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<SwitchPreference
android:defaultValue="false"
android:key="status"
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:title="@string/settings_status_title" />
<EditTextPreference
android:key="id"
android:title="@string/settings_id_title" />
@@ -12,14 +21,14 @@
android:title="@string/settings_address_title" />
<EditTextPreference
android:defaultValue="5005"
android:defaultValue="5055"
android:key="port"
android:numeric="integer"
android:summary="@string/settings_port_summary"
android:title="@string/settings_port_title" />
<EditTextPreference
android:defaultValue="60"
android:defaultValue="300"
android:key="interval"
android:numeric="integer"
android:summary="@string/settings_interval_summary"
@@ -34,18 +43,9 @@
android:title="@string/settings_provider_title" />
<CheckBoxPreference
android:defaultValue="false"
android:key="extended"
android:summary="@string/settings_extended_summary"
android:title="@string/settings_extended_title" />
<SwitchPreference
android:defaultValue="false"
android:key="status"
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:title="@string/settings_status_title" />
android:defaultValue="true"
android:key="foreground"
android:summary="@string/settings_foreground_summary"
android:title="@string/settings_foreground_title" />
</PreferenceScreen>
+13 -13
Просмотреть файл
@@ -1,6 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<CheckBoxPreference
android:defaultValue="false"
android:key="status"
android:summaryOff="@string/settings_status_off_summary"
android:summaryOn="@string/settings_status_on_summary"
android:title="@string/settings_status_title" />
<EditTextPreference
android:key="id"
android:title="@string/settings_id_title" />
@@ -12,14 +19,14 @@
android:title="@string/settings_address_title" />
<EditTextPreference
android:defaultValue="5005"
android:defaultValue="5055"
android:key="port"
android:numeric="integer"
android:summary="@string/settings_port_summary"
android:title="@string/settings_port_title" />
<EditTextPreference
android:defaultValue="60"
android:defaultValue="300"
android:key="interval"
android:numeric="integer"
android:summary="@string/settings_interval_summary"
@@ -34,16 +41,9 @@
android:title="@string/settings_provider_title" />
<CheckBoxPreference
android:defaultValue="false"
android:key="extended"
android:summary="@string/settings_extended_summary"
android:title="@string/settings_extended_title" />
<CheckBoxPreference
android:defaultValue="false"
android:key="status"
android:summaryOff="@string/settings_status_off_summary"
android:summaryOn="@string/settings_status_on_summary"
android:title="@string/settings_status_title" />
android:defaultValue="true"
android:key="foreground"
android:summary="@string/settings_foreground_summary"
android:title="@string/settings_foreground_title" />
</PreferenceScreen>
+46
Просмотреть файл
@@ -0,0 +1,46 @@
package org.traccar.client;
import android.database.sqlite.SQLiteDatabase;
import android.location.Location;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import java.util.Date;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class DatabaseHelperTest {
@Test
public void test() throws Exception {
DatabaseHelper databaseHelper = new DatabaseHelper(RuntimeEnvironment.application);
SQLiteDatabase db = databaseHelper.getWritableDatabase();
Position position = new Position("123456789012345", new Location("gps"), 0);
position.setTime(new Date(0));
assertNull(databaseHelper.selectPosition());
databaseHelper.insertPosition(position);
position = databaseHelper.selectPosition();
assertNotNull(position);
databaseHelper.deletePosition(position.getId());
assertNull(databaseHelper.selectPosition());
}
}
+31
Просмотреть файл
@@ -0,0 +1,31 @@
package org.traccar.client;
import android.location.Location;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
import java.util.Date;
import static org.junit.Assert.assertEquals;
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class ProtocolFormatterTest {
@Test
public void testFormatRequest() throws Exception {
Position position = new Position("123456789012345", new Location("gps"), 0);
position.setTime(new Date(0));
String url = ProtocolFormatter.formatRequest("localhost", 5055, position);
assertEquals("http://localhost:5055?id=123456789012345&timestamp=0&lat=0.0&lon=0.0&speed=0.0&bearing=0.0&altitude=0.0&batt=0.0", url);
}
}
+22
Просмотреть файл
@@ -0,0 +1,22 @@
package org.traccar.client;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricGradleTestRunner;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertTrue;
@RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class RequestManagerTest {
@Test
public void testSendRequest() throws Exception {
assertTrue(RequestManager.sendRequest("http://www.google.com"));
}
}
+1 -1
Просмотреть файл
@@ -5,7 +5,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.2'
classpath 'com.android.tools.build:gradle:1.3.0'
}
}
-18
Просмотреть файл
@@ -1,18 +0,0 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Settings specified in this file will override any Gradle settings
# configured through the IDE.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
Двоичные данные
Двоичный файл не отображается.
+2 -2
Просмотреть файл
@@ -1,6 +1,6 @@
#Fri Feb 06 09:56:43 NZDT 2015
#Wed Aug 12 13:33:05 NZST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-all.zip
Vendored
-90
Просмотреть файл
@@ -1,90 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
-119
Просмотреть файл
@@ -1,119 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="64px"
height="64px"
id="svg2985"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="traccar.svg">
<defs
id="defs2987" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="4"
inkscape:cx="-11.637539"
inkscape:cy="7.0291785"
inkscape:current-layer="layer1"
showgrid="true"
inkscape:document-units="px"
inkscape:grid-bbox="true"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:object-nodes="true"
inkscape:snap-intersection-paths="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-center="true"
inkscape:snap-object-midpoints="true"
inkscape:window-width="1920"
inkscape:window-height="1176"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:snap-global="false" />
<metadata
id="metadata2990">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
id="layer1"
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<g
id="g2995">
<path
transform="matrix(11.849785,-6.8414759,4.1048857,7.1098702,-141.6761,-453.06363)"
d="m -4.633625,61.745384 a 2.0991254,3.4985423 0 1 1 -4.1982508,0 2.0991254,3.4985423 0 1 1 4.1982508,0 z"
sodipodi:ry="3.4985423"
sodipodi:rx="2.0991254"
sodipodi:cy="61.745384"
sodipodi:cx="-6.7327504"
id="path3038"
style="fill:#ffffff"
sodipodi:type="arc" />
<path
transform="matrix(0.98000485,-0.56580602,0.76260819,1.3208761,-13.500496,-10.292296)"
d="m 16.134891,38.929852 a 1.9927555,1.478496 0 1 1 -3.985511,0 1.9927555,1.478496 0 1 1 3.985511,0 z"
sodipodi:ry="1.478496"
sodipodi:rx="1.9927555"
sodipodi:cy="38.929852"
sodipodi:cx="14.142136"
id="path2993"
style="fill:#000000"
sodipodi:type="arc" />
<path
id="path3004"
d="m 36.965211,24.251054 -2.816072,3.57877 c 0.657208,0.517134 1.313001,1.146671 1.756681,1.915146 0.443679,0.768474 0.660975,1.651177 0.780224,2.478901 l 4.507342,-0.649405 C 41.001257,30.166972 40.565802,28.79619 39.81164,27.489944 39.057477,26.183697 38.088074,25.121191 36.965211,24.251054 z"
style="fill:#000000"
inkscape:connector-curvature="0" />
<path
id="path3014"
d="m 42.404828,17.041928 -2.816072,3.578769 c 1.591875,1.223919 3.062315,2.767181 4.128704,4.614221 1.066388,1.847038 1.667671,3.892108 1.931679,5.882671 l 4.507341,-0.649405 c -0.336471,-2.571017 -1.155959,-5.102841 -2.5332,-7.488294 -1.377241,-2.385452 -3.160122,-4.36106 -5.218452,-5.937962 z"
style="fill:#000000"
inkscape:connector-curvature="0" />
<path
sodipodi:end="4.712389"
sodipodi:start="1.5707963"
transform="matrix(3.9507144,-2.2809459,1.4097023,2.4416757,-59.699972,-127.24372)"
d="m -2.0227272,68.375862 a 1.9772727,3.1992946 0 1 1 0,-6.398589 l -1e-7,3.199294 z"
sodipodi:ry="3.1992946"
sodipodi:rx="1.9772727"
sodipodi:cy="65.176567"
sodipodi:cx="-2.0227273"
id="path3036"
style="fill:#000000"
sodipodi:type="arc" />
<path
id="path3038-8"
d="M 17.638883,7.1258129 C 3.9012503,15.057239 -0.80560983,32.62348 7.1258152,46.361111 15.057241,60.098742 32.623482,64.805603 46.361115,56.874177 60.098748,48.942752 64.805608,31.37651 56.874183,17.63888 48.942758,3.9012493 31.376516,-0.80561226 17.638883,7.1258129 z m 1.689543,2.9263741 C 31.449867,3.0538711 46.949491,7.2069826 53.947808,19.328422 60.946126,31.449863 56.793012,46.949488 44.671573,53.947803 32.550132,60.94612 17.050507,56.793009 10.05219,44.671568 3.0538724,32.550127 7.2069849,17.050503 19.328426,10.052187 z"
style="fill:#000000"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

До

Ширина:  |  Высота:  |  Размер: 4.8 KiB

Двоичные данные
Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 32 KiB

+1 -1
Просмотреть файл
@@ -1 +1 @@
include ':traccar-client'
include ':app'
-21
Просмотреть файл
@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id="traccar-client-android" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="java-gradle" name="Java-Gradle">
<configuration>
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
<option name="BUILDABLE" value="false" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<output url="file://$MODULE_DIR$/build/classes/main" />
<output-test url="file://$MODULE_DIR$/build/classes/test" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
-1
Просмотреть файл
@@ -1 +0,0 @@
/build
-17
Просмотреть файл
@@ -1,17 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/user/android-studio/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-141
Просмотреть файл
@@ -1,141 +0,0 @@
/*
* 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.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.os.Handler;
import android.util.Log;
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;
}
private BroadcastReceiver connectivityListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
StatusActivity.addMessage(context.getString(R.string.status_connectivity_change));
/*if (intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false)) {
handler.removeCallbacksAndMessages(null);
} else {
reconnect();
}*/
}
};
public void start() {
handler = new Handler();
connection = new Connection(this);
connection.connect(address, port);
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(connectivityListener, filter);
}
public void stop() {
context.unregisterReceiver(connectivityListener);
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();
}
}
}
-157
Просмотреть файл
@@ -1,157 +0,0 @@
/*
* 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.
* 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.io.Closeable;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import android.os.AsyncTask;
import android.util.Log;
/**
* Asynchronous connection
*
* All methods should be called from UI thread only.
*/
public class Connection implements Closeable {
public static final String LOG_TAG = "Traccar.Connection";
public static final int SOCKET_TIMEOUT = 10 * 1000;
/**
* Callback interface
*/
public interface ConnectionHandler {
void onConnected(boolean result);
void onSent(boolean result);
}
private ConnectionHandler handler;
private Socket socket;
private OutputStream socketStream;
private boolean closed;
private boolean busy;
public boolean isClosed() {
return closed;
}
public boolean isBusy() {
return busy;
}
public Connection(ConnectionHandler handler) {
this.handler = handler;
closed = false;
busy = false;
}
public void connect(final String address, final int port) {
busy = true;
new AsyncTask<Void, Void, Boolean>() {
@Override
protected Boolean doInBackground(Void... params) {
try {
socket = new Socket();
socket.connect(new InetSocketAddress(address, port));
socket.setSoTimeout(SOCKET_TIMEOUT);
socketStream = socket.getOutputStream();
return true;
} catch (Exception e) {
Log.w(LOG_TAG, e.getMessage());
return false;
}
}
@Override
protected void onCancelled() {
if (!closed) {
busy = false;
handler.onConnected(false);
}
}
@Override
protected void onPostExecute(Boolean result) {
if (!closed) {
busy = false;
handler.onConnected(result);
}
}
}.execute();
}
public void send(String message) {
busy = true;
new AsyncTask<String, Void, Boolean>() {
@Override
protected Boolean doInBackground(String... params) {
try {
socketStream.write(params[0].getBytes());
socketStream.flush();
return true;
} catch (Exception e) {
Log.w(LOG_TAG, e.getMessage());
return false;
}
}
@Override
protected void onCancelled() {
if (!closed) {
busy = false;
handler.onSent(false);
}
}
@Override
protected void onPostExecute(Boolean result) {
if (!closed) {
busy = false;
handler.onSent(result);
}
}
}.execute(message);
}
@Override
public void close() {
closed = true;
try {
if (socketStream != null) {
socketStream.close();
}
if (socket != null) {
socket.close();
}
} catch (Exception e) {
Log.e(LOG_TAG, e.getMessage());
}
}
}
-156
Просмотреть файл
@@ -1,156 +0,0 @@
/*
* Copyright 2013 - 2015 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.Date;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.LocationProvider;
import android.os.Bundle;
import android.os.Handler;
import android.widget.Toast;
public class PositionProvider {
public static final String PROVIDER_MIXED = "mixed";
public static final long PERIOD_DELTA = 10 * 1000;
public static final long RETRY_PERIOD = 60 * 1000;
public interface PositionListener {
public void onPositionUpdate(Location location);
}
private final Handler handler;
private final LocationManager locationManager;
private final long period;
private final PositionListener listener;
private final Context context;
private boolean useFine;
private boolean useCoarse;
public PositionProvider(Context context, String type, long period, PositionListener listener) {
handler = new Handler(context.getMainLooper());
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
this.period = period;
this.listener = listener;
this.context = context;
// Determine providers
if (type.equals(PROVIDER_MIXED)) {
useFine = true;
useCoarse = true;
} else if (type.equals(LocationManager.GPS_PROVIDER)) {
useFine = true;
} else if (type.equals(LocationManager.NETWORK_PROVIDER)) {
useCoarse = true;
}
}
public void startUpdates() {
if (useFine) {
try {
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, period, 0, fineLocationListener);
} catch (Exception e) {
StatusActivity.addMessage(context.getString(R.string.status_provider_missing));
}
}
if (useCoarse) {
try {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, period, 0, coarseLocationListener);
} catch (Exception e) {
StatusActivity.addMessage(context.getString(R.string.status_provider_missing));
}
}
handler.postDelayed(updateTask, period);
}
public void stopUpdates() {
handler.removeCallbacks(updateTask);
locationManager.removeUpdates(fineLocationListener);
locationManager.removeUpdates(coarseLocationListener);
}
private final Runnable updateTask = new Runnable() {
private long lastTime;
private boolean tryProvider(String provider) {
Location location = locationManager.getLastKnownLocation(provider);
/*if (location != null) {
Toast.makeText(context, "phone: " + new Date() + "\ngps: " + new Date(location.getTime()), Toast.LENGTH_LONG).show();
} else {
Toast.makeText(context, "no location", Toast.LENGTH_LONG).show();
}*/
if (location != null && location.getTime() != lastTime) {
lastTime = location.getTime();
listener.onPositionUpdate(location);
return true;
} else {
return false;
}
}
@Override
public void run() {
if (useFine && tryProvider(LocationManager.GPS_PROVIDER)) {
} else if (useCoarse && tryProvider(LocationManager.NETWORK_PROVIDER)) {
} else {
listener.onPositionUpdate(null);
}
handler.postDelayed(this, period);
}
};
private final InternalLocationListener fineLocationListener = new InternalLocationListener();
private final InternalLocationListener coarseLocationListener = new InternalLocationListener();
private class InternalLocationListener implements LocationListener {
@Override
public void onLocationChanged(Location location) {
}
@Override
public void onProviderDisabled(String provider) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onStatusChanged(final String provider, int status, Bundle extras) {
if (status == LocationProvider.TEMPORARILY_UNAVAILABLE || status == LocationProvider.OUT_OF_SERVICE) {
handler.postDelayed(new Runnable() {
@Override
public void run() {
locationManager.removeUpdates(InternalLocationListener.this);
locationManager.requestLocationUpdates(provider, period, 0, InternalLocationListener.this);
}
}, RETRY_PERIOD);
}
}
}
}
-92
Просмотреть файл
@@ -1,92 +0,0 @@
/*
* Copyright 2012 - 2014 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.Calendar;
import java.util.Formatter;
import java.util.Locale;
import java.util.TimeZone;
import android.location.Location;
/**
* Protocol formatting
*/
public class Protocol {
/**
* Format device id message
*/
public static String createLoginMessage(String id) {
StringBuilder s = new StringBuilder("$PGID,");
Formatter f = new Formatter(s, Locale.ENGLISH);
s.append(id);
byte checksum = 0;
for (byte b : s.substring(1).getBytes()) {
checksum ^= b;
}
f.format("*%02x\r\n", (int) checksum);
f.close();
return s.toString();
}
/**
* Format location message
*/
public static String createLocationMessage(boolean extended, Location l, double battery) {
StringBuilder s = new StringBuilder(extended ? "$TRCCR," : "$GPRMC,");
Formatter f = new Formatter(s, Locale.ENGLISH);
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.ENGLISH);
calendar.setTimeInMillis(l.getTime());
if (extended) {
f.format("%1$tY%1$tm%1$td%1$tH%1$tM%1$tS.%1$tL,A,", calendar);
f.format("%.6f,%.6f,", l.getLatitude(), l.getLongitude());
f.format("%.2f,%.2f,", l.getSpeed() * 1.943844, l.getBearing());
f.format("%.2f,", l.getAltitude());
f.format("%.0f,", battery);
} else {
f.format("%1$tH%1$tM%1$tS.%1$tL,A,", calendar);
double lat = l.getLatitude();
double lon = l.getLongitude();
f.format("%02d%07.4f,%c,", (int) Math.abs(lat), Math.abs(lat) % 1 * 60, lat < 0 ? 'S' : 'N');
f.format("%03d%07.4f,%c,", (int) Math.abs(lon), Math.abs(lon) % 1 * 60, lon < 0 ? 'W' : 'E');
double speed = l.getSpeed() * 1.943844; // speed in knots
f.format("%.2f,%.2f,", speed, l.getBearing());
f.format("%1$td%1$tm%1$ty,,", calendar);
}
byte checksum = 0;
for (byte b : s.substring(1).getBytes()) {
checksum ^= b;
}
f.format("*%02x\r\n", (int) checksum);
f.close();
return s.toString();
}
}
-130
Просмотреть файл
@@ -1,130 +0,0 @@
/*
* Copyright 2012 - 2014 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.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.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
/**
* Main user interface
*/
@SuppressWarnings("deprecation")
public class TraccarActivity extends PreferenceActivity {
public static final String LOG_TAG = "traccar";
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_PROVIDER = "provider";
public static final String KEY_EXTENDED = "extended";
public static final String KEY_STATUS = "status";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
initPreferences();
SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
if (sharedPreferences.getBoolean(KEY_STATUS, false))
startService(new Intent(this, TraccarService.class));
}
@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));
}
} else if (key.equals(KEY_ID)) {
findPreference(KEY_ID).setSummary(sharedPreferences.getString(KEY_ID, null));
}
}
};
@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;
}
private void initPreferences() {
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String id = telephonyManager.getDeviceId();
SharedPreferences sharedPreferences = getPreferenceScreen().getSharedPreferences();
if (!sharedPreferences.contains(KEY_ID)) {
sharedPreferences.edit().putString(KEY_ID, id).commit();
}
findPreference(KEY_ID).setSummary(sharedPreferences.getString(KEY_ID, id));
}
}
-179
Просмотреть файл
@@ -1,179 +0,0 @@
/*
* Copyright 2012 - 2014 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.annotation.TargetApi;
import android.app.Service;
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.os.BatteryManager;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.preference.PreferenceManager;
import android.util.Log;
/**
* Background service
*/
public class TraccarService extends Service {
public static final String LOG_TAG = "Traccar.TraccarService";
private String id;
private String address;
private int port;
private int interval;
private String provider;
private boolean extended;
private SharedPreferences sharedPreferences;
private ClientController clientController;
private PositionProvider positionProvider;
private WakeLock wakeLock;
@Override
public void onCreate() {
StatusActivity.addMessage(getString(R.string.status_service_create));
PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
wakeLock.acquire();
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
try {
id = sharedPreferences.getString(TraccarActivity.KEY_ID, null);
address = sharedPreferences.getString(TraccarActivity.KEY_ADDRESS, null);
provider = sharedPreferences.getString(TraccarActivity.KEY_PROVIDER, null);
port = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_PORT, null));
interval = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_INTERVAL, null));
extended = sharedPreferences.getBoolean(TraccarActivity.KEY_EXTENDED, false);
} catch (Exception error) {
Log.w(LOG_TAG, error);
}
clientController = new ClientController(this, address, port, Protocol.createLoginMessage(id));
clientController.start();
positionProvider = new PositionProvider(this, provider, interval * 1000, positionListener);
positionProvider.startUpdates();
sharedPreferences.registerOnSharedPreferenceChangeListener(preferenceChangeListener);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onDestroy() {
StatusActivity.addMessage(getString(R.string.status_service_destroy));
if (sharedPreferences != null) {
sharedPreferences.unregisterOnSharedPreferenceChangeListener(preferenceChangeListener);
}
if (positionProvider != null) {
positionProvider.stopUpdates();
}
if (clientController != null) {
clientController.stop();
}
wakeLock.release();
}
@TargetApi(Build.VERSION_CODES.ECLAIR)
public double getBatteryLevel() {
if (android.os.Build.VERSION.SDK_INT > Build.VERSION_CODES.ECLAIR) {
Intent batteryIntent = registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
int scale = batteryIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
return (level * 100.0) / scale;
} else {
return 0;
}
}
private PositionProvider.PositionListener positionListener = new PositionProvider.PositionListener() {
@Override
public void onPositionUpdate(Location location) {
if (location != null) {
StatusActivity.addMessage(getString(R.string.status_location_update));
clientController.setNewLocation(Protocol.createLocationMessage(extended, location, getBatteryLevel()));
}
}
};
OnSharedPreferenceChangeListener preferenceChangeListener = new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
StatusActivity.addMessage(getString(R.string.status_preference_update));
try {
if (key.equals(TraccarActivity.KEY_ADDRESS)) {
address = sharedPreferences.getString(TraccarActivity.KEY_ADDRESS, null);
clientController.setNewServer(address, port);
} else if (key.equals(TraccarActivity.KEY_PORT)) {
port = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_PORT, null));
clientController.setNewServer(address, port);
} else if (key.equals(TraccarActivity.KEY_INTERVAL)) {
interval = Integer.valueOf(sharedPreferences.getString(TraccarActivity.KEY_INTERVAL, null));
positionProvider.stopUpdates();
positionProvider = new PositionProvider(TraccarService.this, provider, interval * 1000, positionListener);
positionProvider.startUpdates();
} else if (key.equals(TraccarActivity.KEY_ID)) {
id = sharedPreferences.getString(TraccarActivity.KEY_ID, null);
clientController.setNewLogin(Protocol.createLoginMessage(id));
} else if (key.equals(TraccarActivity.KEY_PROVIDER)) {
provider = sharedPreferences.getString(TraccarActivity.KEY_PROVIDER, null);
positionProvider.stopUpdates();
positionProvider = new PositionProvider(TraccarService.this, provider, interval * 1000, positionListener);
positionProvider.startUpdates();
} else if (key.equals(TraccarActivity.KEY_EXTENDED)) {
extended = sharedPreferences.getBoolean(TraccarActivity.KEY_EXTENDED, false);
}
} catch (Exception error) {
Log.w(LOG_TAG, error);
}
}
};
}
-90
Просмотреть файл
@@ -1,90 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":traccar-client" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="traccar-client-android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":traccar-client" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>