Background: We have an app that does time registration for a group of people. In this example we use a Zebra TC26 (model: TC26BK-11A222-A6) and we clock in multiple people by scanning. Next the app tracks the GPS position of the phone to locate in which field the activity is performed. The farmer can then calculated its costs per field more accuratly.
This al worked fine till android 10. Now I have on my device that I don't get a new location after like 1h or 1h30. On another device I sometimes got it longer but than it also stopped. Since Android 10 I am having issues and I found a lot of information online, but it doesn't seem to fix the issue. A normal workday:
- Start around 8 AM. and then device is in the pocket till lunch
- Lunch between 1:00 PM and 1:30 PM and again device goes in the pocket.
- End around 5PM.
So during the work they don't use the phone.
Extra:
- In the past I tried with a wakelock on the screen. This worked for android 8/9 to activate the GPS again. but this doesn't work on android 10/11
- I also added the background location access while not required but to see if I can enable "location always" if this had in affect.
- The antiDoze service was also something from few years ago to keep the CPU awake. note that the channelID for the notification is the same. I don't know if this has an influence.
- I also see in my app that most of the times (like 99%) the server still receives data from the device but the location is empty. In the 1% case, the device is not sending data.
- I don't use the fuse location provider as not all devices have the GMS service on them.
- It is possible that the answer is that I need to rewrite some things. For me this is not a problem as my end goal is to have a working product. If this is the case, then please provide me with either a detailed plan and where to put what or to provide a link to a tutorial.
Manifest: (I left out some permissions and an antiDozeService as I think they are not relevant for the GPS part)
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<activity android:name=".SplashActivity"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity"
android:launchMode="singleTop"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service
android:name=".Services.LocationTracker"
android:enabled="true"
android:foregroundServiceType="location">
</service>
Main acitivity (note the splash activity is the entry point but was added later so this is still called the main activity)
protected void onCreate(Bundle savedInstanceState)
{
...
Intent service = new Intent(this, xxx.LocationTracker.class);
service.setAction("STARTFOREGROUND_ACTION");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(service);
}else{
startService(service);
}
}
LocationTracker: (onStartCommand)
public int onStartCommand(Intent intent, int flags, int startId) {
//Show notification
Intent notificationIntent = new Intent(mContext, MainActivity.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
//Create notification channel
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = getString(R.string.service_channel_name);
String description = getString(R.string.service_channel_description);
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel("12345678", name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(this, "12345678")
.setContentTitle("My app title")
.setTicker("My app title")
.setContentText("Application is running")
.setSmallIcon(R.drawable.xxxx)
.setContentIntent(pendingIntent)
.build();
// starts this service as foreground
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
{
startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION);
//=> My latest test I added here the "FOREGROUND_SERVICE_TYPE_LOCATION"
}
else{
startForeground("12345678", notification);
}
return START_STICKY;
}
LocationTracker: (onCreate)
@Override
public void onCreate() {
//LogUtils.debug("LocationTracker service started");
mContext = getApplicationContext();
//Location listener
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
try{
if(StaticVariables.LocationAllowed)
{
if(StaticVariables.LocationTrackingActive)
{
//Check if we found a point.
Location location = getLatestPoint();
writeLocationToServer(location);
startLocationTracking();
}
else
{
//LogUtils.debug("Location 1: Location tracking is not active");
stopLocationListener();
}
}
handler.postDelayed(this, HANDLER_DELAY);
}
catch (Exception ex)
{
LogUtils.debug("Location failed to run: " + ex.getMessage());
}
}
}, 1000);
LocationTracker: (getLatestPoint)
private Location getLatestPoint()
{
Location gpsPoint = null;
Location networkPoint = null;
LogUtils.debug("Getting latest point");
if(gpsListener != null)
{
gpsPoint = gpsListener.getLastLocation();
}
if(networkListener != null)
{
networkPoint = networkListener.getLastLocation();
}
if(gpsPoint != null && networkPoint != null)
{
if(gpsPoint.getAccuracy() < networkPoint.getAccuracy())
{
return gpsPoint;
}
else
{
return networkPoint;
}
}
else if(gpsPoint != null)
{
return gpsPoint;
}
else if(networkPoint != null)
{
return networkPoint;
}
else
{
return null;
}
}
Location listener:
public CustomerLocationListener(LocationManager locationManager, String provider) {
this.locationManager = locationManager;
this.provider = provider;
}
@Override
public void onLocationChanged(Location location) {
this.location = location;
stopLocationListener();
}
@SuppressLint("MissingPermission") //=> Not an issue as this is checked before starting
public void startLocationListener()
{
if(StaticVariables.LocationAllowed)
{
if(locationManager.isProviderEnabled(provider))
{
locationManager.requestLocationUpdates(provider, GPS_TIME_INTERVAL, GPS_DISTANCE,this);
}
else
{
//LogUtils.debug("Provider: " + provider + " is not available");
}
}
}
public void stopLocationListener()
{
if(locationManager != null)
{
locationManager.removeUpdates(this); // remove this listener
}
}
build.gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion '30.0.3'
defaultConfig {
applicationId "xxxx"
minSdkVersion 21
targetSdkVersion 30
versionCode 28
versionName "VERSIONNAME"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true //For zxing
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
apply plugin: 'com.android.application'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
...
The interval was: "1 request / 20 seconds" but I have already changed this to "1 request/min"
I hope that someone can help me find a solution as this is a popular product. Thank you for your time.