Some Launchers will launch an app at it’s LAUNCH activity on top of the last point the user was at. Imagine:

1. User opens app.
2. The Launcher Activity is designated at Activity A, so that’s what opens.
3. User navigates several Activities deep and ends up at Activity D (A > B > C > D).
4. User stops using app and starts making calls, checking email, etc. Time passes.
5. User wants to interact with app again, finds launcher icon, and taps it.
6. The Launcher starts the app at Activity A, since this is designated.
7. Activity A is now put on top of Activity D (stack now looks like A, B, C, D, A). This will happen regardless of launch mode.

To get around it, a common pattern is to check if the activity has been launched via launcher and is root, something like this:

1

2

3

getIntent().hasCategory(Intent.CATEGORY_LAUNCHER)

&&Intent.ACTION_MAIN.equals(getIntent().getAction())

&&!isTaskRoot()

This works well and is pretty consistent, but if called in onCreate or onResume of a device with API 19 or less, isTaskRoot may return false when it should be true (e.g., when not launched from a launcher). This is a timing issue. In later APIs, it reports true correctly, even as early as onCreate or onResume, but in older APIs (19 or earlier), it may report false during setup lifecycle callbacks (onCreate, onStart, onResume), but later correctly report true – e.g., in response to a user event.