Fragments and Notifications: Target different Activities from Notification; depending on screen configuration
android, android-fragments, android-notifications, java
Solution
This is a really good question!
I think one can safely rule out the possibility of the Service probing for the current configuration to decide what activity to target with the PendingIntent.
I'd agree that it would be preferable to keep UI decisions at the UI layer, but having the service make the decision would certainly be an expedient choice. You might use a static method on a UI layer class to keep the decision code technically outside of the service (e.g., a static `createArticlePendingIntent()` method on `NewsReaderActivity` that the service uses to build its `Notification`).
So, how does one decide what activity to launch from a notification, if the activity to launch depends on screen configuration?
Use a `getActivity()` `PendingIntent` for `NewsReaderActivity` in your `Notification`, with enough extras that `NewsReaderActivity` knows that it is in this "show the article" scenario. Before it calls `setContentView()`, have it determine if `ArticleActivity` is the right answer. If so, `NewsReaderActivity` calls `startActivity()` to launch `ArticleActivity`, then calls `finish()` to get rid of itself (or not, if you want BACK from the article to go to `NewsReaderActivity`).
Or, use a `getActivity()` `PendingIntent` for `ICanHazArticleActivity` in your `Notification`. `ICanHazArticleActivity` has `Theme.NoDisplay`, so it will not have a UI. It makes the decision of whether to launch `NewsReaderActivity` or `ArticleActivity`, calls `startActivity()` on the right answer, and then calls `finish()`. The advantage over the previous solution is that there is no brief flash of `NewsReaderActivity` if the end destination is `ArticleActivity`.
Or, use the `createArticlePendingIntent()` option I mentioned in the first paragraph of my answer.
There may be other options as well, but those are what come to mind.
Problem
Question: How to decide what `Activity` a `Notification` should launch if the target might depend on the configuration (screen size, orientation etc); as is often the case when one uses `Fragment`s? Details: Let's consider the NewsReader sample that demonstrates how to use `Fragment`s to produce an app that plays well with multiple screen sizes and orientations. This app is structured as follows: - A `HeadlinesFragment`. - An `ArticleFragment`. - A "main" activity (`NewsReaderActivity`). In dual pane mode, this activity contains both the fragments. In single-pane mode, it only contains the `HeadlinesFragment`. - An `ArticleActivity`. This activity is only used in single pane mode; and it contains the `ArticleFragment`. Now, suppose I were to enhance this app to add a background `Service` that listens for news updates and notifies the user via status bar notifications whenever there are new news items. A reasonable requirements listing might read like so: - If there are multiple news updates, clicking on the notification should always take the user to the headlines list. - If there's only one update, clicking on the notification should open up the brand new news article. Note that these requirements translate to different target activities depending on current configuration. In particular, - Requirement (1) in either mode = `NewsReaderActivity`. - Requirement (2) in dual-pane mode = `NewsReaderActivity`. - Requirement (2) in single-pane mode = `ArticleActivity`. What would be an elegant way to achieve (2) and (3) above? I think one can safely rule out the possibility of the `Service` probing for the current configuration to decide what activity to target with the `PendingIntent`. One solution I thought of was to skip (2) and always do (3) - i.e., always launch `ArticleActivity` if there's only one news update. This snippet from ArticleActivity looked promising: ``` @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //... //... // If we are in two-pane layout mode, this activity is no longer necessary if (getResources().getBoolean(R.bool.has_two_panes)) { finish(); return; } //... //... } ``` This code ensures that if one is viewing the `ArticleActivity`, but switches to a configuration where it is no longer required (for example from portrait to landscape); then the activity simple closes. However, this won't work in our case since the intent will have the `FLAG_ACTIVITY_NEW_TASK ` flag set; we would have created a new task, and there is no "previous" activity on the stack. So, calling `finish()` would just clear the entire stack. So, how does one decide what activity to launch from a notification, if the activity to launch depends on screen configuration?