Say you have an app A which opens up another app B (e.g. a map), which is not controlled by you (i.e. it's a preexisting app). So now app A is in the background. Suppose an event occurs and A wants to show a floating dialog over app B's UI (while leaving app B's activity visible behind it). Is this possible?
(The usual answer to this would be to display a notification, but this is not a mass market app, and we are trying to get the user's attention very directly.)
Currently, I was trying to do something like this:
// This code runs in a class other than app A's main activity,
// and the "activity" variable used here is a reference to that activity.
Intent intent = new Intent(activity, NotificationDialogActivity.class);
// EDIT: I'm not exactly sure whether NEW_TASK helps here or not
// so I removed it, but the REORDER_TO_FRONT would ideally cause
// app A's dialog activity to be moved to the front of the back stack?
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
// The "msg" variable here is just some data being passed to the dialog activity
// I included it here only so it is clear that there is a purpose.
intent.putExtra(NotificationDialogActivity.EXTRA_MSG, msg);
activity.startActivity(intent);
from within app A (the one in the background).
But what happens when I do that is that the dialog gets inserted between the original app A activity and the app B activity on the back stack.
In order to have a dialog activity shown over another application, a few things must be done:
@android:style/Theme.Translucent.NoTitleBar
)Window.setLayout
)FLAG_ACTIVITY_NEW_TASK
)FLAG_ACTIVITY_REORDER_TO_FRONT
)Dialog
class directlyIn the code that starts the dialog activity:
Intent intent = new Intent(baseActivity, DialogActivity.class);
// NEW_TASK allows the new dialog activity to be separate from the existing activity.
// REORDER_TO_FRONT causes the dialog activity to be moved to the front,
// if it's already running.
// Without the NEW_TASK flag, the existing "base" activity
// would be moved to the front as well.
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(DialogActivity.EXTRA_SOME_PARAM, someParamValue);
// The activity must be started from the application context.
// I'm not sure why exactly.
baseActivity.getApplicationContext().startActivity(intent);
In the above, baseActivity
is a reference to the main activity of the application.
It may help to give the dialog activity a launchMode
of singleInstance
, ensuring that it never accumulates other activities in its task, but this may be unnecessary. The @android:style/Theme.Translucent.NoTitleBar
theme allows the activity underneath it to show through.
<activity
android:name=".DialogActivity"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
</activity>
For the dialog activity itself, it may be necessary to adjust its window to ensure that it doesn't fill the whole screen:
getWindow().setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
Likewise, in the dialog activity's layout XML, it may also be necessary:
android:layout_width="fill_parent"
android:layout_height="wrap_content"
For the dialog itself, you can do a lot of things, but one solution is to extend the Dialog
class:
class DialogActivity extends Dialog { ... }
To show the dialog from the activity, just create a new instance of the Dialog and call its show()
method.