Migrate from Bazel
This commit is contained in:
commit
016dbd0814
59 changed files with 7044 additions and 0 deletions
184
content/posts/android-display-a-dialog-from-an-appwidget.md
Normal file
184
content/posts/android-display-a-dialog-from-an-appwidget.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
+++
|
||||
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?
|
||||
|
||||
<!--more-->
|
||||
|
||||
## 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
|
||||
<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*
|
||||
|
||||
```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
|
||||
<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.
|
||||
|
||||
{{ 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).
|
||||
Loading…
Add table
Add a link
Reference in a new issue