Android: display a Dialog from an AppWidget
Issue
When you want to display a dialog, you don’t only need a context, you need an activity context. From an activity, displaying a dialog is pretty straightforward:
Display a dialog from an activity
new AlertDialog.Builder(MyActivity.this)
.setTitle("Dialog title")
.setMessage("Dialog message")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Handle a positive answer
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Handle a negative answer
}
})
.setIcon(R.drawable.ic_dialog_alert)
.show();
Okay, that’s a pretty usual code sample. But what about displaying it from an app-widget?
Display a Dialog from an AppWidget
What is needed to display a Dialog? An Activity. So let’s open an Activity, which will open the Dialog. When you update your AppWidget, via a RemoteView:
Open an activity from an AppWidget
Intent intent = new Intent(getApplicationContext(), MyActivity.class);
// Old activities shouldn't be in the history stack
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// Link the PendingIntent to a Button
rv.setOnClickPendingIntent(R.id.btn_dialog, pendingIntent);
When the button btn_dialog
is pressed, the activity MyActivity
is launched.
Let’s say we have the AlertDialogBuilder code from the first sample in
MyActivity.onCreate()
, we have a dialog displayed from an app-widget. But there’s
an issue: we don’t want the activity to be visible.
Hide the proxy activity
The activity must be displayed. But what about making it fully transparent? That’s an easy, two-steps task. First, in the manifest, remove any decoration and hide this activity from history:
Remove Activity decorations
<activity
android:name=".activities.MyActivity"
android:noHistory="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
/>
Then in the activity itself, set a transparent background:
Set a transparent background
public class MyActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setBackgroundDrawable(new ColorDrawable(0));
// Dialog creation goes here
}
}
At this point, there are two issues. First, if the dialog is displayed from the app-widget, it will appear in the recent apps list. That’s probably not wanted. There’s again a simple solution. In the manifest:
Hide the Activity from recent apps
<activity
android:name=".activities.MyActivity"
android:noHistory="true"
android:excludeFromRecents="true"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
/>
The second issue is more visible. The theme Theme.Translucent.NoTitleBar
refers to a pre-ICS theme, hence the Gingerbread-looking dialog.
To use the Holo theme on 3.0+ devices, the dialog construction code has to be tweaked a little:
Applying a theme to the dialog
Context context;
// For a custom theme:
context = new ContextThemeWrapper(MyActivity.this, R.style.dialog);
// For the Holo one on 3.0+ devices, fallback on 1.x/2.x devices:
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
context = new ContextThemeWrapper(MyActivity.this, android.R.style.Theme_Holo);
} else {
context = new ContextThemeWrapper(MyActivity.this, android.R.style.Theme_Dialog);
}
new AlertDialog.Builder(context)
.setTitle("Dialog title")
.setMessage("Dialog message")
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Handle a positive answer
}
})
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// Handle a negative answer
}
})
.setIcon(R.drawable.ic_dialog_alert)
.show();
If multiple dialogs are needed, the activity could be reused by adding parameters to the intent, and display the needed dialog accordingly. You can also call this activity like any other from your other activities, and share the dialog creation code. Here’s an example of a generic dialog activity, called from a button on another activity:
Last point: even if the activity is invisible, it still needs to be closed when
the dialog is hidden. Don’t forget to call Activity.finish()
when the dialogs
are dismissed. Starting with API 17, you can use a
DialogInterface.OnDismissListener()
:
Finishing the activity
new AlertDialog.Builder(context)
.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialogInterface) {
finish();
}
})
// …
.show()
You can find a full sample code on GitHub.