2

I'm trying to get coordinates using GPS in android. I'm successfully getting location in foreground but whenever I put app in background GPS sign vanishes and it stops locating point while in background. I went with different versions of android, some locating location points (below 8.0) and some aren't (Pie).

How to keep running GPS in background in Pie.I tried different SO answers but didn't get solution.

I'm using Service to run app in background and getting coordinates using Broadcast receiver. But I'm not getting points in Pie version.

Here's my MainActivity.java

public class MainActivity extends AppCompatActivity {

    private LocationManager locationManager;
    private LocationListener locationListener;
    private double latitude, longitude;
    BroadcastReceiver broadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        /*inflating layout*/
        riderFirstName = findViewById(R.id.rider_fName);
        riderLastName = findViewById(R.id.rider_lName);
        riderNote = findViewById(R.id.note);
        logout = findViewById(R.id.logout);     

        if (!runtime_permissions()) {
            Intent i = new Intent(getApplicationContext(), GPS_Service.class);
            startService(i);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();

        if (broadcastReceiver==null){
            broadcastReceiver=new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {

                    double lat = (double) intent.getExtras().get("latitude");
                    double lng= (double) intent.getExtras().get("longitude");
                    Log.i("lat", String.valueOf(lat));
                    Log.i("lang", String.valueOf(lng));
                    Log.i("lang", String.valueOf(RiderID));

                }
            };
        }
        registerReceiver(broadcastReceiver, new IntentFilter("location_update"));
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        if (broadcastReceiver!=null)
            unregisterReceiver(broadcastReceiver);
    }

    private boolean runtime_permissions() {
        if (Build.VERSION.SDK_INT >= 23 && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

            requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 100);

            return true;
        }
        return false;
    }


    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == 100) {
            if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                Intent i = new Intent(getApplicationContext(), GPS_Service.class);
                startService(i);
            } else {
                runtime_permissions();
            }
        }
    }

}

Here's my Service class

public class GPS_Service extends Service {
    PowerManager.WakeLock wakeLock;

    private LocationListener listener;
    private LocationManager locationManager;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @SuppressLint("InvalidWakeLockTag")
    @Override
    public void onCreate() {

        listener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                Intent i = new Intent("location_update");
                i.putExtra("latitude",  location.getLatitude());
                i.putExtra("longitude", location.getLongitude());

                sendBroadcast(i);
            }

            @Override
            public void onStatusChanged(String s, int i, Bundle bundle) {

            }

            @Override
            public void onProviderEnabled(String s) {

            }

            @Override
            public void onProviderDisabled(String s) {
                Intent i = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(i);
            }

        };

        locationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);

        //noinspection MissingPermission
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, CommonObjects.DELAY_LOCATION, 0, listener);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if(locationManager != null){
            //noinspection MissingPermission
            locationManager.removeUpdates(listener);
        }
    }
}

Here's Manifest

 <!-- my permissions -->
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
Zoe
  • 27,060
  • 21
  • 118
  • 148
Irfan Akram
  • 718
  • 1
  • 11
  • 20
  • As of Andriod 8 and above, location updates from the background service are only received a few times in an hour. Try using a foreground service. – Shubham Panchal Jun 02 '19 at 08:52
  • @ShubhamPanchal - Can you please refer or answer code for foreground service? It would be greate help. I"m trying but failing every time – Irfan Akram Jun 02 '19 at 09:42
  • You can get the code [here](https://stackoverflow.com/questions/8828639/get-gps-location-via-a-service-in-android?noredirect=1&lq=1) and [here](https://stackoverflow.com/questions/28535703/best-way-to-get-user-gps-location-in-background-in-android?rq=1). You can refer to do official docs [here](https://developer.android.com/about/versions/oreo/background-location-limits). – Shubham Panchal Jun 02 '19 at 10:43

1 Answers1

1

By using startForegroundService() instead of startService() I got the solution my my question (get GPS location in background) for Oreo (8.0) and above versions.

For implement we have to add a Foreground permission in Manifest and a startForeground(); method in Service class as shown below:

Here's my updated code of MianActivity.java

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ...    

        if (!runtime_permissions()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        {
            Intent serviceIntent = new Intent(context, YourService.class);
            ContextCompat.startForegroundService(context, serviceIntent );
        }
        else
        {
            context.startService(new Intent(context, YourService.class));
        }
        }
    }

updated my Service class

@SuppressLint("InvalidWakeLockTag")
    @Override
    public void onCreate() {

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            startMyOwnForeground();
        else
            startForeground(1, new Notification());

     ...

}

private void startMyOwnForeground(){
        String NOTIFICATION_CHANNEL_ID = "com.example.simpleapp";
        String channelName = "My Background Service";
        NotificationChannel chan = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            chan = new NotificationChannel(NOTIFICATION_CHANNEL_ID, channelName, NotificationManager.IMPORTANCE_NONE);
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            chan.setLightColor(Color.BLUE);
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            chan.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        }
        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        assert manager != null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            manager.createNotificationChannel(chan);
        }

        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
        Notification notification = notificationBuilder.setOngoing(true)
                .setContentTitle("App is running in background")
                .setPriority(NotificationManager.IMPORTANCE_MIN)
                .setCategory(Notification.CATEGORY_SERVICE)
                .build();
        startForeground(2, notification);
    }

Updated Manifest permission

    ...
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
Irfan Akram
  • 718
  • 1
  • 11
  • 20
  • Im having the same problem, has anybody tried this lately to verify it still works in 2021? – programmer3 Jul 26 '21 at 12:13
  • @programmer3 - This problem is still present. lol. Actually, it depends on the manufacturer. Most of the manufacturers doesn't allow any background process keep running for a long time due to battery consumption until the app is removed from the power saving mode/auto start. – Irfan Akram Jul 26 '21 at 14:42
  • Adding a foreground service is not enough to resolve this issue. In addition, you have to move the end user in the settings thru an intent so that he can remove the app from the *power saving mode/auto start* if you want your background service keep running 24/7. – Irfan Akram Jul 26 '21 at 14:46