+++
template = "article.html"
title = "Android: display a Dialog from an AppWidget"
date = 2014-04-06T22:27:19+02:00
description = "A workaround for displaying dialogs from Android AppWidgets, which normally can't show dialogs due to context limitations."
[taxonomies]
tags = ["android"]
+++
## 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*
```java
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*
```java
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*
```xml
```
Then in the activity itself, set a transparent background:
*Set a transparent background*
```java
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*
```xml
```
The second issue is more visible. The theme `Theme.Translucent.NoTitleBar`
refers to a pre-ICS theme, hence the Gingerbread-looking dialog.
{{ img(src="/images/articles/android-display-a-dialog-from-an-appwidget/1-dialog-gb-theme.png", caption="Default theme") }}
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*
```java
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();
```
{{ img(src="/images/articles/android-display-a-dialog-from-an-appwidget/2-dialog-holo-theme.png", caption="Holo theme") }}
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:
{{ img(src="/images/articles/android-display-a-dialog-from-an-appwidget/3-in-app-shared-dialog.png", caption="Dialog on top of a basic 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*
```java
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](https://github.com/Kernald/android-dialog-activity-sample).