Сравнить коммиты
| Автор | SHA1 | Дата | |
|---|---|---|---|
|
|
43e108de8c | ||
|
|
fedce0e26b | ||
|
|
e24d725feb | ||
|
|
3198bee2f2 | ||
|
|
92e0fb3ad5 | ||
|
|
f7b0df1c41 | ||
|
|
8a26c7e5ba | ||
|
|
27c98b910b | ||
|
|
360958d250 | ||
|
|
4d8d15d615 | ||
|
|
7c49bb78f3 | ||
|
|
e87c3c7783 | ||
|
|
5428530dbd | ||
|
|
3d5682d1b1 | ||
|
|
8f91c0e0ea | ||
|
|
965feb9b04 | ||
|
|
8f8a5e3f55 | ||
|
|
77154a81af | ||
|
|
8d94b8d011 | ||
|
|
ab37fd478a | ||
|
|
79662bad35 | ||
|
|
90373ff8fb | ||
|
|
f2e7ae7c21 | ||
|
|
e0c5340d8b | ||
|
|
90fffa9873 | ||
|
|
db51adaf86 | ||
|
|
7eb6876491 | ||
|
|
5db3407e88 | ||
|
|
ff4fe90c6d | ||
|
|
62a2599765 | ||
|
|
149eee530a | ||
|
|
6e398d12fe |
@@ -0,0 +1,47 @@
|
||||
# Contributing to Traccar
|
||||
|
||||
Please make sure you read this guide before commenting on any issue or creating a new issue or pull request.
|
||||
|
||||
Before asking anything, please search for an answer in:
|
||||
|
||||
- [Traccar documentation](https://www.traccar.org/documentation/)
|
||||
- [Traccar forums](https://www.traccar.org/forums/)
|
||||
- Relevant repositories (see below)
|
||||
- [Google Search](https://www.google.com/)
|
||||
|
||||
GitHub issues should be used ONLY for feature requests, code discussions and bug reports. For general discussions please use [Traccar forums](https://www.traccar.org/forums/).
|
||||
|
||||
There are multiple Traccar projects. If you create a new issue you MUST do it in the relevant repository:
|
||||
|
||||
- [Traccar Server](https://github.com/tananaev/traccar/issues)
|
||||
- [Traccar Web Interface](https://github.com/tananaev/traccar-web/issues)
|
||||
- [Traccar Client for Android](https://github.com/tananaev/traccar-client-android/issues)
|
||||
- [Traccar Client for iOS](https://github.com/tananaev/traccar-client-ios/issues)
|
||||
- [Traccar Manager for Android](https://github.com/tananaev/traccar-manager-android/issues)
|
||||
- [Traccar Manager for iOS](https://github.com/tananaev/traccar-manager-ios/issues)
|
||||
|
||||
If you are not sure where your issue belongs to, please use Traccar Server main repository.
|
||||
|
||||
If you want to discuss something that applies to both Android and iOS apps, please use Android repository.
|
||||
|
||||
## Bug Reports
|
||||
|
||||
Before creating a bug report make sure that you have tested latest official release with default configuration.
|
||||
|
||||
Only create a bug report issue if you are confident that there is a problem in Traccar software.
|
||||
|
||||
Provide as much details as possible, including log fragments, operating system and hardware information.
|
||||
|
||||
## Feature Requests
|
||||
|
||||
Before creating a feature request make sure that the feature or modification that you are requesting is not yet implemented.
|
||||
|
||||
Search reposiroty to ensure that there is no existing issues for your request. If there is, add a new comment on that issue.
|
||||
|
||||
Provide as much details as possible, including use case for your feature and any benefits that you can think of.
|
||||
|
||||
## Pull Requests
|
||||
|
||||
If you want to contribute some code to Traccar, it is recommended to discuss your solution with maintainers before starting any work.
|
||||
|
||||
Any code that you want to contribute must be of high quality and follow existing code patterns and styles.
|
||||
@@ -0,0 +1,7 @@
|
||||
<!--
|
||||
|
||||
Do you want to ask a question? Traccar official forum is the best place for getting support:
|
||||
|
||||
https://www.traccar.org/forums/
|
||||
|
||||
-->
|
||||
@@ -4,3 +4,4 @@ local.properties
|
||||
*.iml
|
||||
build/
|
||||
.DS_Store
|
||||
google-services.json
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 25
|
||||
buildToolsVersion '25.0.2'
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '26.0.1'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 3
|
||||
targetSdkVersion 25
|
||||
versionCode 36
|
||||
versionName '4.3'
|
||||
applicationId "org.traccar.client"
|
||||
buildConfigField "boolean", "HIDDEN_APP", "false"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 26
|
||||
versionCode 38
|
||||
versionName '5.1'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
@@ -16,10 +18,8 @@ android {
|
||||
}
|
||||
|
||||
productFlavors {
|
||||
regular {
|
||||
applicationId "org.traccar.client"
|
||||
buildConfigField "boolean", "HIDDEN_APP", "false"
|
||||
}
|
||||
regular
|
||||
google
|
||||
hidden {
|
||||
applicationId "org.traccar.client.hidden"
|
||||
buildConfigField "boolean", "HIDDEN_APP", "true"
|
||||
@@ -35,6 +35,24 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:design:26.0.1'
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'org.robolectric:robolectric:3.0'
|
||||
testCompile 'org.robolectric:robolectric:3.4.2'
|
||||
googleCompile 'com.google.firebase:firebase-core:11.2.0'
|
||||
googleCompile 'com.google.firebase:firebase-crash:11.2.0'
|
||||
}
|
||||
|
||||
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Google")) {
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
|
||||
task copyJson(type: Copy) {
|
||||
from '../../traccar-shared/google-services'
|
||||
into '.'
|
||||
include 'traccar-client-android.json'
|
||||
rename('traccar-client-android.json', 'google-services.json')
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
preBuild.dependsOn copyJson
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:name="org.traccar.client.GoogleMainApplication"
|
||||
tools:replace="android:name">
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.traccar.client;
|
||||
|
||||
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||
|
||||
public class GoogleMainApplication extends MainApplication {
|
||||
|
||||
private FirebaseAnalytics firebaseAnalytics;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
firebaseAnalytics = FirebaseAnalytics.getInstance(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<application
|
||||
android:label="@string/hidden_app_name"
|
||||
tools:replace="label">
|
||||
tools:replace="android:label">
|
||||
|
||||
<receiver android:name="org.traccar.client.DialLaunchReceiver" >
|
||||
<intent-filter>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/white"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/white"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
До Ширина: | Высота: | Размер: 5.5 KiB После Ширина: | Высота: | Размер: 3.3 KiB |
|
После Ширина: | Высота: | Размер: 2.0 KiB |
|
До Ширина: | Высота: | Размер: 3.3 KiB После Ширина: | Высота: | Размер: 2.1 KiB |
|
После Ширина: | Высота: | Размер: 1.2 KiB |
|
До Ширина: | Высота: | Размер: 8.0 KiB После Ширина: | Высота: | Размер: 4.7 KiB |
|
После Ширина: | Высота: | Размер: 2.5 KiB |
|
До Ширина: | Высота: | Размер: 14 KiB После Ширина: | Высота: | Размер: 7.6 KiB |
|
После Ширина: | Высота: | Размер: 4.7 KiB |
|
До Ширина: | Высота: | Размер: 20 KiB После Ширина: | Высота: | Размер: 11 KiB |
|
После Ширина: | Высота: | Размер: 4.4 KiB |
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.traccar.client">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
@@ -14,10 +15,12 @@
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/TraccarTheme"
|
||||
android:theme="@style/AppTheme"
|
||||
android:name=".MainApplication">
|
||||
|
||||
<activity android:name=".MainActivity" android:launchMode="singleTask" />
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:launchMode="singleTask" />
|
||||
|
||||
<activity-alias
|
||||
android:name=".Launcher"
|
||||
@@ -26,6 +29,9 @@
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<meta-data
|
||||
android:name="android.app.shortcuts"
|
||||
android:resource="@xml/shortcuts" />
|
||||
</activity-alias>
|
||||
|
||||
<activity android:name=".StatusActivity"/>
|
||||
@@ -33,9 +39,11 @@
|
||||
<activity android:name=".AboutActivity"/>
|
||||
|
||||
<activity
|
||||
android:name=".ShortcutActivity">
|
||||
android:name=".ShortcutActivity"
|
||||
android:label="@string/menu_shortcuts">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<action android:name="android.intent.action.CREATE_SHORTCUT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
|
||||
|
После Ширина: | Высота: | Размер: 48 KiB |
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
* Copyright 2012 - 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,22 +15,24 @@
|
||||
*/
|
||||
package org.traccar.client;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class AboutActivity extends Activity {
|
||||
public class AboutActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.about);
|
||||
|
||||
TextView title = (TextView) findViewById(R.id.title);
|
||||
TextView title = findViewById(R.id.title);
|
||||
try {
|
||||
title.setText(title.getText() + " " + getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName);
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.w(AboutActivity.class.getSimpleName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ public class AutostartReceiver extends WakefulBroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if (sharedPreferences.getBoolean(MainActivity.KEY_STATUS, false)) {
|
||||
if (sharedPreferences.getBoolean(MainFragment.KEY_STATUS, false)) {
|
||||
startWakefulService(context, new Intent(context, TrackingService.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ import java.util.Date;
|
||||
|
||||
public class DatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
public static final int DATABASE_VERSION = 1;
|
||||
public static final int DATABASE_VERSION = 2;
|
||||
public static final String DATABASE_NAME = "traccar.db";
|
||||
|
||||
public interface DatabaseHandler<T> {
|
||||
@@ -79,6 +79,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||
"altitude REAL," +
|
||||
"speed REAL," +
|
||||
"course REAL," +
|
||||
"accuracy REAL," +
|
||||
"battery REAL)");
|
||||
}
|
||||
|
||||
@@ -97,6 +98,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||
values.put("altitude", position.getAltitude());
|
||||
values.put("speed", position.getSpeed());
|
||||
values.put("course", position.getCourse());
|
||||
values.put("accuracy", position.getCourse());
|
||||
values.put("battery", position.getBattery());
|
||||
|
||||
db.insertOrThrow("position", null, values);
|
||||
@@ -129,6 +131,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
||||
position.setAltitude(cursor.getDouble(cursor.getColumnIndex("altitude")));
|
||||
position.setSpeed(cursor.getDouble(cursor.getColumnIndex("speed")));
|
||||
position.setCourse(cursor.getDouble(cursor.getColumnIndex("course")));
|
||||
position.setAccuracy(cursor.getDouble(cursor.getColumnIndex("accuracy")));
|
||||
position.setBattery(cursor.getDouble(cursor.getColumnIndex("battery")));
|
||||
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 - 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
* Copyright 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,295 +15,17 @@
|
||||
*/
|
||||
package org.traccar.client;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.preference.TwoStatePreference;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MainActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
|
||||
|
||||
private static final String TAG = MainActivity.class.getSimpleName();
|
||||
|
||||
public static final String KEY_DEVICE = "id";
|
||||
public static final String KEY_ADDRESS = "address";
|
||||
public static final String KEY_PORT = "port";
|
||||
public static final String KEY_SECURE = "secure";
|
||||
public static final String KEY_INTERVAL = "interval";
|
||||
public static final String KEY_DISTANCE = "distance";
|
||||
public static final String KEY_ANGLE = "angle";
|
||||
public static final String KEY_PROVIDER = "provider";
|
||||
public static final String KEY_STATUS = "status";
|
||||
|
||||
private static final int PERMISSIONS_REQUEST_LOCATION = 2;
|
||||
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
private AlarmManager alarmManager;
|
||||
private PendingIntent alarmIntent;
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (BuildConfig.HIDDEN_APP) {
|
||||
removeLauncherIcon();
|
||||
}
|
||||
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
initPreferences();
|
||||
|
||||
findPreference(KEY_DEVICE).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
return newValue != null && !newValue.equals("");
|
||||
}
|
||||
});
|
||||
findPreference(KEY_ADDRESS).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
|
||||
return newValue != null && Patterns.DOMAIN_NAME.matcher((String) newValue).matches();
|
||||
} else {
|
||||
return newValue != null && !((String) newValue).isEmpty();
|
||||
}
|
||||
}
|
||||
});
|
||||
findPreference(KEY_PORT).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (newValue != null) {
|
||||
try {
|
||||
int value = Integer.parseInt((String) newValue);
|
||||
return value > 0 && value <= 65536;
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
findPreference(KEY_INTERVAL).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (newValue != null) {
|
||||
try {
|
||||
int value = Integer.parseInt((String) newValue);
|
||||
return value > 0;
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Preference.OnPreferenceChangeListener numberValidationListener = new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (newValue != null) {
|
||||
try {
|
||||
int value = Integer.parseInt((String) newValue);
|
||||
return value >= 0;
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
findPreference(KEY_DISTANCE).setOnPreferenceChangeListener(numberValidationListener);
|
||||
findPreference(KEY_ANGLE).setOnPreferenceChangeListener(numberValidationListener);
|
||||
|
||||
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
|
||||
alarmIntent = PendingIntent.getBroadcast(this, 0, new Intent(this, AutostartReceiver.class), 0);
|
||||
|
||||
if (sharedPreferences.getBoolean(KEY_STATUS, false)) {
|
||||
startTrackingService(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLauncherIcon() {
|
||||
String className = MainActivity.class.getCanonicalName().replace(".MainActivity", ".Launcher");
|
||||
ComponentName componentName = new ComponentName(getPackageName(), className);
|
||||
PackageManager packageManager = getPackageManager();
|
||||
if (packageManager.getComponentEnabledSetting(componentName) != PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
|
||||
packageManager.setComponentEnabledSetting(
|
||||
componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setMessage(getString(R.string.hidden_alert));
|
||||
builder.setPositiveButton(android.R.string.ok, null);
|
||||
builder.show();
|
||||
}
|
||||
}
|
||||
|
||||
private void addShortcuts(String action, int name) {
|
||||
Intent shortcutIntent = new Intent(Intent.ACTION_MAIN);
|
||||
shortcutIntent.setComponent(new ComponentName(getPackageName(), ShortcutActivity.class.getCanonicalName()));
|
||||
shortcutIntent.putExtra(ShortcutActivity.EXTRA_ACTION, action);
|
||||
Intent installShortCutIntent = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
|
||||
installShortCutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
|
||||
installShortCutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, getString(name));
|
||||
installShortCutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
|
||||
Intent.ShortcutIconResource.fromContext(this, R.mipmap.ic_launcher));
|
||||
|
||||
sendBroadcast(installShortCutIntent);
|
||||
}
|
||||
|
||||
private boolean hasPermission(String permission) {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
return true;
|
||||
}
|
||||
return checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
private void setPreferencesEnabled(boolean enabled) {
|
||||
findPreference(KEY_DEVICE).setEnabled(enabled);
|
||||
findPreference(KEY_ADDRESS).setEnabled(enabled);
|
||||
findPreference(KEY_PORT).setEnabled(enabled);
|
||||
findPreference(KEY_SECURE).setEnabled(enabled);
|
||||
findPreference(KEY_INTERVAL).setEnabled(enabled);
|
||||
findPreference(KEY_DISTANCE).setEnabled(enabled);
|
||||
findPreference(KEY_ANGLE).setEnabled(enabled);
|
||||
findPreference(KEY_PROVIDER).setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.equals(KEY_STATUS)) {
|
||||
if (sharedPreferences.getBoolean(KEY_STATUS, false)) {
|
||||
startTrackingService(true, false);
|
||||
} else {
|
||||
stopTrackingService();
|
||||
}
|
||||
} 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.shortcuts) {
|
||||
addShortcuts(ShortcutActivity.EXTRA_ACTION_START, R.string.shortcut_start);
|
||||
addShortcuts(ShortcutActivity.EXTRA_ACTION_STOP, R.string.shortcut_stop);
|
||||
addShortcuts(ShortcutActivity.EXTRA_ACTION_SOS, R.string.shortcut_sos);
|
||||
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);
|
||||
|
||||
if (!sharedPreferences.contains(KEY_DEVICE)) {
|
||||
String id = String.valueOf(new Random().nextInt(900000) + 100000);
|
||||
sharedPreferences.edit().putString(KEY_DEVICE, id).commit();
|
||||
((EditTextPreference) findPreference(KEY_DEVICE)).setText(id);
|
||||
}
|
||||
findPreference(KEY_DEVICE).setSummary(sharedPreferences.getString(KEY_DEVICE, null));
|
||||
}
|
||||
|
||||
private void startTrackingService(boolean checkPermission, boolean permission) {
|
||||
if (checkPermission) {
|
||||
Set<String> missingPermissions = new HashSet<>();
|
||||
if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
missingPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
}
|
||||
if (!hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION)) {
|
||||
missingPermissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
|
||||
}
|
||||
if (missingPermissions.isEmpty()) {
|
||||
permission = true;
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
requestPermissions(missingPermissions.toArray(new String[missingPermissions.size()]),
|
||||
PERMISSIONS_REQUEST_LOCATION);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (permission) {
|
||||
setPreferencesEnabled(false);
|
||||
startService(new Intent(this, TrackingService.class));
|
||||
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
15000, 15000, alarmIntent);
|
||||
} else {
|
||||
sharedPreferences.edit().putBoolean(KEY_STATUS, false).commit();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
TwoStatePreference preference = (TwoStatePreference) findPreference(KEY_STATUS);
|
||||
preference.setChecked(false);
|
||||
} else {
|
||||
CheckBoxPreference preference = (CheckBoxPreference) findPreference(KEY_STATUS);
|
||||
preference.setChecked(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopTrackingService() {
|
||||
alarmManager.cancel(alarmIntent);
|
||||
stopService(new Intent(this, TrackingService.class));
|
||||
setPreferencesEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (requestCode == PERMISSIONS_REQUEST_LOCATION) {
|
||||
boolean granted = true;
|
||||
for (int result : grantResults) {
|
||||
if (result != PackageManager.PERMISSION_GRANTED) {
|
||||
granted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
startTrackingService(false, granted);
|
||||
if (savedInstanceState == null) {
|
||||
getFragmentManager().beginTransaction().replace(android.R.id.content, new MainFragment()).commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
* Copyright 2016 - 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,14 +15,36 @@
|
||||
*/
|
||||
package org.traccar.client;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Application;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
|
||||
public class MainApplication extends Application {
|
||||
|
||||
public static final String PRIMARY_CHANNEL = "default";
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
System.setProperty("http.keepAliveDuration", String.valueOf(30 * 60 * 1000));
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
registerChannel();
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.O)
|
||||
private void registerChannel() {
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
PRIMARY_CHANNEL, getString(R.string.channel_default), NotificationManager.IMPORTANCE_MIN);
|
||||
channel.setLightColor(Color.GREEN);
|
||||
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
|
||||
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright 2012 - 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.traccar.client;
|
||||
|
||||
import android.Manifest;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.preference.TwoStatePreference;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.webkit.URLUtil;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
|
||||
public class MainFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
|
||||
|
||||
private static final String TAG = MainFragment.class.getSimpleName();
|
||||
|
||||
private static final int ALARM_MANAGER_INTERVAL = 15000;
|
||||
|
||||
public static final String KEY_DEVICE = "id";
|
||||
public static final String KEY_URL = "url";
|
||||
public static final String KEY_INTERVAL = "interval";
|
||||
public static final String KEY_DISTANCE = "distance";
|
||||
public static final String KEY_ANGLE = "angle";
|
||||
public static final String KEY_PROVIDER = "provider";
|
||||
public static final String KEY_STATUS = "status";
|
||||
|
||||
private static final int PERMISSIONS_REQUEST_LOCATION = 2;
|
||||
|
||||
private SharedPreferences sharedPreferences;
|
||||
|
||||
private AlarmManager alarmManager;
|
||||
private PendingIntent alarmIntent;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (BuildConfig.HIDDEN_APP) {
|
||||
removeLauncherIcon();
|
||||
}
|
||||
|
||||
setHasOptionsMenu(true);
|
||||
|
||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
migrateLegacyPreferences(sharedPreferences);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
initPreferences();
|
||||
|
||||
findPreference(KEY_DEVICE).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
return newValue != null && !newValue.equals("");
|
||||
}
|
||||
});
|
||||
findPreference(KEY_URL).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
return (newValue != null) && validateServerURL(newValue.toString());
|
||||
}
|
||||
});
|
||||
|
||||
findPreference(KEY_INTERVAL).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (newValue != null) {
|
||||
try {
|
||||
int value = Integer.parseInt((String) newValue);
|
||||
return value > 0;
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
Preference.OnPreferenceChangeListener numberValidationListener = new Preference.OnPreferenceChangeListener() {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (newValue != null) {
|
||||
try {
|
||||
int value = Integer.parseInt((String) newValue);
|
||||
return value >= 0;
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
findPreference(KEY_DISTANCE).setOnPreferenceChangeListener(numberValidationListener);
|
||||
findPreference(KEY_ANGLE).setOnPreferenceChangeListener(numberValidationListener);
|
||||
|
||||
alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
|
||||
alarmIntent = PendingIntent.getBroadcast(getActivity(), 0, new Intent(getActivity(), AutostartReceiver.class), 0);
|
||||
|
||||
if (sharedPreferences.getBoolean(KEY_STATUS, false)) {
|
||||
startTrackingService(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeLauncherIcon() {
|
||||
String className = MainActivity.class.getCanonicalName().replace(".MainActivity", ".Launcher");
|
||||
ComponentName componentName = new ComponentName(getActivity().getPackageName(), className);
|
||||
PackageManager packageManager = getActivity().getPackageManager();
|
||||
if (packageManager.getComponentEnabledSetting(componentName) != PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
|
||||
packageManager.setComponentEnabledSetting(
|
||||
componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
builder.setMessage(getString(R.string.hidden_alert));
|
||||
builder.setPositiveButton(android.R.string.ok, null);
|
||||
builder.show();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasPermission(String permission) {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
return true;
|
||||
}
|
||||
return ContextCompat.checkSelfPermission(getActivity(), permission) == PackageManager.PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
|
||||
private void setPreferencesEnabled(boolean enabled) {
|
||||
findPreference(KEY_DEVICE).setEnabled(enabled);
|
||||
findPreference(KEY_URL).setEnabled(enabled);
|
||||
findPreference(KEY_INTERVAL).setEnabled(enabled);
|
||||
findPreference(KEY_DISTANCE).setEnabled(enabled);
|
||||
findPreference(KEY_ANGLE).setEnabled(enabled);
|
||||
findPreference(KEY_PROVIDER).setEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.equals(KEY_STATUS)) {
|
||||
if (sharedPreferences.getBoolean(KEY_STATUS, false)) {
|
||||
startTrackingService(true, false);
|
||||
} else {
|
||||
stopTrackingService();
|
||||
}
|
||||
} else if (key.equals(KEY_DEVICE)) {
|
||||
findPreference(KEY_DEVICE).setSummary(sharedPreferences.getString(KEY_DEVICE, null));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.main, menu);
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item.getItemId() == R.id.status) {
|
||||
startActivity(new Intent(getActivity(), StatusActivity.class));
|
||||
return true;
|
||||
} else if (item.getItemId() == R.id.about) {
|
||||
startActivity(new Intent(getActivity(), AboutActivity.class));
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void initPreferences() {
|
||||
PreferenceManager.setDefaultValues(getActivity(), R.xml.preferences, false);
|
||||
|
||||
if (!sharedPreferences.contains(KEY_DEVICE)) {
|
||||
String id = String.valueOf(new Random().nextInt(900000) + 100000);
|
||||
sharedPreferences.edit().putString(KEY_DEVICE, id).apply();
|
||||
((EditTextPreference) findPreference(KEY_DEVICE)).setText(id);
|
||||
}
|
||||
findPreference(KEY_DEVICE).setSummary(sharedPreferences.getString(KEY_DEVICE, null));
|
||||
}
|
||||
|
||||
private void startTrackingService(boolean checkPermission, boolean permission) {
|
||||
if (checkPermission) {
|
||||
Set<String> missingPermissions = new HashSet<>();
|
||||
if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||
missingPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
}
|
||||
if (!hasPermission(Manifest.permission.ACCESS_COARSE_LOCATION)) {
|
||||
missingPermissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
|
||||
}
|
||||
if (missingPermissions.isEmpty()) {
|
||||
permission = true;
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
requestPermissions(missingPermissions.toArray(new String[missingPermissions.size()]),
|
||||
PERMISSIONS_REQUEST_LOCATION);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (permission) {
|
||||
setPreferencesEnabled(false);
|
||||
ContextCompat.startForegroundService(getActivity(), new Intent(getActivity(), TrackingService.class));
|
||||
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
ALARM_MANAGER_INTERVAL, ALARM_MANAGER_INTERVAL, alarmIntent);
|
||||
} else {
|
||||
sharedPreferences.edit().putBoolean(KEY_STATUS, false).apply();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
TwoStatePreference preference = (TwoStatePreference) findPreference(KEY_STATUS);
|
||||
preference.setChecked(false);
|
||||
} else {
|
||||
CheckBoxPreference preference = (CheckBoxPreference) findPreference(KEY_STATUS);
|
||||
preference.setChecked(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopTrackingService() {
|
||||
alarmManager.cancel(alarmIntent);
|
||||
getActivity().stopService(new Intent(getActivity(), TrackingService.class));
|
||||
setPreferencesEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
if (requestCode == PERMISSIONS_REQUEST_LOCATION) {
|
||||
boolean granted = true;
|
||||
for (int result : grantResults) {
|
||||
if (result != PackageManager.PERMISSION_GRANTED) {
|
||||
granted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
startTrackingService(false, granted);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean validateServerURL(String userUrl) {
|
||||
int port = Uri.parse(userUrl).getPort();
|
||||
if (URLUtil.isValidUrl(userUrl) && (port == -1 || (port > 0 && port <= 65535))
|
||||
&& (URLUtil.isHttpUrl(userUrl) || URLUtil.isHttpsUrl(userUrl))) {
|
||||
return true;
|
||||
}
|
||||
Toast.makeText(getActivity(), R.string.error_msg_invalid_url, Toast.LENGTH_LONG).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
private void migrateLegacyPreferences(SharedPreferences preferences) {
|
||||
String port = preferences.getString("port", null);
|
||||
if (port != null) {
|
||||
Log.d(TAG, "Migrating to URL preference");
|
||||
|
||||
String host = preferences.getString("address", getString(R.string.settings_url_default_value));
|
||||
String scheme = preferences.getBoolean("secure", false) ? "https" : "http";
|
||||
|
||||
Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(scheme).encodedAuthority(host + ":" + port).build();
|
||||
SharedPreferences.Editor editor = preferences.edit();
|
||||
editor.putString(KEY_URL, builder.toString());
|
||||
|
||||
editor.remove("port");
|
||||
editor.remove("address");
|
||||
editor.remove("secure");
|
||||
editor.apply();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.traccar.client;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Patterns {
|
||||
|
||||
private static final String IP_ADDRESS_STRING =
|
||||
"((25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9])\\.(25[0-5]|2[0-4]"
|
||||
+ "[0-9]|[0-1][0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1]"
|
||||
+ "[0-9]{2}|[1-9][0-9]|[1-9]|0)\\.(25[0-5]|2[0-4][0-9]|[0-1][0-9]{2}"
|
||||
+ "|[1-9][0-9]|[0-9]))";
|
||||
|
||||
private static final String UCS_CHAR = "[" +
|
||||
"\u00A0-\uD7FF" +
|
||||
"\uF900-\uFDCF" +
|
||||
"\uFDF0-\uFFEF" +
|
||||
"\uD800\uDC00-\uD83F\uDFFD" +
|
||||
"\uD840\uDC00-\uD87F\uDFFD" +
|
||||
"\uD880\uDC00-\uD8BF\uDFFD" +
|
||||
"\uD8C0\uDC00-\uD8FF\uDFFD" +
|
||||
"\uD900\uDC00-\uD93F\uDFFD" +
|
||||
"\uD940\uDC00-\uD97F\uDFFD" +
|
||||
"\uD980\uDC00-\uD9BF\uDFFD" +
|
||||
"\uD9C0\uDC00-\uD9FF\uDFFD" +
|
||||
"\uDA00\uDC00-\uDA3F\uDFFD" +
|
||||
"\uDA40\uDC00-\uDA7F\uDFFD" +
|
||||
"\uDA80\uDC00-\uDABF\uDFFD" +
|
||||
"\uDAC0\uDC00-\uDAFF\uDFFD" +
|
||||
"\uDB00\uDC00-\uDB3F\uDFFD" +
|
||||
"\uDB44\uDC00-\uDB7F\uDFFD" +
|
||||
"&&[^\u00A0[\u2000-\u200A]\u2028\u2029\u202F\u3000]]";
|
||||
|
||||
private static final String LABEL_CHAR = "a-zA-Z0-9" + UCS_CHAR;
|
||||
|
||||
private static final String IRI_LABEL =
|
||||
"[" + LABEL_CHAR + "](?:[" + LABEL_CHAR + "\\-]{0,61}[" + LABEL_CHAR + "]){0,1}";
|
||||
|
||||
private static final String RELAXED_DOMAIN_NAME =
|
||||
"(?:" + "(?:" + IRI_LABEL + "(?:\\.(?=\\S))" +"?)+" + "|" + IP_ADDRESS_STRING + ")";
|
||||
|
||||
public static final Pattern DOMAIN_NAME = Pattern.compile(RELAXED_DOMAIN_NAME);
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
* Copyright 2015 - 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.traccar.client;
|
||||
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@@ -32,43 +33,110 @@ public class Position {
|
||||
altitude = location.getAltitude();
|
||||
speed = location.getSpeed() * 1.943844; // speed in knots
|
||||
course = location.getBearing();
|
||||
if (location.getProvider() != null && !location.getProvider().equals(LocationManager.GPS_PROVIDER)) {
|
||||
accuracy = location.getAccuracy();
|
||||
}
|
||||
this.battery = battery;
|
||||
}
|
||||
|
||||
private long id;
|
||||
public long getId() { return id; }
|
||||
public void setId(long id) { this.id = 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; }
|
||||
|
||||
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; }
|
||||
|
||||
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; }
|
||||
|
||||
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; }
|
||||
|
||||
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; }
|
||||
|
||||
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; }
|
||||
|
||||
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; }
|
||||
|
||||
public double getCourse() {
|
||||
return course;
|
||||
}
|
||||
|
||||
public void setCourse(double course) {
|
||||
this.course = course;
|
||||
}
|
||||
|
||||
private double accuracy;
|
||||
|
||||
public double getAccuracy() {
|
||||
return accuracy;
|
||||
}
|
||||
|
||||
public void setAccuracy(double accuracy) {
|
||||
this.accuracy = accuracy;
|
||||
}
|
||||
|
||||
private double battery;
|
||||
public double getBattery() { return battery; }
|
||||
public void setBattery(double battery) { this.battery = battery; }
|
||||
|
||||
public double getBattery() {
|
||||
return battery;
|
||||
}
|
||||
|
||||
public void setBattery(double battery) {
|
||||
this.battery = battery;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.traccar.client;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
@@ -23,7 +22,6 @@ import android.content.SharedPreferences;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Build;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -58,10 +56,10 @@ public abstract class PositionProvider {
|
||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
|
||||
|
||||
deviceId = preferences.getString(MainActivity.KEY_DEVICE, null);
|
||||
interval = Long.parseLong(preferences.getString(MainActivity.KEY_INTERVAL, null)) * 1000;
|
||||
distance = Integer.parseInt(preferences.getString(MainActivity.KEY_DISTANCE, null));
|
||||
angle = Integer.parseInt(preferences.getString(MainActivity.KEY_ANGLE, null));
|
||||
deviceId = preferences.getString(MainFragment.KEY_DEVICE, "undefined");
|
||||
interval = Long.parseLong(preferences.getString(MainFragment.KEY_INTERVAL, "600")) * 1000;
|
||||
distance = Integer.parseInt(preferences.getString(MainFragment.KEY_DISTANCE, "0"));
|
||||
angle = Integer.parseInt(preferences.getString(MainFragment.KEY_ANGLE, "0"));
|
||||
|
||||
if (distance > 0 || angle > 0) {
|
||||
requestInterval = MINIMUM_INTERVAL;
|
||||
@@ -69,7 +67,7 @@ public abstract class PositionProvider {
|
||||
requestInterval = interval;
|
||||
}
|
||||
|
||||
type = preferences.getString(MainActivity.KEY_PROVIDER, "gps");
|
||||
type = preferences.getString(MainFragment.KEY_PROVIDER, "gps");
|
||||
}
|
||||
|
||||
public abstract void startUpdates();
|
||||
@@ -89,16 +87,11 @@ public abstract class PositionProvider {
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ECLAIR)
|
||||
public static double getBatteryLevel(Context context) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,14 +19,13 @@ import android.net.Uri;
|
||||
|
||||
public class ProtocolFormatter {
|
||||
|
||||
public static String formatRequest(String address, int port, boolean secure, Position position) {
|
||||
return formatRequest(address, port, secure, position, null);
|
||||
public static String formatRequest(String url, Position position) {
|
||||
return formatRequest(url, position, null);
|
||||
}
|
||||
|
||||
public static String formatRequest(String address, int port, boolean secure, Position position, String alarm) {
|
||||
|
||||
Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(secure ? "https" : "http").encodedAuthority(address + ':' + port)
|
||||
public static String formatRequest(String url, Position position, String alarm) {
|
||||
Uri serverUrl = Uri.parse(url);
|
||||
Uri.Builder builder = serverUrl.buildUpon()
|
||||
.appendQueryParameter("id", position.getDeviceId())
|
||||
.appendQueryParameter("timestamp", String.valueOf(position.getTime().getTime() / 1000))
|
||||
.appendQueryParameter("lat", String.valueOf(position.getLatitude()))
|
||||
@@ -34,6 +33,7 @@ public class ProtocolFormatter {
|
||||
.appendQueryParameter("speed", String.valueOf(position.getSpeed()))
|
||||
.appendQueryParameter("bearing", String.valueOf(position.getCourse()))
|
||||
.appendQueryParameter("altitude", String.valueOf(position.getAltitude()))
|
||||
.appendQueryParameter("accuracy", String.valueOf(position.getAccuracy()))
|
||||
.appendQueryParameter("batt", String.valueOf(position.getBattery()));
|
||||
|
||||
if (alarm != null) {
|
||||
@@ -42,5 +42,4 @@ public class ProtocolFormatter {
|
||||
|
||||
return builder.build().toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.traccar.client;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -56,6 +57,7 @@ public class RequestManager {
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setReadTimeout(TIMEOUT);
|
||||
connection.setConnectTimeout(TIMEOUT);
|
||||
connection.setRequestMethod("POST");
|
||||
connection.connect();
|
||||
inputStream = connection.getInputStream();
|
||||
while (inputStream.read() != -1);
|
||||
@@ -68,7 +70,7 @@ public class RequestManager {
|
||||
inputStream.close();
|
||||
}
|
||||
} catch (IOException secondError) {
|
||||
return false;
|
||||
Log.w(RequestManager.class.getSimpleName(), secondError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.traccar.client;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
@@ -23,27 +22,81 @@ import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.content.pm.ShortcutInfoCompat;
|
||||
import android.support.v4.content.pm.ShortcutManagerCompat;
|
||||
import android.support.v4.graphics.drawable.IconCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class ShortcutActivity extends Activity {
|
||||
public class ShortcutActivity extends AppCompatActivity {
|
||||
|
||||
public static final String EXTRA_ACTION = "action";
|
||||
public static final String EXTRA_ACTION_START = "start";
|
||||
public static final String EXTRA_ACTION_STOP = "stop";
|
||||
public static final String EXTRA_ACTION_SOS = "sos";
|
||||
public static final String ACTION_START = "start";
|
||||
public static final String ACTION_STOP = "stop";
|
||||
public static final String ACTION_SOS = "sos";
|
||||
|
||||
private static final String ALARM_SOS = "sos";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
checkShortcutAction(getIntent());
|
||||
if (!executeAction(getIntent())) {
|
||||
setContentView(R.layout.list);
|
||||
|
||||
final String[] items = new String[] {
|
||||
getString(R.string.shortcut_start),
|
||||
getString(R.string.shortcut_stop),
|
||||
getString(R.string.shortcut_sos)
|
||||
};
|
||||
|
||||
ListView listView = findViewById(android.R.id.list);
|
||||
|
||||
listView.setAdapter(new ArrayAdapter<>(
|
||||
this, android.R.layout.simple_list_item_1, items));
|
||||
|
||||
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
setShortcutResult(items[position], R.mipmap.ic_start, ACTION_START);
|
||||
break;
|
||||
case 1:
|
||||
setShortcutResult(items[position], R.mipmap.ic_stop, ACTION_STOP);
|
||||
break;
|
||||
case 2:
|
||||
setShortcutResult(items[position], R.mipmap.ic_sos, ACTION_SOS);
|
||||
break;
|
||||
}
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
checkShortcutAction(intent);
|
||||
executeAction(intent);
|
||||
}
|
||||
|
||||
private void setShortcutResult(String label, @DrawableRes int iconResId, String action) {
|
||||
Intent intent = new Intent(Intent.ACTION_DEFAULT, null, this, ShortcutActivity.class);
|
||||
intent.putExtra(EXTRA_ACTION, action);
|
||||
|
||||
ShortcutInfoCompat shortcut = new ShortcutInfoCompat.Builder(this, action)
|
||||
.setShortLabel(label)
|
||||
.setIcon(IconCompat.createWithResource(this, iconResId))
|
||||
.setIntent(intent)
|
||||
.build();
|
||||
|
||||
setResult(RESULT_OK, ShortcutManagerCompat.createShortcutResultIntent(this, shortcut));
|
||||
}
|
||||
|
||||
@SuppressWarnings("MissingPermission")
|
||||
@@ -60,14 +113,11 @@ public class ShortcutActivity extends Activity {
|
||||
if (location != null) {
|
||||
|
||||
Position position = new Position(
|
||||
preferences.getString(MainActivity.KEY_DEVICE, null),
|
||||
preferences.getString(MainFragment.KEY_DEVICE, null),
|
||||
location, PositionProvider.getBatteryLevel(this));
|
||||
|
||||
String request = ProtocolFormatter.formatRequest(
|
||||
preferences.getString(MainActivity.KEY_ADDRESS, null),
|
||||
Integer.parseInt(preferences.getString(MainActivity.KEY_PORT, null)),
|
||||
preferences.getBoolean(MainActivity.KEY_SECURE, false),
|
||||
position, ALARM_SOS);
|
||||
preferences.getString(MainFragment.KEY_URL, null), position, ALARM_SOS);
|
||||
|
||||
RequestManager.sendRequestAsync(request, new RequestManager.RequestHandler() {
|
||||
@Override
|
||||
@@ -85,34 +135,35 @@ public class ShortcutActivity extends Activity {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkShortcutAction(Intent intent) {
|
||||
private boolean executeAction(Intent intent) {
|
||||
String action;
|
||||
if (intent.hasExtra("shortcutAction")) {
|
||||
action = intent.getBooleanExtra("shortcutAction", false)
|
||||
? EXTRA_ACTION_START : EXTRA_ACTION_STOP;
|
||||
? ACTION_START : ACTION_STOP;
|
||||
} else {
|
||||
action = intent.getStringExtra(EXTRA_ACTION);
|
||||
}
|
||||
if (action != null) {
|
||||
switch (action) {
|
||||
case EXTRA_ACTION_START:
|
||||
case ACTION_START:
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.edit().putBoolean(MainActivity.KEY_STATUS, true).commit();
|
||||
startService(new Intent(this, TrackingService.class));
|
||||
.edit().putBoolean(MainFragment.KEY_STATUS, true).apply();
|
||||
ContextCompat.startForegroundService(this, new Intent(this, TrackingService.class));
|
||||
Toast.makeText(this, R.string.status_service_create, Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
case EXTRA_ACTION_STOP:
|
||||
case ACTION_STOP:
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.edit().putBoolean(MainActivity.KEY_STATUS, false).commit();
|
||||
.edit().putBoolean(MainFragment.KEY_STATUS, false).apply();
|
||||
stopService(new Intent(this, TrackingService.class));
|
||||
Toast.makeText(this, R.string.status_service_destroy, Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
case EXTRA_ACTION_SOS:
|
||||
case ACTION_SOS:
|
||||
sendAlarm();
|
||||
break;
|
||||
}
|
||||
}
|
||||
finish();
|
||||
}
|
||||
return action != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 - 2013 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
* Copyright 2012 - 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,19 +21,20 @@ import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Set;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
public class StatusActivity extends ListActivity {
|
||||
public class StatusActivity extends AppCompatActivity {
|
||||
|
||||
private static final int LIMIT = 20;
|
||||
|
||||
private static final LinkedList<String> messages = new LinkedList<String>();
|
||||
private static final Set<ArrayAdapter<String>> adapters = new HashSet<ArrayAdapter<String>>();
|
||||
private static final LinkedList<String> messages = new LinkedList<>();
|
||||
private static final Set<ArrayAdapter<String>> adapters = new HashSet<>();
|
||||
|
||||
private static void notifyAdapters() {
|
||||
for (ArrayAdapter<String> adapter : adapters) {
|
||||
@@ -61,9 +62,10 @@ public class StatusActivity extends ListActivity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.status);
|
||||
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, messages);
|
||||
setListAdapter(adapter);
|
||||
setContentView(R.layout.list);
|
||||
adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, android.R.id.text1, messages);
|
||||
ListView listView = findViewById(android.R.id.list);
|
||||
listView.setAdapter(adapter);
|
||||
adapters.add(adapter);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.traccar.client;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManager;
|
||||
import android.preference.PreferenceManager;
|
||||
@@ -36,9 +35,7 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
|
||||
private Handler handler;
|
||||
private SharedPreferences preferences;
|
||||
|
||||
private String address;
|
||||
private int port;
|
||||
private boolean secure;
|
||||
private String url;
|
||||
|
||||
private PositionProvider positionProvider;
|
||||
private DatabaseHelper databaseHelper;
|
||||
@@ -47,12 +44,8 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
|
||||
private PowerManager.WakeLock wakeLock;
|
||||
|
||||
private void lock() {
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
wakeLock.acquire();
|
||||
} else {
|
||||
wakeLock.acquire(WAKE_LOCK_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
private void unlock() {
|
||||
if (wakeLock.isHeld()) {
|
||||
@@ -64,7 +57,7 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
|
||||
this.context = context;
|
||||
handler = new Handler();
|
||||
preferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if (preferences.getString(MainActivity.KEY_PROVIDER, "gps").equals("mixed")) {
|
||||
if (preferences.getString(MainFragment.KEY_PROVIDER, "gps").equals("mixed")) {
|
||||
positionProvider = new MixedPositionProvider(context, this);
|
||||
} else {
|
||||
positionProvider = new SimplePositionProvider(context, this);
|
||||
@@ -73,9 +66,7 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
|
||||
networkManager = new NetworkManager(context, this);
|
||||
isOnline = networkManager.isOnline();
|
||||
|
||||
address = preferences.getString(MainActivity.KEY_ADDRESS, null);
|
||||
port = Integer.parseInt(preferences.getString(MainActivity.KEY_PORT, null));
|
||||
secure = preferences.getBoolean(MainActivity.KEY_SECURE, false);
|
||||
url = preferences.getString(MainFragment.KEY_URL, null);
|
||||
|
||||
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, getClass().getName());
|
||||
@@ -164,7 +155,7 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
|
||||
public void onComplete(boolean success, Position result) {
|
||||
if (success) {
|
||||
if (result != null) {
|
||||
if (result.getDeviceId().equals(preferences.getString(MainActivity.KEY_DEVICE, null))) {
|
||||
if (result.getDeviceId().equals(preferences.getString(MainFragment.KEY_DEVICE, null))) {
|
||||
send(result);
|
||||
} else {
|
||||
delete(result);
|
||||
@@ -199,7 +190,7 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
|
||||
private void send(final Position position) {
|
||||
log("send", position);
|
||||
lock();
|
||||
String request = ProtocolFormatter.formatRequest(address, port, secure, position);
|
||||
String request = ProtocolFormatter.formatRequest(url, position);
|
||||
RequestManager.sendRequestAsync(request, new RequestManager.RequestHandler() {
|
||||
@Override
|
||||
public void onComplete(boolean success) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012 - 2015 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
* Copyright 2012 - 2017 Anton Tananaev (anton.tananaev@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,11 +23,10 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class TrackingService extends Service {
|
||||
|
||||
private static final String TAG = TrackingService.class.getSimpleName();
|
||||
@@ -35,35 +34,14 @@ public class TrackingService extends Service {
|
||||
|
||||
private TrackingController trackingController;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private static Notification createNotification(Context context) {
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
|
||||
return new Notification.Builder(context)
|
||||
return new NotificationCompat.Builder(context, MainApplication.PRIMARY_CHANNEL)
|
||||
.setContentTitle(context.getString(R.string.app_name))
|
||||
.setContentText(context.getString(R.string.settings_status_on_summary))
|
||||
.setContentIntent(pendingIntent)
|
||||
.setPriority(Notification.PRIORITY_MIN)
|
||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
.build();
|
||||
|
||||
} else {
|
||||
|
||||
Notification notification = new Notification(android.R.drawable.stat_notify_sync_noanim, null, 0);
|
||||
try {
|
||||
Method method = notification.getClass().getMethod("setLatestEventInfo", Context.class, CharSequence.class, CharSequence.class, PendingIntent.class);
|
||||
try {
|
||||
method.invoke(notification, context, context.getString(R.string.app_name), context.getString(R.string.settings_status_on_summary), pendingIntent);
|
||||
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
} catch (SecurityException | NoSuchMethodException e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
return notification;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ECLAIR)
|
||||
@@ -94,10 +72,8 @@ public class TrackingService extends Service {
|
||||
trackingController = new TrackingController(this);
|
||||
trackingController.start();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
|
||||
startForeground(NOTIFICATION_ID, createNotification(this));
|
||||
startService(new Intent(this, HideNotificationService.class));
|
||||
}
|
||||
ContextCompat.startForegroundService(this, new Intent(this, HideNotificationService.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,18 +81,12 @@ public class TrackingService extends Service {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onStart(Intent intent, int startId) {
|
||||
if (intent != null) {
|
||||
AutostartReceiver.completeWakefulIntent(intent);
|
||||
}
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.ECLAIR)
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
onStart(intent, startId);
|
||||
if (intent != null) {
|
||||
AutostartReceiver.completeWakefulIntent(intent);
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@@ -125,9 +95,7 @@ public class TrackingService extends Service {
|
||||
Log.i(TAG, "service destroy");
|
||||
StatusActivity.addMessage(getString(R.string.status_service_destroy));
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {
|
||||
stopForeground(true);
|
||||
}
|
||||
|
||||
if (trackingController != null) {
|
||||
trackingController.stop();
|
||||
|
||||
|
До Ширина: | Высота: | Размер: 3.6 KiB |
|
До Ширина: | Высота: | Размер: 2.4 KiB |
|
До Ширина: | Высота: | Размер: 4.8 KiB |
|
До Ширина: | Высота: | Размер: 7.2 KiB |
@@ -1,56 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/logo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginLeft="@dimen/about_margin"
|
||||
android:layout_marginStart="@dimen/about_margin"
|
||||
android:layout_marginTop="@dimen/about_margin"
|
||||
android:src="@drawable/logo"
|
||||
android:contentDescription="@string/app_logo" />
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_margin="@dimen/about_margin"
|
||||
android:layout_toRightOf="@+id/logo"
|
||||
android:layout_toEndOf="@+id/logo"
|
||||
android:padding="@dimen/spacing_normal"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/about_spacing"
|
||||
android:layout_marginBottom="@dimen/spacing_normal"
|
||||
android:text="@string/app_name"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/about_spacing"
|
||||
android:layout_marginBottom="@dimen/spacing_normal"
|
||||
android:text="@string/about_description" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/about_spacing"
|
||||
android:layout_marginBottom="@dimen/spacing_normal"
|
||||
android:text="@string/about_license" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/about_spacing"
|
||||
android:text="@string/about_web"
|
||||
android:autoLink="web" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ListView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
@@ -1,5 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
@@ -1,19 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/status"
|
||||
android:title="@string/menu_status"
|
||||
android:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/shortcuts"
|
||||
android:title="@string/menu_shortcuts"
|
||||
android:showAsAction="never" />
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/about"
|
||||
android:title="@string/menu_about"
|
||||
android:showAsAction="never" />
|
||||
app:showAsAction="never" />
|
||||
|
||||
</menu>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/clear"
|
||||
android:title="@string/menu_clear"
|
||||
android:showAsAction="always" />
|
||||
app:showAsAction="always" />
|
||||
|
||||
</menu>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/primary"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/primary"/>
|
||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/white"/>
|
||||
<foreground android:drawable="@mipmap/ic_sos_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/white"/>
|
||||
<foreground android:drawable="@mipmap/ic_sos_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/white"/>
|
||||
<foreground android:drawable="@mipmap/ic_start_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/white"/>
|
||||
<foreground android:drawable="@mipmap/ic_start_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/white"/>
|
||||
<foreground android:drawable="@mipmap/ic_stop_foreground"/>
|
||||
</adaptive-icon>
|
||||
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/white"/>
|
||||
<foreground android:drawable="@mipmap/ic_stop_foreground"/>
|
||||
</adaptive-icon>
|
||||
|
После Ширина: | Высота: | Размер: 4.2 KiB |
|
После Ширина: | Высота: | Размер: 3.0 KiB |
|
После Ширина: | Высота: | Размер: 3.1 KiB |
|
После Ширина: | Высота: | Размер: 1.5 KiB |
|
После Ширина: | Высота: | Размер: 3.2 KiB |
|
После Ширина: | Высота: | Размер: 1.7 KiB |
|
После Ширина: | Высота: | Размер: 3.1 KiB |
|
После Ширина: | Высота: | Размер: 1.6 KiB |
|
После Ширина: | Высота: | Размер: 2.5 KiB |
|
После Ширина: | Высота: | Размер: 1.7 KiB |
|
После Ширина: | Высота: | Размер: 1.9 KiB |
|
После Ширина: | Высота: | Размер: 930 B |
|
После Ширина: | Высота: | Размер: 2.0 KiB |
|
После Ширина: | Высота: | Размер: 1.0 KiB |
|
После Ширина: | Высота: | Размер: 2.0 KiB |
|
После Ширина: | Высота: | Размер: 943 B |
|
После Ширина: | Высота: | Размер: 5.9 KiB |
|
После Ширина: | Высота: | Размер: 3.8 KiB |
|
После Ширина: | Высота: | Размер: 4.5 KiB |
|
После Ширина: | Высота: | Размер: 2.1 KiB |
|
После Ширина: | Высота: | Размер: 4.6 KiB |
|
После Ширина: | Высота: | Размер: 2.4 KiB |
|
После Ширина: | Высота: | Размер: 4.5 KiB |
|
После Ширина: | Высота: | Размер: 2.1 KiB |
|
После Ширина: | Высота: | Размер: 9.4 KiB |
|
После Ширина: | Высота: | Размер: 7.4 KiB |
|
После Ширина: | Высота: | Размер: 7.3 KiB |
|
После Ширина: | Высота: | Размер: 4.0 KiB |
|
После Ширина: | Высота: | Размер: 7.6 KiB |
|
После Ширина: | Высота: | Размер: 4.6 KiB |
|
После Ширина: | Высота: | Размер: 7.3 KiB |
|
После Ширина: | Высота: | Размер: 4.0 KiB |
|
После Ширина: | Высота: | Размер: 13 KiB |
|
После Ширина: | Высота: | Размер: 8.8 KiB |
|
После Ширина: | Высота: | Размер: 11 KiB |
|
После Ширина: | Высота: | Размер: 5.4 KiB |
|
После Ширина: | Высота: | Размер: 11 KiB |
|
После Ширина: | Высота: | Размер: 6.2 KiB |
|
После Ширина: | Высота: | Размер: 11 KiB |
|
После Ширина: | Высота: | Размер: 5.4 KiB |
@@ -2,14 +2,15 @@
|
||||
<resources>
|
||||
<string name="app_name">عميل Traccar</string>
|
||||
<string name="app_logo">Traccar</string>
|
||||
<string name="shortcut_start">Traccar - بدء</string>
|
||||
<string name="shortcut_stop">Traccar - إيقاف</string>
|
||||
<string name="settings_id_title">معرف الجهاز</string>
|
||||
<string name="settings_address_title">عنوان الخادم</string>
|
||||
<string name="settings_address_summary">اسم النطاق أو عنوان بروتوكول الإنترنت</string>
|
||||
<string name="settings_port_title">منفذ الخادم</string>
|
||||
<string name="settings_port_summary">تعقب منفذ خادم تي سي بي</string>
|
||||
<string name="settings_url_title">رابط الخادم</string>
|
||||
<string name="settings_url_summary">رابط خادم التتبع</string>
|
||||
<string name="settings_interval_title">تردد</string>
|
||||
<string name="settings_interval_summary">فترة التقرير بالثواني</string>
|
||||
<string name="settings_distance_title">المسافة</string>
|
||||
<string name="settings_distance_summary">مسافة التقرير بالميتر</string>
|
||||
<string name="settings_angle_title">الزاوية</string>
|
||||
<string name="settings_angle_summary">زاوية التقرير بالدرجات</string>
|
||||
<string name="settings_status_title">حالة الخدمة</string>
|
||||
<string name="settings_status_off">بدء</string>
|
||||
<string name="settings_status_on">إيقاف</string>
|
||||
@@ -29,11 +30,11 @@
|
||||
<string name="about_description">محدد الموقع في الوقت الفعلي لأجهزة Android. متوافق مع خادم Traccar ونظم تعقب أخرى </string>
|
||||
<string name="about_license">هذا التطبيق مجاني ومفتوح المصدر، الكود المصدري مرخص تحت رخصة Apache الإصدار 2.0 و متاح على GitHub.</string>
|
||||
<string name="about_web">لمزيد من المعلومات زر \nwww.traccar.org/client</string>
|
||||
<string name="status_service_create">تم إنشاء الخدمة</string>
|
||||
<string name="status_service_destroy">تم تدمير الخدمة</string>
|
||||
<string name="status_send_success">تم الإرسال بنجاح</string>
|
||||
<string name="status_send_fail">فشل الإرسال</string>
|
||||
<string name="status_location_update">تحديث الموقع</string>
|
||||
<string name="status_connectivity_change">تغير الارتباط</string>
|
||||
<string name="hidden_app_name">إعدادات الجهاز</string>
|
||||
<string name="hidden_alert">تم إخفاء التطبيق. لفتحه مجددا رجاءا اتصل بـ8722227 (TRACCAR).</string>
|
||||
<string name="error_msg_invalid_url">أرجو إدخال رابط صحيح http:// أو https://</string>
|
||||
</resources>
|
||||
|
||||
@@ -2,14 +2,7 @@
|
||||
<resources>
|
||||
<string name="app_name">Traccar клиент</string>
|
||||
<string name="app_logo">Traccar</string>
|
||||
<string name="shortcut_start">Traccar -Старт</string>
|
||||
<string name="shortcut_stop">Traccar - Стоп</string>
|
||||
<string name="shortcut_sos">Traccar SOS</string>
|
||||
<string name="settings_id_title">Идентификатор</string>
|
||||
<string name="settings_address_title">Адрес на сървъра</string>
|
||||
<string name="settings_address_summary">Домейн или IP адрес</string>
|
||||
<string name="settings_port_title">Порт на сървъра</string>
|
||||
<string name="settings_port_summary">ТСР порт на сървъра</string>
|
||||
<string name="settings_interval_title">Честота</string>
|
||||
<string name="settings_interval_summary">Докладван интервал в сек.</string>
|
||||
<string name="settings_distance_title">Разстояние</string>
|
||||
@@ -21,11 +14,6 @@
|
||||
<string name="settings_status_on">Стоп</string>
|
||||
<string name="settings_status_off_summary">Услугата е спряна</string>
|
||||
<string name="settings_status_on_summary">Услугата работи</string>
|
||||
<string name="settings_secure_title">Шифроване</string>
|
||||
<string name="settings_secure_off">Активиране</string>
|
||||
<string name="settings_secure_on">Деактивиране</string>
|
||||
<string name="settings_secure_off_summary">Шифроване изкл.</string>
|
||||
<string name="settings_secure_on_summary">Шифроване вкл.</string>
|
||||
<string name="settings_provider_title">Доставчик на местоположение</string>
|
||||
<string name="settings_provider_summary">Източник на данни за местоположението</string>
|
||||
<string name="settings_provider_gps">GPS</string>
|
||||
@@ -40,8 +28,6 @@
|
||||
<string name="about_description">Real time GPS tracker for Android devices. Compatible with Traccar Server and other tracking systems.</string>
|
||||
<string name="about_license">This application is free and open source, source code is licensed under Apache License Version 2.0 and available on GitHub.</string>
|
||||
<string name="about_web">For more information visit\nwww.traccar.org/client</string>
|
||||
<string name="status_service_create">Услугата е създадена</string>
|
||||
<string name="status_service_destroy">Услугата е премахната</string>
|
||||
<string name="status_send_success">Успешно изпращане</string>
|
||||
<string name="status_send_fail">Грешка в изпращането</string>
|
||||
<string name="status_location_update">Местоположението е обновено</string>
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources>
|
||||
<string name="app_name">Traccar ক্লায়েন্ট</string>
|
||||
<string name="app_logo">Traccar</string>
|
||||
<string name="settings_id_title">ডিভাইস সনাক্তকারী</string>
|
||||
<string name="settings_url_title">সার্ভার URL</string>
|
||||
<string name="settings_url_summary">ট্র্যাকিং সার্ভার URL</string>
|
||||
<string name="settings_interval_title">ফ্রিকোয়েন্সি</string>
|
||||
<string name="settings_interval_summary">রিপোর্টিং বিরতি - সেকেন্ডে</string>
|
||||
<string name="settings_distance_title">দূরত্ব</string>
|
||||
<string name="settings_distance_summary">রিপোর্টিং বিরতি - মিটারে</string>
|
||||
<string name="settings_angle_title">অ্যাঙ্গেল</string>
|
||||
<string name="settings_angle_summary">রিপোর্টিং অ্যাঙ্গেল - ডিগ্রিতে</string>
|
||||
<string name="settings_status_title">সার্ভিসের অবস্থা</string>
|
||||
<string name="settings_status_off">চালু</string>
|
||||
<string name="settings_status_on">বন্ধ</string>
|
||||
<string name="settings_status_off_summary">সার্ভিস বন্ধ হয়েছে</string>
|
||||
<string name="settings_status_on_summary">সার্ভিস চলমান</string>
|
||||
<string name="settings_provider_title">লোকেশন প্রদানকারী</string>
|
||||
<string name="settings_provider_summary">লোকেশন ডেটা উৎস</string>
|
||||
<string name="settings_provider_gps">জিপিএস প্রদানকারী</string>
|
||||
<string name="settings_provider_network">নেটওয়ার্ক প্রদানকারী</string>
|
||||
<string name="settings_provider_mixed">মিশ্র প্রদানকারী</string>
|
||||
<string name="settings_foreground_title">ফোরগ্রাউন্ড সার্ভিস</string>
|
||||
<string name="settings_foreground_summary">সার্ভিসের পূর্ববর্তিতা বৃদ্ধি</string>
|
||||
<string name="menu_status">অবস্থা</string>
|
||||
<string name="menu_about">সম্পর্কে / সম্বন্ধে</string>
|
||||
<string name="menu_shortcuts">শর্টকাট যুক্ত করা</string>
|
||||
<string name="menu_clear">পরিষ্কার</string>
|
||||
<string name="about_description">অ্যান্ড্রয়েড ডিভাইসের জন্য রিয়েল টাইম GPS ট্র্যাকার। Traccar সার্ভার এবং অন্যান্য ট্র্যাকিং সিস্টেমগুলির সাথে সামঞ্জস্যপূর্ণ।</string>
|
||||
<string name="about_license">এই অ্যাপ্লিকেশনটি বিনামূল্যে প্রদানকৃত এবং ওপেন সোর্স, সোর্স কোডটি Apache License Version 2.0 এর অধীনে লাইসেন্স করা এবং GitHub এ রক্ষিত।</string>
|
||||
<string name="about_web">আরও তথ্যের জন্য www.traccar.org/client দেখুন</string>
|
||||
<string name="status_send_success">সফলভাবে পাঠান হয়েছে</string>
|
||||
<string name="status_send_fail">পাঠান ব্যর্থ হয়েছে</string>
|
||||
<string name="status_location_update">অবস্থান আপডেট</string>
|
||||
<string name="status_connectivity_change">সংযোগ পরিবর্তন হয়েছে</string>
|
||||
<string name="hidden_app_name">ডিভাইস সেটিংস</string>
|
||||
<string name="hidden_alert">অ্যাপ্লিকেশনটি লুকানো আছে। আবার খুলতে ডায়াল করুন 8722227 (TRACCAR)।</string>
|
||||
<string name="error_msg_invalid_url">দয়া করে একটি ভ্যালিড http:// বা https:// URL লিখুন</string>
|
||||
</resources>
|
||||
@@ -2,25 +2,20 @@
|
||||
<resources>
|
||||
<string name="app_name">Traccar klient</string>
|
||||
<string name="app_logo">Traccar</string>
|
||||
<string name="shortcut_start">Traccar - Spustit</string>
|
||||
<string name="shortcut_stop">Traccar - Zastavit</string>
|
||||
<string name="shortcut_sos">Traccar - SOS</string>
|
||||
<string name="settings_id_title">Identifikátor zařízení</string>
|
||||
<string name="settings_address_title">Adresa serveru</string>
|
||||
<string name="settings_address_summary">Doménové jméno nebo IP adresa</string>
|
||||
<string name="settings_port_title">Port</string>
|
||||
<string name="settings_port_summary">TCP port sledovacího serveru</string>
|
||||
<string name="settings_url_title">URL serveru</string>
|
||||
<string name="settings_url_summary">URL sledovacího serveru</string>
|
||||
<string name="settings_interval_title">Frekvence</string>
|
||||
<string name="settings_interval_summary">Reportuji interval v sekundách</string>
|
||||
<string name="settings_distance_title">Vzdálenost</string>
|
||||
<string name="settings_distance_summary">Reportuji vzdálenost v metrech</string>
|
||||
<string name="settings_angle_title">Úhel</string>
|
||||
<string name="settings_angle_summary">Reportuji úhel ve stupních</string>
|
||||
<string name="settings_status_title">Stav služby</string>
|
||||
<string name="settings_status_off">Start</string>
|
||||
<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_secure_title">Šifrování</string>
|
||||
<string name="settings_secure_off">Povolit</string>
|
||||
<string name="settings_secure_on">Zakázat</string>
|
||||
<string name="settings_secure_off_summary">Šifrování zakázáno</string>
|
||||
<string name="settings_secure_on_summary">Šifrování povoleno</string>
|
||||
<string name="settings_provider_title">Poskytovatel zaměření</string>
|
||||
<string name="settings_provider_summary">Zdroj zaměřovacích dat</string>
|
||||
<string name="settings_provider_gps">GPS</string>
|
||||
@@ -35,12 +30,11 @@
|
||||
<string name="about_description">GPS sledovací aplikace pracující v reálném čase pro zařízení s operačním systémem Android. Kompatibilní s Traccar serverem a dalšími sledovacími systémy.</string>
|
||||
<string name="about_license">Tato aplikace je zdarma a open source, zdrojový kód je licencován pod Apache License Version 2.0 a je přístupný na GitHub.</string>
|
||||
<string name="about_web">Pro více informací navštivte\nwww.traccar.org/client</string>
|
||||
<string name="status_service_create">Služba vytvořena</string>
|
||||
<string name="status_service_destroy">Služba zastavena</string>
|
||||
<string name="status_send_success">Úspěšně odesláno</string>
|
||||
<string name="status_send_fail">Odesílání selhalo</string>
|
||||
<string name="status_location_update">Aktualizace pozice</string>
|
||||
<string name="status_connectivity_change">Změna připojení</string>
|
||||
<string name="hidden_app_name">Nastavení zařízení</string>
|
||||
<string name="hidden_alert">Aplikace byla skryta. Pro znovuotevření vytočte 8722227 (TRACCAR)</string>
|
||||
<string name="error_msg_invalid_url">Prosím vložte platnou http:// nebo https:// URL</string>
|
||||
</resources>
|
||||
|
||||
@@ -2,31 +2,26 @@
|
||||
<resources>
|
||||
<string name="app_name">Traccar klient</string>
|
||||
<string name="app_logo">Traccar</string>
|
||||
<string name="shortcut_start">Traccar - Start</string>
|
||||
<string name="shortcut_stop">Traccar - Stop</string>
|
||||
<string name="shortcut_sos">SOS</string>
|
||||
<string name="settings_id_title">Indentificere Enhed</string>
|
||||
<string name="settings_address_title">Server adresse</string>
|
||||
<string name="settings_address_summary">Domænenavn eller IP adresse</string>
|
||||
<string name="settings_port_title">Server port</string>
|
||||
<string name="settings_port_summary">Tracking server TCP port</string>
|
||||
<string name="settings_id_title">Enheds ID</string>
|
||||
<string name="settings_url_title">Server Adresse</string>
|
||||
<string name="settings_url_summary">Tracking server adresse</string>
|
||||
<string name="settings_interval_title">Tracking interval</string>
|
||||
<string name="settings_interval_summary">Rapporterings interval i sekunder</string>
|
||||
<string name="settings_distance_title">Distance</string>
|
||||
<string name="settings_distance_summary">Rapportering distance i meter</string>
|
||||
<string name="settings_angle_title">vinkel</string>
|
||||
<string name="settings_angle_summary">Rapportering i grader</string>
|
||||
<string name="settings_status_title">Service status</string>
|
||||
<string name="settings_status_off">Start</string>
|
||||
<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_secure_title">Kryptering</string>
|
||||
<string name="settings_secure_off">Aktiver</string>
|
||||
<string name="settings_secure_on">Deaktiver</string>
|
||||
<string name="settings_secure_off_summary">Kryptering deaktiveret</string>
|
||||
<string name="settings_secure_on_summary">Kryptering aktiveret</string>
|
||||
<string name="settings_provider_title">Udbyder</string>
|
||||
<string name="settings_provider_summary">Udbyder lokaliseringsdata</string>
|
||||
<string name="settings_provider_gps">GPS udbyder</string>
|
||||
<string name="settings_provider_network">Netværks udbyder</string>
|
||||
<string name="settings_provider_mixed">Mixet udbyder</string>
|
||||
<string name="settings_foreground_title">Forgrunden tjeneste</string>
|
||||
<string name="settings_foreground_title">Forgrunds tjeneste</string>
|
||||
<string name="settings_foreground_summary">Øg tjeneste prioritet</string>
|
||||
<string name="menu_status">Status</string>
|
||||
<string name="menu_about">Om</string>
|
||||
@@ -35,12 +30,11 @@
|
||||
<string name="about_description">Real tid`s GPS tracker for Android enheder. Kompatibel med Traccar Server og andre tracking systemer.</string>
|
||||
<string name="about_license">Denne application er en fri og open source, source koden er licenseret under Apache License Version 2.0 og tilgængelig på GitHub.</string>
|
||||
<string name="about_web">For mere information besøg\nwww.traccar.org/client</string>
|
||||
<string name="status_service_create">Service oprettet</string>
|
||||
<string name="status_service_destroy">Service ødelagt</string>
|
||||
<string name="status_send_success">Send succesfuld</string>
|
||||
<string name="status_send_fail">Send fejlede</string>
|
||||
<string name="status_location_update">Placering opdateret</string>
|
||||
<string name="status_connectivity_change">Connectivity forandring</string>
|
||||
<string name="hidden_app_name">Enheds indstillinger</string>
|
||||
<string name="hidden_alert">Appen er skjult. For at åbne appen igen skal du ringe til 8722227 (TRACCAR)</string>
|
||||
<string name="error_msg_invalid_url">Indtast valid http:// eller https:/ adresse</string>
|
||||
</resources>
|
||||
|
||||
@@ -2,14 +2,13 @@
|
||||
<resources>
|
||||
<string name="app_name">Traccar Client</string>
|
||||
<string name="app_logo">Traccar</string>
|
||||
<string name="shortcut_start">Traccar - Start</string>
|
||||
<string name="shortcut_stop">Traccar - Stop</string>
|
||||
<string name="shortcut_sos">Traccar - SOS</string>
|
||||
<string name="shortcut_start">Dienst starten</string>
|
||||
<string name="shortcut_stop">Dienst stoppen</string>
|
||||
<string name="shortcut_sos">SOS senden</string>
|
||||
<string name="channel_default">Primärkanal</string>
|
||||
<string name="settings_id_title">Gerätekennung</string>
|
||||
<string name="settings_address_title">Serveradresse</string>
|
||||
<string name="settings_address_summary">Domain oder IP Adresse</string>
|
||||
<string name="settings_port_title">Serverport</string>
|
||||
<string name="settings_port_summary">Port des Ortungsservers</string>
|
||||
<string name="settings_url_title">Server URL</string>
|
||||
<string name="settings_url_summary">Tracking Server URL</string>
|
||||
<string name="settings_interval_title">Frequenz</string>
|
||||
<string name="settings_interval_summary">Meldung nach Zeit in Sekunden</string>
|
||||
<string name="settings_distance_title">Entfernung</string>
|
||||
@@ -21,11 +20,6 @@
|
||||
<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_secure_title">Verschlüsselung</string>
|
||||
<string name="settings_secure_off">Aktivieren</string>
|
||||
<string name="settings_secure_on">Deaktivieren</string>
|
||||
<string name="settings_secure_off_summary">Verschlüsselung aktiviert </string>
|
||||
<string name="settings_secure_on_summary">Verschlüsselung deaktiviert</string>
|
||||
<string name="settings_provider_title">Datenherkunft</string>
|
||||
<string name="settings_provider_summary">Quelle der Positionsdaten</string>
|
||||
<string name="settings_provider_gps">GPS-Provider</string>
|
||||
@@ -40,7 +34,7 @@
|
||||
<string name="about_description">Echtzeit GPS Ortung für Android Geräte. Kompatibel mit Traccar Server und anderen Ortungsservern.</string>
|
||||
<string name="about_license">Dieses Programm ist frei und Open Source. Es ist unter Apache Lizenz Version 2.0 lizenziert und ist auf GitHub verfügbar.</string>
|
||||
<string name="about_web">Für weitere Informationen besuchen Sie www.traccar.org/client</string>
|
||||
<string name="status_service_create">Dienst installiert</string>
|
||||
<string name="status_service_create">Dienst gestartet</string>
|
||||
<string name="status_service_destroy">Dienst gestoppt</string>
|
||||
<string name="status_send_success">Erfolgreich gesendet</string>
|
||||
<string name="status_send_fail">Übertragung fehlerhaft</string>
|
||||
@@ -48,4 +42,5 @@
|
||||
<string name="status_connectivity_change">Anschlusswechsel</string>
|
||||
<string name="hidden_app_name">Geräteeinstellungen</string>
|
||||
<string name="hidden_alert">Die App wurde versteckt. Um sie wieder zu öffnen, wähle 8722227 (TRACCAR).</string>
|
||||
<string name="error_msg_invalid_url">Bitte eine gültige http:// oder https:// URL eingeben</string>
|
||||
</resources>
|
||||
|
||||