Sathish Battula
Sathish Battula

Reputation: 67

requestlocationupdates with time interval not getting location updates in Foreground Service?

I created one foreground service to fetch the location for every 1 min somehow this service is not fetching location after sometime like one min.

I am creating one service before oreo background after oreo foreground service with in service I am trying to register for location updates but the problem is after killing app only up to one min I am getting location updates after that there is nothing I can get other than foreground service notification.

MainActivity.java

package com.practice.satya.foreground;

import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        startService();
    }
    public void startService() {
        if(Build.VERSION.SDK_INT >25){
            startForegroundService(new Intent(this, LocationFetchInForeground.class));
        }else{
            startService(new Intent(this, LocationFetchInForeground.class));
        }
    }
}



LocationUpdatesReceiver.java

package com.practice.satya.foreground;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.TaskStackBuilder;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.support.v4.app.NotificationCompat;

public class LocationUpdatesReceiver extends BroadcastReceiver {
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public void onReceive(Context context, Intent intent) {
        showNotification(context,"Location Changed","Updated location",intent);
    }
    @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
    public void showNotification(Context context, String title, String body, Intent intent) {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        int notificationId = 93;
        String channelId = "testing";
        String channelName = "testing chanel";
        int importance = NotificationManager.IMPORTANCE_HIGH;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel mChannel = new NotificationChannel(
                    channelId, channelName, importance);
            notificationManager.createNotificationChannel(mChannel);
        }

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, channelId)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(title)
                .setContentText(body);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addNextIntent(intent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
                0,
                PendingIntent.FLAG_UPDATE_CURRENT
        );
        mBuilder.setContentIntent(resultPendingIntent);

        notificationManager.notify(notificationId, mBuilder.build());
    }
}

LocationFetchInForeground.java

package com.practice.satya.foreground;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.app.TaskStackBuilder;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
import android.support.annotation.RequiresApi;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.NotificationCompat;
import android.util.Log;
import android.widget.Toast;

public class LocationFetchInForeground extends Service {
    private SensorManager sensorManager;
    private Sensor sensor;
    private TriggerEventListener triggerEventListener;

    /** indicates how to behave if the service is killed */
    int mStartMode;

    /** interface for clients that bind */
    IBinder mBinder;

    /** indicates whether onRebind should be used */
    boolean mAllowRebind;

    private static final String TAG = "MyLocationService";
    private LocationManager mLocationManager = null;
    private static final int LOCATION_INTERVAL = 1000;
    private static final float LOCATION_DISTANCE = 0f;

    private class LocationListener implements android.location.LocationListener {
        Location mLastLocation;

        public LocationListener(String provider) {
            Log.e(TAG, "LocationListener " + provider);
            mLastLocation = new Location(provider);
        }

        @Override
        public void onLocationChanged(Location location) {
            Log.e(TAG, "onLocationChanged: " + location);
            Toast.makeText(getApplicationContext(),"onLocationUpdated", Toast.LENGTH_LONG).show();
            Intent intent=new Intent();
            showNotification(getApplicationContext(),"Location Changed","Updated location",intent);
            mLastLocation.set(location);
        }

        @Override
        public void onProviderDisabled(String provider) {
            Log.e(TAG, "onProviderDisabled: " + provider);
        }

        @Override
        public void onProviderEnabled(String provider) {
            Log.e(TAG, "onProviderEnabled: " + provider);
        }

        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {
            Log.e(TAG, "onStatusChanged: " + provider);
        }
    }

    /*
    LocationListener[] mLocationListeners = new LocationListener[]{
            new LocationListener(LocationManager.GPS_PROVIDER),
            new LocationListener(LocationManager.NETWORK_PROVIDER)
    };
    */

    LocationListener[] mLocationListeners = new LocationListener[]{
            new LocationListener(LocationManager.GPS_PROVIDER)
    };



    /** Called when the service is being created. */
    @Override
    public void onCreate() {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            //For creating the Foreground Service
            NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            String channelId = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? getNotificationChannel(notificationManager) : "";
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId);
            Notification notification = notificationBuilder.setOngoing(true)
                    .setContentTitle("Location service")
                    .setContentText("This service is used to fetch location in background")
                    .setSmallIcon(R.mipmap.ic_launcher)
                    // .setPriority(PRIORITY_MIN)
                    .setCategory(NotificationCompat.CATEGORY_SERVICE)
                    .build();
            startForeground(1, notification);
        }
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        sensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);

        triggerEventListener = new TriggerEventListener() {
            @Override
            public void onTrigger(TriggerEvent event) {
                // Do work
                Toast.makeText(getApplicationContext(), "Location Updated", Toast.LENGTH_LONG).show();
                Intent intent = new Intent();
                showNotification(getApplicationContext(), "Motion Changed", "Updated location", intent);
            }
        };
        if (sensor != null) {
            sensorManager.requestTriggerSensor(triggerEventListener, sensor);
        }


        Log.e(TAG, "onCreate");

        initializeLocationManager();
    }

    /** The service is starting, due to a call to startService() */
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Let it continue running until it is stopped.
        Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
            try {

//                Intent intenter = new Intent(this,LocationUpdatesReceiver.class);
//                PendingIntent proximityIntent = PendingIntent.getBroadcast(this, 0, intenter, PendingIntent.FLAG_UPDATE_CURRENT);
//                mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
//                        LOCATION_INTERVAL,
//                        LOCATION_DISTANCE,
//                        proximityIntent);
                Intent intenter2 = new Intent(this,LocationUpdatesReceiver.class);
                PendingIntent proximityIntent2 = PendingIntent.getBroadcast(this, 0, intenter2, PendingIntent.FLAG_UPDATE_CURRENT);
                mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
                        LOCATION_INTERVAL,
                        LOCATION_DISTANCE,
                        proximityIntent2);
//
//            mLocationManager.requestLocationUpdates(
//                    LocationManager.GPS_PROVIDER,
//                    LOCATION_INTERVAL,
//                    LOCATION_DISTANCE,
//                    mLocationListeners[0]
//            );

            } catch (java.lang.SecurityException ex) {
                Log.i(TAG, "fail to request location update, ignore", ex);
            } catch (IllegalArgumentException ex) {
                Log.d(TAG, "network provider does not exist, " + ex.getMessage());
            }
        return START_STICKY;
    }

    /** A client is binding to the service with bindService() */
    @Override
    public IBinder onBind(Intent intent) {
        return mBinder;
    }

    /** Called when all clients have unbound with unbindService() */
    @Override
    public boolean onUnbind(Intent intent) {
        return mAllowRebind;
    }

    /** Called when a client is binding to the service with bindService()*/
    @Override
    public void onRebind(Intent intent) {

    }

    /** Called when The service is no longer used and is being destroyed */

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
        Log.e(TAG, "onDestroy");
        super.onDestroy();
        if (mLocationManager != null) {
            for (int i = 0; i < mLocationListeners.length; i++) {
                try {
                    if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                        return;
                    }
                    mLocationManager.removeUpdates(mLocationListeners[i]);
                } catch (Exception ex) {
                    Log.i(TAG, "fail to remove location listener, ignore", ex);
                }
            }
        }
    }
    private void initializeLocationManager() {
        Log.e(TAG, "initializeLocationManager - LOCATION_INTERVAL: "+ LOCATION_INTERVAL + " LOCATION_DISTANCE: " + LOCATION_DISTANCE);
        if (mLocationManager == null) {
            mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
        }
    }
    @RequiresApi(Build.VERSION_CODES.O)
    private String getNotificationChannel(NotificationManager notificationManager){
        String channelId = "ForegroundLocationFetch";
        String channelName = getResources().getString(R.string.app_name);
        NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH);
        channel.setImportance(NotificationManager.IMPORTANCE_NONE);
        channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
        notificationManager.createNotificationChannel(channel);
        return channelId;
    }

    public void showNotification(Context context, String title, String body, Intent intent) {
        NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

        int notificationId = 234;
        String channelId = "testing";
        String channelName = "testing chanel";
        int importance = NotificationManager.IMPORTANCE_HIGH;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            NotificationChannel mChannel = new NotificationChannel(
                    channelId, channelName, importance);
            notificationManager.createNotificationChannel(mChannel);
        }

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, channelId)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle(title)
                .setContentText(body);

        TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
        stackBuilder.addNextIntent(intent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
                0,
                PendingIntent.FLAG_UPDATE_CURRENT
        );
        mBuilder.setContentIntent(resultPendingIntent);

        notificationManager.notify(notificationId, mBuilder.build());
    }
}


AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.practice.satya.foreground">

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-feature android:name="android.hardware.location.network"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name=".LocationFetchInForeground" />
        <receiver android:name=".LocationUpdatesReceiver"/>
    </application>

</manifest>



Upvotes: 0

Views: 1587

Answers (2)

Nicolas Delahaie
Nicolas Delahaie

Reputation: 31

In my experience with a React Native project using Expo Go, I've noticed a similar issue. When using an Android phone, whether I build the app or launch it with Expo Go, I only receive location updates when I'm actively moving. This behavior doesn't occur on iOS.

It seems that on Android, the background task for updating location doesn't trigger unless you're in motion. It waits for movement before updating the location.

Hope this helps!

Upvotes: 0

Ahmed mohamed hussien
Ahmed mohamed hussien

Reputation: 56

if your code is working right, some times android limit location updates due to power saving so make sure that your phone is charged more than 30% and your location is on ' high accuracy ':

package de.conlance.kotlinclean.stackoverflow

import android.annotation.SuppressLint
import android.app.Notification.EXTRA_NOTIFICATION_ID
import android.content.Intent
import android.os.IBinder
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import android.app.*
import android.content.Context
import android.location.Location
import android.location.LocationListener
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import de.conlance.kotlinclean.R


class ForGroundService : Service() {
    companion object {
        val CHANNEL_ID = "1956"
        val notificationId = 252
        val ACTION_SNOOZE = "de.conlance.kotlinclean.stopservice"
        var cnt = 0

    }

    var locationListener: LocationListener? = null
    var locationManager: LocationManager? = null
    override fun onBind(intent: Intent?): IBinder? = null
    override fun onCreate() {
        // Start up the thread running the service
        createCh()
        startForeground(notificationId, NotificationCompat.Builder(this, CHANNEL_ID).build())


    }

    override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {

        // If we get killed, after returning from here, restart
        //Main Thread
        showNotification("Service is Running")
        doWork()
        return START_NOT_STICKY
    }

    fun doWork() {
        getLocation() {
            showNotification(it)
        }
    }

    override fun onDestroy() {
        Log.v("ForService", "Service Is Dead")
        RemoveUpdates()
        showNotification("Service is Destroyed restart app .")
        stopForeground(true)


    }

    //Create Notification Channel ID .

    @SuppressLint("InlinedApi")
    private fun showNotification(msg: String) {
        val stopintent = Intent(this, MyBroadcastReceiver::class.java).apply {
            ACTION_SNOOZE
            putExtra(EXTRA_NOTIFICATION_ID, 0)
        }

        val stoppendingintent: PendingIntent =
            PendingIntent.getBroadcast(this, 0, stopintent, 0)

        val builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("My notification")
            .setContentText(msg)
            .setStyle(
                NotificationCompat.BigTextStyle()
                    .bigText(msg)
            )
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .addAction(
                R.mipmap.ic_launcher_round, "StopService",
                stoppendingintent
            )

        with(NotificationManagerCompat.from(this)) {
            // notificationId is a unique int for each notification that you must define
            notify(notificationId, builder.build())
        }
    }

    fun Context.getLocation(onResult: (String) -> Unit = {}) {
        val context = this
        locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager?

        locationListener = object : LocationListener {
            override fun onLocationChanged(location: Location?) {
                location?.let {
                    onResult("cntrefresh {${++cnt}} lat-> ${it.latitude} , lng ${it.longitude} ")
                    //send Location To Activity and then send it to Parse Location Function......

                }
            }

            override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
                //   Timber.tag(MyTag).v("on Status Changed $provider  $status")
            }

            override fun onProviderEnabled(provider: String?) {
                //  Timber.tag(MyTag).v("on Provider Enabled $provider")
            }

            override fun onProviderDisabled(provider: String?) {
                //   Timber.tag(MyTag).v("on Provider Disabled $provider")
            }
        }// location Listner
        try {
            locationManager?.let {
                if (it.isProviderEnabled(LocationManager.GPS_PROVIDER) && it.isProviderEnabled(LocationManager.NETWORK_PROVIDER))
                    it.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 1000, 0f, locationListener)
                else {
                    //fail.value = Failure.GPSError
                    onResult("Gps Error")

                }

            }
        } catch (ex: SecurityException) {
            //  fail.value = Failure.SecurityError
            onResult("Permission")

        }
    }

    private fun RemoveUpdates() {
        locationListener?.let {
            locationManager?.removeUpdates(it)

        }
    }

    fun createCh() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            // Create the NotificationChannel
            val name = "randname"
            val descriptionText = "dumdum"
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val mChannel = NotificationChannel(CHANNEL_ID, name, importance)
            mChannel.description = descriptionText
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this
            val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(mChannel)
        }
    }

}

Upvotes: 1

Related Questions