title: Delay while launching activity from service
body: <p>I have a broadcast receiver which receives screen off broadcast, and when the screen is turned off, it launches an Activity. I've named this activity LockScreenActivity. I've added  <code>getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);</code> in <code>onCreate()</code> of the activity, so that it appears on top of the Android lockscreen, which is exactly what I want. This works well enough, mostly. Problem happens whenever I press home button to send <em>any</em> app to the background.</p>
  
  <p>When I press home button to return to home screen from any app, and then immediately press power button to turn off the screen, and press power button in a second to turn in back on, it shows the Android lock screen. My activity gets created some 3-4 seconds later. This is a huge delay and is unacceptable. In other scenarios, this delay does not happen. If I've been in home screen for some time, or some other app is open, and I click power button twice in quick succession, I see my LockScreenActivity before seeing the Android lockscreen.</p>
  
  <p>My app also has a few other normal activities (launched from App drawer) and a service which shows a persistent notification. The same LockScreenActivity is launched whenever the notification is clicked. Interestingly enough, if I press home button to minimize some app and immediately click the notification of my app, it opens the LockScreenActivity without any delay. </p>
  
  <p>I've searched a lot for any solution. Here's what I've tried out so far:</p>
  
  <ol>
  <li>Made the broadcast receiver run in separate thread by passing a handler when registering the broadcast receiver</li>
  <li>Acquired a wakelock in the broadcast receiver's <code>onReceive()</code> and released it in <code>onResume()</code> of LockScreenActivity</li>
  <li>Made a separate task stack for LockScreenActivity by specifying a different taskAffinity in manifest. I've also played with lot of combinations of the options related to activity stack, but nothing has helped so far.</li>
  <li>Instead of launching the activity directly, sent an intent to the service which then launches the activity.
  Nothing has worked, unfortunately.</li>
  </ol>
  
  <p>Here's the manifest declaration of the activity, and service:</p>
  
  <pre><code>&lt;activity
          android:name=".LockScreenActivity"
          android:label="@string/app_name"
          android:excludeFromRecents="true"
          android:taskAffinity="@string/task_lockscreen"&gt;
  &lt;/activity&gt;
  &lt;service
          android:name=".services.BaseService"
          android:enabled="true" &gt;
  &lt;/service&gt;
  </code></pre>
  
  <p>Broadcast receiver:</p>
  
  <pre><code>public class ScreenReceiver extends BroadcastReceiver {
  private static final String LOG_TAG = ScreenReceiver.class.getSimpleName();
  private static final String HANDLER_THREAD_NAME = "screen_receiver_thread";
  public static final String WAKELOCK_TAG = "lockscreen_overlay_create_wakelock";
  
  @Override
  public void onReceive(Context context, Intent intent) {
      if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
          WakeLockHelper.acquireWakeLock(WAKELOCK_TAG, context);
          Log.d(LOG_TAG, "Screen off");
          context.startService(BaseService.getServiceIntent(context, null, BaseService.ACTION_START_LOCKSCREEN_ACTIVITY));
      } else {
          if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
              Log.d(LOG_TAG, "Screen on");
          }
      }
  }
  
  public static void registerScreenReceiver(Context context){
      new BroadcastReceiverRegistration().execute(context);
  }
  
  private static class BroadcastReceiverRegistration extends AsyncTask&lt;Context, Void, Void&gt;{
      @Override
      protected Void doInBackground(Context... params) {
          Context context = params[0];
          if(Utility.checkForNullAndWarn(context, LOG_TAG)){
              return null;
          }
          HandlerThread handlerThread = new HandlerThread(HANDLER_THREAD_NAME);
          handlerThread.start();
          Looper looper = handlerThread.getLooper(); //Will block till thread is started, hence using AsyncTask
          Handler handler = new Handler(looper);
  
          IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
          filter.addAction(Intent.ACTION_SCREEN_ON);
          BroadcastReceiver mReceiver = new ScreenReceiver();
  
          context.registerReceiver(mReceiver, filter, null, handler);
          return null;
      }
  }
  }
  </code></pre>
  
  <p>WakeLockHelper is a class which manages all the wakelocks in my app. <code>registerScreenReceiver()</code> is called by the Service when it starts.</p>
  
  <p>Here's the onCreate() of LockScreenActivity:</p>
  
  <pre><code>protected void onCreate(Bundle savedInstanceState) {
      Log.d(LOG_TAG, "LockscreenActivity onCreate()");
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_lock_screen);
      if (savedInstanceState == null) {
          getFragmentManager().beginTransaction()
                  .add(R.id.container, new LockScreenFragment())
                  .commit();
      }
      getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
      getWindow().setDimAmount((float) 0.4);
      getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
  
      int systemUiVisibilityFlags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
              View.SYSTEM_UI_FLAG_FULLSCREEN |
              View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
              View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
      if(Build.VERSION.SDK_INT &gt;= Build.VERSION_CODES.KITKAT) {
          systemUiVisibilityFlags = systemUiVisibilityFlags | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
      }
      getWindow().getDecorView().setSystemUiVisibility(systemUiVisibilityFlags);
  }
  </code></pre>
  
  <p>Here's the log when things work as expected: (Screen is intially on; it is turned off and on again) </p>
  
  <pre><code>09-19 11:00:09.384  31226-31243/com.pvsagar.smartlockscreen D/ScreenReceiver﹕ Screen off
  09-19 11:00:09.384  31226-31226/com.pvsagar.smartlockscreen D/BaseService﹕ Starting lockscreen overlay.
  09-19 11:00:09.394  31226-31226/com.pvsagar.smartlockscreen D/LockScreenActivity﹕ LockscreenActivity onCreate()
  09-19 11:00:09.735  31226-31243/com.pvsagar.smartlockscreen D/ScreenReceiver﹕ Screen on
  </code></pre>
  
  <p>Not much delay between screen off and sending the intent and the LockScreenActivity actually starting. Now Screen is initially on; I press home from some app (any app, even some other activity of my own app); Screen is turned off and on again:</p>
  
  <pre><code>09-19 11:02:51.557  31226-31243/com.pvsagar.smartlockscreen D/ScreenReceiver﹕ Screen off
  09-19 11:02:51.557  31226-31226/com.pvsagar.smartlockscreen D/BaseService﹕ Starting lockscreen overlay.
  09-19 11:02:51.708  31226-31243/com.pvsagar.smartlockscreen D/ScreenReceiver﹕ Screen on
  09-19 11:02:54.851  31226-31226/com.pvsagar.smartlockscreen D/LockScreenActivity﹕ LockscreenActivity onCreate()
  </code></pre>
  
  <p>Here, as you can see, screen off broadcast is received in time, service gets the intent immediately and send the intent to LockScreenActivity, but onCreate() of LockScreenActivity is delayed by 3 seconds.</p>
  
  <p>This is how the LockScreenActivity is started by the service:</p>
  
  <pre><code>Intent lockscreenIntent = new Intent(this, LockScreenActivity.class);
  lockscreenIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  Log.d(LOG_TAG, "Starting lockscreen overlay.");
  startActivity(lockscreenIntent);
  </code></pre>
  
  <p>This is the pending intent passed to the notification (just to show that it does the same thing):</p>
  
  <pre><code>Intent notificationIntent = new Intent(context, LockScreenActivity.class);
  notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
  PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
  notificationBuilder.setContentIntent(pendingIntent);
  </code></pre>
  
  <p>I'm not having any idea why this is happening. GC is also not running too much. What could be the problem? What can I possibly do to overcome this? 
  Any suggestions/ideas would be greatly appreciated.</p>
  
  <p>The entire code can be found at: <a href="https://github.com/aravindsagar/SmartLockScreen/tree/backend_code_strengthening" rel="noreferrer">https://github.com/aravindsagar/SmartLockScreen/tree/backend_code_strengthening</a></p>