14

I would like to run my service when the screen is unlocked and stop it when the screen is locked. I looked into these answers and implemented them. However, when I lock my screen the service stops as required, but when I unlock the screen it doesn't starts again.

The code for to run this service is as follows:

public class PhonePositionService extends Service {
@Override
    public void onCreate() {
    //ADDED CODE
    IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
    filter.addAction(Intent.ACTION_SCREEN_OFF);
    BroadcastReceiver mReceiver = new BootCompletedIntentReceiver();
    registerReceiver(mReceiver, filter);
    {...}
    }
@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
    int icon = R.drawable.ic_stat_bright;
    startForeground(NOTIFICATION_ID, getCompatNotification(icon));
    if (backgroundThread != null) {
      backgroundThread.start();
    }
    return START_STICKY;
  }
}

In some other file, my broadcast receiver code is as follows:

public class BootCompletedIntentReceiver extends BroadcastReceiver {
 @Override
 public void onReceive(Context context, Intent intent) {
   String action = intent.getAction();
   if(Intent.ACTION_SCREEN_ON.equals(action)) {
     // start the service
     Intent pushIntent = new Intent(context, PhonePositionService.class);
     context.startService(pushIntent);
   } else if(Intent.ACTION_SCREEN_OFF.equals(action)) {
     // stop the service
     Intent pushIntent = new Intent(context, PhonePositionService.class);
     context.stopService(pushIntent);
   }
  if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
    Intent pushIntent = new Intent(context, PhonePositionService.class);
    context.startService(pushIntent);
  }
 }
}

Then why is it so that when I unlock my phone the service does not start again?

Nitin Gurbani
  • 1,220
  • 6
  • 16
Sarah cartenz
  • 1,313
  • 2
  • 14
  • 37
  • You can add one more callback for retrieving user action by following [answer](https://stackoverflow.com/a/3463127/5308778) – yashkal Apr 10 '18 at 06:22

2 Answers2

10

First of all its not possible to detect if user has unlocked the phone until you have Admin Privilages. The issue you are facing is because you are stopping the PhonePositionService using stopService() when Screen is OFF:

public class BootCompletedIntentReceiver extends BroadcastReceiver {
 @Override
 public void onReceive(Context context, Intent intent) {
   String action = intent.getAction();
   if(Intent.ACTION_SCREEN_ON.equals(action)) {
     // start the service
     Intent pushIntent = new Intent(context, PhonePositionService.class);
     context.startService(pushIntent);
   } else if(Intent.ACTION_SCREEN_OFF.equals(action)) {
     // stop the service
     Intent pushIntent = new Intent(context, PhonePositionService.class);
     //This will stop the service
     context.stopService(pushIntent);
   }
  if ("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
    Intent pushIntent = new Intent(context, PhonePositionService.class);
    context.startService(pushIntent);
  }
 }
}

It would lead to some memory leak since BroadcastReceiver is not unregistered.

It is discouraged to keep service running in foreground for forever since it could lead to (fast) battery drainage.

I would recommend you to find other alternatives. But if your core functionality is impacted and you still want to proceed you can do following work around:

Make BootCompletedIntentReceiver as inner class for PhonePositionService. And instead of starting and stopping the service you perform your action directly.

public class PhonePositionService extends Service {
   @Override
   public void onCreate() {
       //ADDED CODE
       IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
       filter.addAction(Intent.ACTION_SCREEN_OFF);
       BroadcastReceiver mReceiver = new BootCompletedIntentReceiver();
       registerReceiver(mReceiver, filter);
       ...
    }
    ...
    private class BootCompletedIntentReceiver extends BroadcastReceiver {
       @Override
       public void onReceive(Context context, Intent intent) {
         String action = intent.getAction();
         if(Intent.ACTION_SCREEN_ON.equals(action)) {
          //DO action for SCREEN_ON
         } else if(Intent.ACTION_SCREEN_OFF.equals(action)) {
          //Do action for SCREEN_OFF
         }

       }
   }
}
Nitin Gurbani
  • 1,220
  • 6
  • 16
Sagar
  • 23,903
  • 4
  • 62
  • 62
2

That's because you are registering your receiver inside your service, which is a component like an activity that has a lifecycle and when it's destroyed your broadcast listener goes with it too. Actually I'm guessing you are leaking your Service here too, because you didn't unregister it which is another problem.

Since API 26 aka Oreo you cannot register you broadcast listener inside AndroidManifest.xml, If you want to target API 26+ your best bet is to register it in your Application class, but be aware when the system kills your app you will lose your broadcast listener too. However if you use a foreground service the system won't kill your service.

Edit: Here is an example:

import android.app.Application;
import android.content.Intent;
import android.content.IntentFilter;

/**
 * @author : M.Reza.Nasirloo@gmail.com
 * Created on: 2018-04-12
 */
public class App extends Application {

    @Override
    public void onCreate() {
    super.onCreate();
    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_SCREEN_OFF);
    filter.addAction(Intent.ACTION_SCREEN_ON);
    registerReceiver(new BootCompletedIntentReceiver(), filter);
    }
}

Don't forget to set this class inside your manifest file.

<application
    android:name=".App"
    android:allowBackup="true"

Note you need a foreground service to be run always to not miss the events.

PS: There's another solution which is a bit hacky, target a lower API version and register your listener inside the manifest file.

Looks like targeting a lower API is out of table. It seems google knew some developers would use it to get around this.

M. Reza Nasirloo
  • 16,434
  • 2
  • 29
  • 41
  • I unregistered it onDestroy() function. In the example codes I saw they all called registerReceiver() inside their onCreate function (activity or service). Where am i suppose to register it then? Can you provide some code examples in your answer please. – Sarah cartenz Apr 12 '18 at 16:28
  • @Sarahcartenz I've added a sample code to my answer. – M. Reza Nasirloo Apr 12 '18 at 16:56