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

..
18 Коммитов
Автор SHA1 Сообщение Дата
Anton Tananaev 5d8f0dfb83 Update app version 2019-01-06 14:49:43 -08:00
Anton Tananaev f42ecf9f09 Use fused location provider 2019-01-06 14:48:47 -08:00
Anton Tananaev 556856ab5c Update copyright notice 2019-01-06 14:23:45 -08:00
Anton Tananaev f9f37ead08 Split position provider implementation 2019-01-06 14:22:19 -08:00
Anton Tananaev b3ee99140e Fix unit tests 2019-01-06 12:12:51 -08:00
Anton Tananaev 85f1e09308 Fix compilation issue 2019-01-06 12:03:38 -08:00
Anton Tananaev 20fd20f425 Migrate to AndroidX libraries 2019-01-06 11:56:36 -08:00
Anton Tananaev 1ae7b27683 Use app compat classes 2019-01-06 11:44:08 -08:00
Anton Tananaev f5b12b9e74 Update project files 2019-01-06 11:41:08 -08:00
Anton Tananaev d2f653034d Update app version 2018-11-06 20:58:48 +13:00
Anton Tananaev ab5aec9721 Improvements in permissions handling 2018-11-06 20:57:17 +13:00
Anton Tananaev 1b0559c98a Update version number 2018-10-18 16:05:48 +13:00
Anton Tananaev 2e0e7ea453 Fix merge issues 2018-10-18 15:44:58 +13:00
Anton Tananaev ac6d677ff4 Explicitly select location providers 2018-10-18 15:43:07 +13:00
Anton Tananaev cbfe90757d Disable advertising id collection 2018-09-22 08:51:41 +12:00
Anton Tananaev a9f4390ae4 Update app version 2018-09-15 08:54:32 +12:00
Anton Tananaev 8a938701c8 Improve service handling 2018-09-15 08:54:09 +12:00
Anton Tananaev 2319834c5b Handle runtime exceptions 2018-09-15 08:48:37 +12:00
31 изменённых файлов: 380 добавлений и 185 удалений
+7 -7
Просмотреть файл
@@ -2,15 +2,14 @@ apply plugin: 'com.android.application'
android { android {
compileSdkVersion 28 compileSdkVersion 28
buildToolsVersion '28.0.2'
defaultConfig { defaultConfig {
applicationId "org.traccar.client" applicationId "org.traccar.client"
buildConfigField "boolean", "HIDDEN_APP", "false" buildConfigField "boolean", "HIDDEN_APP", "false"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 28 targetSdkVersion 28
versionCode 49 versionCode 54
versionName '5.12' versionName '5.17'
} }
lintOptions { lintOptions {
@@ -35,11 +34,12 @@ android {
} }
dependencies { dependencies {
implementation 'com.android.support:design:28.0.0-rc02' implementation 'com.google.android.material:material:1.1.0-alpha02'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
testImplementation 'org.robolectric:robolectric:3.8' testImplementation 'org.robolectric:robolectric:4.1'
googleImplementation 'com.google.firebase:firebase-core:16.0.3' googleImplementation 'com.google.firebase:firebase-core:16.0.6'
googleImplementation 'com.crashlytics.sdk.android:crashlytics:2.9.5' googleImplementation 'com.crashlytics.sdk.android:crashlytics:2.9.8'
googleImplementation "com.google.android.gms:play-services-location:16.0.0"
} }
if (getGradle().getStartParameter().getTaskRequests().toString().contains("Google")) { if (getGradle().getStartParameter().getTaskRequests().toString().contains("Google")) {
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2017 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+84
Просмотреть файл
@@ -0,0 +1,84 @@
/*
* Copyright 2019 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.client;
import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Location;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.android.gms.tasks.OnSuccessListener;
public class GooglePositionProvider extends PositionProvider {
private FusedLocationProviderClient fusedLocationClient;
public GooglePositionProvider(Context context, PositionListener listener) {
super(context, listener);
fusedLocationClient = LocationServices.getFusedLocationProviderClient(context);
}
@SuppressLint("MissingPermission")
public void startUpdates() {
LocationRequest locationRequest = new LocationRequest();
locationRequest.setPriority(getPriority(preferences.getString(MainFragment.KEY_ACCURACY, "medium")));
locationRequest.setInterval(distance > 0 || angle > 0 ? MINIMUM_INTERVAL : interval);
fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null);
}
public void stopUpdates() {
fusedLocationClient.removeLocationUpdates(locationCallback);
}
@SuppressLint("MissingPermission")
public void requestSingleLocation() {
fusedLocationClient.getLastLocation().addOnSuccessListener(new OnSuccessListener<Location>() {
@Override
public void onSuccess(Location location) {
if (location != null) {
listener.onPositionUpdate(new Position(deviceId, location, getBatteryLevel(context)));
}
}
});
}
private static int getPriority(String accuracy) {
switch (accuracy) {
case "high":
return LocationRequest.PRIORITY_HIGH_ACCURACY;
case "low":
return LocationRequest.PRIORITY_LOW_POWER;
default:
return LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY;
}
}
private LocationCallback locationCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
if (locationResult != null) {
for (Location location : locationResult.getLocations()) {
processLocation(location);
}
}
}
};
}
+26
Просмотреть файл
@@ -0,0 +1,26 @@
/*
* Copyright 2019 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.client;
import android.content.Context;
public class PositionProviderFactory {
public static PositionProvider create(Context context, PositionProvider.PositionListener listener) {
return new GooglePositionProvider(context, listener);
}
}
+26
Просмотреть файл
@@ -0,0 +1,26 @@
/*
* Copyright 2019 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.client;
import android.content.Context;
public class PositionProviderFactory {
public static PositionProvider create(Context context, PositionProvider.PositionListener listener) {
return new AndroidPositionProvider(context, listener);
}
}
+7
Просмотреть файл
@@ -12,6 +12,9 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-feature android:name="android.hardware.location.network" />
<uses-feature android:name="android.hardware.location.gps" />
<application <application
android:allowBackup="true" android:allowBackup="true"
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
@@ -20,6 +23,10 @@
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
android:name=".MainApplication"> android:name=".MainApplication">
<meta-data
android:name="google_analytics_adid_collection_enabled"
android:value="false" />
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:launchMode="singleTask" /> android:launchMode="singleTask" />
+2 -2
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012 - 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,7 +17,7 @@ package org.traccar.client;
import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.util.Log; import android.util.Log;
import android.widget.TextView; import android.widget.TextView;
+110
Просмотреть файл
@@ -0,0 +1,110 @@
/*
* Copyright 2019 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.client;
import android.annotation.SuppressLint;
import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Looper;
public class AndroidPositionProvider extends PositionProvider implements LocationListener {
private LocationManager locationManager;
private String provider;
public AndroidPositionProvider(Context context, PositionListener listener) {
super(context, listener);
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
provider = getProvider(preferences.getString(MainFragment.KEY_ACCURACY, "medium"));
}
@SuppressLint("MissingPermission")
public void startUpdates() {
try {
locationManager.requestLocationUpdates(
provider, distance > 0 || angle > 0 ? MINIMUM_INTERVAL : interval, 0, this);
} catch (RuntimeException e) {
listener.onPositionError(e);
}
}
public void stopUpdates() {
locationManager.removeUpdates(this);
}
@SuppressLint("MissingPermission")
public void requestSingleLocation() {
try {
Location location = locationManager.getLastKnownLocation(LocationManager.PASSIVE_PROVIDER);
if (location != null) {
listener.onPositionUpdate(new Position(deviceId, location, getBatteryLevel(context)));
} else {
locationManager.requestSingleUpdate(provider, new LocationListener() {
@Override
public void onLocationChanged(Location location) {
listener.onPositionUpdate(new Position(deviceId, location, getBatteryLevel(context)));
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}, Looper.myLooper());
}
} catch (RuntimeException e) {
listener.onPositionError(e);
}
}
private static String getProvider(String accuracy) {
switch (accuracy) {
case "high":
return LocationManager.GPS_PROVIDER;
case "low":
return LocationManager.PASSIVE_PROVIDER;
default:
return LocationManager.NETWORK_PROVIDER;
}
}
@Override
public void onLocationChanged(Location location) {
processLocation(location);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2013 - 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2013 - 2017 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2015 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2015 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+3 -3
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2017 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,8 +16,8 @@
package org.traccar.client; package org.traccar.client;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity { public class MainActivity extends AppCompatActivity {
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 - 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+6 -17
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012 - 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@ package org.traccar.client;
import android.Manifest; import android.Manifest;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
@@ -28,14 +27,14 @@ import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference; import android.preference.EditTextPreference;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.preference.TwoStatePreference; import android.preference.TwoStatePreference;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.v4.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.appcompat.app.AlertDialog;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@@ -43,9 +42,7 @@ import android.view.MenuItem;
import android.webkit.URLUtil; import android.webkit.URLUtil;
import android.widget.Toast; import android.widget.Toast;
import java.util.HashSet;
import java.util.Random; import java.util.Random;
import java.util.Set;
public class MainFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener { public class MainFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
@@ -215,19 +212,11 @@ public class MainFragment extends PreferenceFragment implements OnSharedPreferen
private void startTrackingService(boolean checkPermission, boolean permission) { private void startTrackingService(boolean checkPermission, boolean permission) {
if (checkPermission) { if (checkPermission) {
Set<String> missingPermissions = new HashSet<>(); if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
missingPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
}
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
missingPermissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
}
if (missingPermissions.isEmpty()) {
permission = true; permission = true;
} else { } else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(missingPermissions.toArray(new String[missingPermissions.size()]), requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_LOCATION);
PERMISSIONS_REQUEST_LOCATION);
} }
return; return;
} }
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2015 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2018 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2015 - 2018 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+18 -64
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2013 - 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2013 - 2019 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,50 +15,42 @@
*/ */
package org.traccar.client; package org.traccar.client;
import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.location.Criteria;
import android.location.Location; import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Looper;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.util.Log; import android.util.Log;
public class PositionProvider implements LocationListener { public abstract class PositionProvider {
private static final String TAG = PositionProvider.class.getSimpleName(); private static final String TAG = PositionProvider.class.getSimpleName();
private static final int MINIMUM_INTERVAL = 1000; protected static final int MINIMUM_INTERVAL = 1000;
public interface PositionListener { public interface PositionListener {
void onPositionUpdate(Position position); void onPositionUpdate(Position position);
void onPositionError(Throwable error);
} }
private final PositionListener listener; protected final PositionListener listener;
private final Context context; protected final Context context;
private SharedPreferences preferences; protected SharedPreferences preferences;
private LocationManager locationManager;
private String deviceId; protected String deviceId;
private long interval; protected long interval;
private double distance; protected double distance;
private double angle; protected double angle;
private Location lastLocation; protected Location lastLocation;
public PositionProvider(Context context, PositionListener listener) { public PositionProvider(Context context, PositionListener listener) {
this.context = context; this.context = context;
this.listener = listener; this.listener = listener;
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
preferences = PreferenceManager.getDefaultSharedPreferences(context); preferences = PreferenceManager.getDefaultSharedPreferences(context);
deviceId = preferences.getString(MainFragment.KEY_DEVICE, "undefined"); deviceId = preferences.getString(MainFragment.KEY_DEVICE, "undefined");
@@ -67,35 +59,13 @@ public class PositionProvider implements LocationListener {
angle = Integer.parseInt(preferences.getString(MainFragment.KEY_ANGLE, "0")); angle = Integer.parseInt(preferences.getString(MainFragment.KEY_ANGLE, "0"));
} }
@SuppressLint("MissingPermission") public abstract void startUpdates();
public void startUpdates() {
locationManager.requestLocationUpdates(
distance > 0 || angle > 0 ? MINIMUM_INTERVAL : interval, 0,
getCriteria(preferences.getString(MainFragment.KEY_ACCURACY, "medium")),
this, Looper.myLooper());
}
public static Criteria getCriteria(String accuracy) { public abstract void stopUpdates();
Criteria criteria = new Criteria();
switch (accuracy) {
case "high":
criteria.setHorizontalAccuracy(Criteria.ACCURACY_HIGH);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
break;
case "low":
criteria.setHorizontalAccuracy(Criteria.ACCURACY_LOW);
criteria.setPowerRequirement(Criteria.POWER_LOW);
break;
default:
criteria.setHorizontalAccuracy(Criteria.ACCURACY_MEDIUM);
criteria.setPowerRequirement(Criteria.POWER_MEDIUM);
break;
}
return criteria;
}
@Override public abstract void requestSingleLocation();
public void onLocationChanged(Location location) {
protected void processLocation(Location location) {
if (location != null && (lastLocation == null if (location != null && (lastLocation == null
|| location.getTime() - lastLocation.getTime() >= interval || location.getTime() - lastLocation.getTime() >= interval
|| distance > 0 && location.distanceTo(lastLocation) >= distance || distance > 0 && location.distanceTo(lastLocation) >= distance
@@ -108,23 +78,7 @@ public class PositionProvider implements LocationListener {
} }
} }
@Override protected static double getBatteryLevel(Context context) {
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
public void stopUpdates() {
locationManager.removeUpdates(this);
}
public static double getBatteryLevel(Context context) {
Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); Intent batteryIntent = context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
if (batteryIntent != null) { if (batteryIntent != null) {
int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); int level = batteryIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012 - 2016 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2012 - 2016 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+1 -1
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2015 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
+19 -52
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2016 - 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -15,29 +15,24 @@
*/ */
package org.traccar.client; package org.traccar.client;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Looper;
import android.preference.PreferenceManager; 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.view.View;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.ListView; import android.widget.ListView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.DrawableRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;
public class ShortcutActivity extends AppCompatActivity { public class ShortcutActivity extends AppCompatActivity {
public static final String EXTRA_ACTION = "action"; public static final String EXTRA_ACTION = "action";
@@ -105,44 +100,10 @@ public class ShortcutActivity extends AppCompatActivity {
@SuppressWarnings("MissingPermission") @SuppressWarnings("MissingPermission")
private void sendAlarm() { private void sendAlarm() {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); PositionProviderFactory.create(this, new PositionProvider.PositionListener() {
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = PositionProvider.getCriteria(
preferences.getString(MainFragment.KEY_ACCURACY, "medium"));
Location location = locationManager.getLastKnownLocation(locationManager.getBestProvider(criteria, true));
if (location != null) {
sendAlarmLocation(location);
} else {
locationManager.requestSingleUpdate(criteria, new LocationListener() {
@Override @Override
public void onLocationChanged(Location location) { public void onPositionUpdate(Position position) {
sendAlarmLocation(location); SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(ShortcutActivity.this);
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
@Override
public void onProviderEnabled(String provider) {
}
@Override
public void onProviderDisabled(String provider) {
}
}, Looper.myLooper());
}
}
private void sendAlarmLocation(Location location) {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
Position position = new Position(
preferences.getString(MainFragment.KEY_DEVICE, null),
location, PositionProvider.getBatteryLevel(this));
String request = ProtocolFormatter.formatRequest( String request = ProtocolFormatter.formatRequest(
preferences.getString(MainFragment.KEY_URL, null), position, ALARM_SOS); preferences.getString(MainFragment.KEY_URL, null), position, ALARM_SOS);
@@ -158,6 +119,13 @@ public class ShortcutActivity extends AppCompatActivity {
}); });
} }
@Override
public void onPositionError(Throwable error) {
Toast.makeText(ShortcutActivity.this, error.getMessage(), Toast.LENGTH_LONG).show();
}
}).requestSingleLocation();
}
private boolean executeAction(Intent intent) { private boolean executeAction(Intent intent) {
String action; String action;
if (intent.hasExtra("shortcutAction")) { if (intent.hasExtra("shortcutAction")) {
@@ -181,8 +149,7 @@ public class ShortcutActivity extends AppCompatActivity {
Toast.makeText(this, R.string.status_service_destroy, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.status_service_destroy, Toast.LENGTH_SHORT).show();
break; break;
case ACTION_SOS: case ACTION_SOS:
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
&& ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
sendAlarm(); sendAlarm();
} else { } else {
Toast.makeText(this, R.string.status_send_fail, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.status_send_fail, Toast.LENGTH_SHORT).show();
+2 -2
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012 - 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -22,7 +22,7 @@ import java.util.LinkedList;
import java.util.Set; import java.util.Set;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
+6 -2
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2015 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2015 - 2019 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -57,7 +57,7 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
this.context = context; this.context = context;
handler = new Handler(); handler = new Handler();
preferences = PreferenceManager.getDefaultSharedPreferences(context); preferences = PreferenceManager.getDefaultSharedPreferences(context);
positionProvider = new PositionProvider(context, this); positionProvider = PositionProviderFactory.create(context, this);
databaseHelper = new DatabaseHelper(context); databaseHelper = new DatabaseHelper(context);
networkManager = new NetworkManager(context, this); networkManager = new NetworkManager(context, this);
isOnline = networkManager.isOnline(); isOnline = networkManager.isOnline();
@@ -98,6 +98,10 @@ public class TrackingController implements PositionProvider.PositionListener, Ne
} }
} }
@Override
public void onPositionError(Throwable error) {
}
@Override @Override
public void onNetworkUpdate(boolean isOnline) { public void onNetworkUpdate(boolean isOnline) {
int message = isOnline ? R.string.status_network_online : R.string.status_network_offline; int message = isOnline ? R.string.status_network_online : R.string.status_network_offline;
+8 -6
Просмотреть файл
@@ -1,5 +1,5 @@
/* /*
* Copyright 2012 - 2017 Anton Tananaev (anton.tananaev@gmail.com) * Copyright 2012 - 2017 Anton Tananaev (anton@traccar.org)
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -24,8 +24,8 @@ import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
import android.os.IBinder; import android.os.IBinder;
import android.support.v4.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import android.support.v4.content.ContextCompat; import androidx.core.content.ContextCompat;
import android.util.Log; import android.util.Log;
public class TrackingService extends Service { public class TrackingService extends Service {
@@ -78,15 +78,17 @@ public class TrackingService extends Service {
Log.i(TAG, "service create"); Log.i(TAG, "service create");
StatusActivity.addMessage(getString(R.string.status_service_create)); StatusActivity.addMessage(getString(R.string.status_service_create));
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED startForeground(NOTIFICATION_ID, createNotification(this));
&& ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
trackingController = new TrackingController(this); trackingController = new TrackingController(this);
trackingController.start(); trackingController.start();
} }
startForeground(NOTIFICATION_ID, createNotification(this)); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
ContextCompat.startForegroundService(this, new Intent(this, HideNotificationService.class)); ContextCompat.startForegroundService(this, new Intent(this, HideNotificationService.class));
} }
}
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
+1 -1
Просмотреть файл
@@ -18,7 +18,7 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.PowerManager; import android.os.PowerManager;
import android.support.v4.content.ContextCompat; import androidx.core.content.ContextCompat;
import android.util.SparseArray; import android.util.SparseArray;
public abstract class WakefulBroadcastReceiver extends BroadcastReceiver { public abstract class WakefulBroadcastReceiver extends BroadcastReceiver {
+26
Просмотреть файл
@@ -0,0 +1,26 @@
/*
* Copyright 2019 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.client;
import android.content.Context;
public class PositionProviderFactory {
public static PositionProvider create(Context context, PositionProvider.PositionListener listener) {
return new AndroidPositionProvider(context, listener);
}
}
-1
Просмотреть файл
@@ -15,7 +15,6 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull; import static org.junit.Assert.assertNull;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class DatabaseHelperTest { public class DatabaseHelperTest {
@Test @Test
-1
Просмотреть файл
@@ -13,7 +13,6 @@ import java.util.Date;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class ProtocolFormatterTest { public class ProtocolFormatterTest {
@Test @Test
-1
Просмотреть файл
@@ -10,7 +10,6 @@ import org.robolectric.annotation.Config;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@RunWith(RobolectricTestRunner.class) @RunWith(RobolectricTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
public class RequestManagerTest { public class RequestManagerTest {
@Ignore @Ignore
+3 -3
Просмотреть файл
@@ -5,9 +5,9 @@ buildscript {
maven { url 'https://maven.fabric.io/public' } maven { url 'https://maven.fabric.io/public' }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.4' classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.google.gms:google-services:4.0.2' classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.25.4' classpath 'io.fabric.tools:gradle:1.26.1'
} }
} }
+3
Просмотреть файл
@@ -0,0 +1,3 @@
android.enableJetifier=true
android.useAndroidX=true
android.enableUnitTestBinaryResources=true
+1 -1
Просмотреть файл
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip