Bring task to front on android.intent.action.USER_PRESENT

15,928

Here's a slightly hackish implementation that works for me:

  • Create a simple BringToFront activity that simply finish() itself on its onCreate():

    public class BringToFront extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            finish();
        }
    
    }
    
  • In your BroadcastReceiver, start the BringToFront activity above instead of your activity_A if the action is USER_PRESENT:

    @Override
    public void onReceive(Context context, Intent intent) {
        Class<? extends Activity> activityClass = activity_A.class;
    
        if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
            activityClass = BringToFront.class;
        }
    
        Intent i = new Intent(context, activityClass);
        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(i);
    }
    

This works because the BringToFront activity has the same taskAffinity as your activity_A and starting it will make the system bring the existing task to the foreground. The BringToFront activity then immediately exit, bringing the last activity on your task (activity_B in your scenario) to the front.

It's worth noting that on API level 11 (Honeycomb), a moveTaskToFront() method is added to the system's ActivityManager service that might probably be the better way to achieve what you want.

Share:
15,928
celoftis
Author by

celoftis

Updated on June 04, 2022

Comments

  • celoftis
    celoftis almost 2 years

    BACKGROUND
    I have a task (i.e. app) with multiple activities.

    QUESTION
    How do I bring a task to the front w/o re-ordering the activity stack for that task?

    USER SCENARIO
    When the device boots (i.e. after android.intent.action.BOOT_COMPLETED broadcast is received) my app starts, call this task 1, and displays activity A (code below). As the user interacts with task 1, he/she opens activity B on the stack (activity B is now currently displayed on screen). Next the user taps the home key and opens some other task, call it task 2, then locks the screen. The user unlocks the screen, and the android.intent.action.USER_PRESENT intent is broadcast and received by my app (see manifest snippet below). My executes the startActivity() call in my IntentReceiver class as expected, but instead of just bringing the task to the foreground it creates a new task, call it task 3.

    CHANGES I'VE TRIED
    If I modify or change the Intent.FLAG_ACTIVITY_NEW_TASK to any other intent then I get this error message:

    Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?

    ...so it looks like I have to use Intent.FLAG_ACTIVITY_NEW_TASK.

    If I change the main activity's lauchMode to "singleTask" the correct task is brought to the foreground (i.e. no new task is created), but the activity stack is reordered such that activity_A is on top of the stack.

    At this point I am at a loss as to how to bring an existing task to the foreground w/o re-ordering the activity stack while listening for the android.intent.action.USER_PRESENT intent, any help would be appreciated.

    BTW, This app is being delivered on to a group of employees, not the general public, on company owned android devices.

    CODE SNIPPETS
    To start the app I setup a broadcast receiver in my manifest file.

    <application
           :
        <activity
            android:label="@string/app_name"
            android:launchMode="singleTop"
            android:name=".activities.activity_A" >
            <intent-filter >
                <action android:name="android.intent.action.MAIN" />
    
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
           :
        <receiver
            android:enabled="true"
            android:name=".utilities.IntentReceiver"
            android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
            <intent-filter >
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.USER_PRESENT" />
    
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>
    

    In my IntentReceiver class, I start my main activity...

    public class IntentReceiver extends BroadcastReceiver {
    
    @Override
    
        public void onReceive(Context context, Intent intent) {
            Intent i = new Intent(context, activity_A.class);  
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(i);  
        }
    }
    
  • celoftis
    celoftis over 12 years
    This works almost except in the following scenario: (1) The app is running; (2) user quits app (main activity calls finish()); (3) User locks screen; (4) user unlocks screen. In this scenario, the app receives the Intent.ACTION_USER_PRESENT (see my Log.i statements in logcat) so it starts and exits the BringToFront.class activity as expected, but since the app was previously exited, no other activities exist in the stack, and the user returns to the HOME screen (or whatever app was previously displayed). How do I know if the app is running so that I can start activity_A.class?
  • Prachur
    Prachur over 10 years
    You saved my time Joe. Was searching for this for last two days. A nice workaround.
  • Pierre
    Pierre over 10 years
    @Joe Anything for Pre-Honeycomb?
  • Pierre
    Pierre over 10 years
    @celoftis Did you remember to de-register your BroadcastReceiver on exit?