Skip to content

Commit a0a938c

Browse files
committed
Notification actions API.
Actions will be attached to the Notification object and also used to inject additional tap targets in the default template used by Builder. Change-Id: Idd58686b9c44b2ca7bb9ec5aa8337f3bdce5b878
1 parent 2d00872 commit a0a938c

File tree

4 files changed

+230
-2
lines changed

4 files changed

+230
-2
lines changed

api/current.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3694,6 +3694,7 @@ package android.app {
36943694

36953695
public static class Notification.Builder {
36963696
ctor public Notification.Builder(android.content.Context);
3697+
method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
36973698
method public android.app.Notification.Builder addKind(java.lang.String);
36983699
method public android.app.Notification getNotification();
36993700
method public android.app.Notification.Builder setAutoCancel(boolean);

core/java/android/app/Notification.java

Lines changed: 155 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
import android.graphics.Bitmap;
2424
import android.net.Uri;
2525
import android.os.Bundle;
26+
import android.os.IBinder;
2627
import android.os.Parcel;
2728
import android.os.Parcelable;
2829
import android.text.TextUtils;
30+
import android.util.IntProperty;
2931
import android.view.View;
3032
import android.widget.ProgressBar;
3133
import android.widget.RemoteViews;
@@ -185,6 +187,13 @@ public class Notification implements Parcelable
185187
*/
186188
public RemoteViews contentView;
187189

190+
191+
/**
192+
* The view that will represent this notification in the pop-up "intruder alert" dialog.
193+
* @hide
194+
*/
195+
public RemoteViews intruderView;
196+
188197
/**
189198
* The bitmap that may escape the bounds of the panel and bar.
190199
*/
@@ -417,6 +426,64 @@ public class Notification implements Parcelable
417426

418427
private Bundle extras;
419428

429+
/**
430+
* Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
431+
* @hide
432+
*/
433+
private static class Action implements Parcelable {
434+
public int icon;
435+
public CharSequence title;
436+
public PendingIntent actionIntent;
437+
@SuppressWarnings("unused")
438+
public Action() { }
439+
private Action(Parcel in) {
440+
icon = in.readInt();
441+
title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
442+
if (in.readInt() == 1) {
443+
actionIntent = PendingIntent.CREATOR.createFromParcel(in);
444+
}
445+
}
446+
public Action(int icon_, CharSequence title_, PendingIntent intent_) {
447+
this.icon = icon_;
448+
this.title = title_;
449+
this.actionIntent = intent_;
450+
}
451+
@Override
452+
public Action clone() {
453+
return new Action(
454+
this.icon,
455+
this.title.toString(),
456+
this.actionIntent // safe to alias
457+
);
458+
}
459+
@Override
460+
public int describeContents() {
461+
return 0;
462+
}
463+
@Override
464+
public void writeToParcel(Parcel out, int flags) {
465+
out.writeInt(icon);
466+
TextUtils.writeToParcel(title, out, flags);
467+
if (actionIntent != null) {
468+
out.writeInt(1);
469+
actionIntent.writeToParcel(out, flags);
470+
} else {
471+
out.writeInt(0);
472+
}
473+
}
474+
public static final Parcelable.Creator<Action> CREATOR
475+
= new Parcelable.Creator<Action>() {
476+
public Action createFromParcel(Parcel in) {
477+
return new Action(in);
478+
}
479+
public Action[] newArray(int size) {
480+
return new Action[size];
481+
}
482+
};
483+
}
484+
485+
private Action[] actions;
486+
420487
/**
421488
* Constructs a Notification object with default values.
422489
* You might want to consider using {@link Builder} instead.
@@ -506,12 +573,17 @@ public Notification(Parcel parcel)
506573
}
507574

508575
priority = parcel.readInt();
509-
576+
510577
kind = parcel.createStringArray(); // may set kind to null
511578

512579
if (parcel.readInt() != 0) {
513580
extras = parcel.readBundle();
514581
}
582+
583+
actions = parcel.createTypedArray(Action.CREATOR);
584+
if (parcel.readInt() != 0) {
585+
intruderView = RemoteViews.CREATOR.createFromParcel(parcel);
586+
}
515587
}
516588

517589
@Override
@@ -571,6 +643,14 @@ public Notification clone() {
571643

572644
}
573645

646+
that.actions = new Action[this.actions.length];
647+
for(int i=0; i<this.actions.length; i++) {
648+
that.actions[i] = this.actions[i].clone();
649+
}
650+
if (this.intruderView != null) {
651+
that.intruderView = this.intruderView.clone();
652+
}
653+
574654
return that;
575655
}
576656

@@ -658,6 +738,15 @@ public void writeToParcel(Parcel parcel, int flags)
658738
} else {
659739
parcel.writeInt(0);
660740
}
741+
742+
parcel.writeTypedArray(actions, 0);
743+
744+
if (intruderView != null) {
745+
parcel.writeInt(1);
746+
intruderView.writeToParcel(parcel, 0);
747+
} else {
748+
parcel.writeInt(0);
749+
}
661750
}
662751

663752
/**
@@ -769,7 +858,14 @@ public String toString() {
769858
sb.append(this.kind[i]);
770859
}
771860
}
772-
sb.append("])");
861+
sb.append("]");
862+
if (actions != null) {
863+
sb.append(" ");
864+
sb.append(actions.length);
865+
sb.append(" action");
866+
if (actions.length > 1) sb.append("s");
867+
}
868+
sb.append(")");
773869
return sb.toString();
774870
}
775871

@@ -821,6 +917,7 @@ public static class Builder {
821917
private ArrayList<String> mKindList = new ArrayList<String>(1);
822918
private Bundle mExtras;
823919
private int mPriority;
920+
private ArrayList<Action> mActions = new ArrayList<Action>(3);
824921

825922
/**
826923
* Constructs a new Builder with the defaults:
@@ -1203,6 +1300,19 @@ public Builder setExtras(Bundle bag) {
12031300
return this;
12041301
}
12051302

1303+
/**
1304+
* Add an action to this notification. Actions are typically displayed by
1305+
* the system as a button adjacent to the notification content.
1306+
*
1307+
* @param icon Resource ID of a drawable that represents the action.
1308+
* @param title Text describing the action.
1309+
* @param intent PendingIntent to be fired when the action is invoked.
1310+
*/
1311+
public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
1312+
mActions.add(new Action(icon, title, intent));
1313+
return this;
1314+
}
1315+
12061316
private void setFlag(int mask, boolean value) {
12071317
if (value) {
12081318
mFlags |= mask;
@@ -1284,6 +1394,44 @@ private RemoteViews makeTickerView() {
12841394
}
12851395
}
12861396

1397+
private RemoteViews makeIntruderView() {
1398+
RemoteViews intruderView = new RemoteViews(mContext.getPackageName(),
1399+
R.layout.notification_intruder_content);
1400+
if (mLargeIcon != null) {
1401+
intruderView.setImageViewBitmap(R.id.icon, mLargeIcon);
1402+
intruderView.setViewVisibility(R.id.icon, View.VISIBLE);
1403+
} else if (mSmallIcon != 0) {
1404+
intruderView.setImageViewResource(R.id.icon, mSmallIcon);
1405+
intruderView.setViewVisibility(R.id.icon, View.VISIBLE);
1406+
} else {
1407+
intruderView.setViewVisibility(R.id.icon, View.GONE);
1408+
}
1409+
if (mContentTitle != null) {
1410+
intruderView.setTextViewText(R.id.title, mContentTitle);
1411+
}
1412+
if (mContentText != null) {
1413+
intruderView.setTextViewText(R.id.text, mContentText);
1414+
}
1415+
if (mActions.size() > 0) {
1416+
intruderView.setViewVisibility(R.id.actions, View.VISIBLE);
1417+
int N = mActions.size();
1418+
if (N>3) N=3;
1419+
final int[] BUTTONS = { R.id.action0, R.id.action1, R.id.action2 };
1420+
for (int i=0; i<N; i++) {
1421+
final Action action = mActions.get(i);
1422+
final int buttonId = BUTTONS[i];
1423+
1424+
intruderView.setViewVisibility(buttonId, View.VISIBLE);
1425+
intruderView.setImageViewResource(buttonId, action.icon);
1426+
intruderView.setContentDescription(buttonId, action.title);
1427+
intruderView.setOnClickPendingIntent(buttonId, action.actionIntent);
1428+
}
1429+
} else {
1430+
intruderView.setViewVisibility(R.id.actions, View.GONE);
1431+
}
1432+
return intruderView;
1433+
}
1434+
12871435
/**
12881436
* Combine all of the options that have been set and return a new {@link Notification}
12891437
* object.
@@ -1309,6 +1457,7 @@ public Notification getNotification() {
13091457
n.ledOffMS = mLedOffMs;
13101458
n.defaults = mDefaults;
13111459
n.flags = mFlags;
1460+
n.intruderView = makeIntruderView();
13121461
if (mLedOnMs != 0 && mLedOffMs != 0) {
13131462
n.flags |= FLAG_SHOW_LIGHTS;
13141463
}
@@ -1323,6 +1472,10 @@ public Notification getNotification() {
13231472
}
13241473
n.priority = mPriority;
13251474
n.extras = mExtras != null ? new Bundle(mExtras) : null;
1475+
if (mActions.size() > 0) {
1476+
n.actions = new Action[mActions.size()];
1477+
mActions.toArray(n.actions);
1478+
}
13261479
return n;
13271480
}
13281481
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:layout_width="match_parent"
3+
android:layout_height="wrap_content"
4+
android:orientation="vertical"
5+
android:background="#FF333333"
6+
android:padding="4dp"
7+
>
8+
<ImageView android:id="@+id/icon"
9+
android:layout_width="32dp"
10+
android:layout_height="32dp"
11+
android:scaleType="center"
12+
android:padding="4dp"
13+
/>
14+
<LinearLayout
15+
android:layout_width="match_parent"
16+
android:layout_height="40dp"
17+
android:layout_marginLeft="40dp"
18+
android:orientation="vertical"
19+
>
20+
<TextView android:id="@+id/title"
21+
android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
22+
android:layout_width="match_parent"
23+
android:layout_height="wrap_content"
24+
android:singleLine="true"
25+
android:ellipsize="marquee"
26+
android:fadingEdge="horizontal"
27+
/>
28+
<TextView android:id="@+id/text"
29+
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
30+
android:layout_width="match_parent"
31+
android:layout_height="wrap_content"
32+
android:layout_weight="1"
33+
android:layout_marginTop="-4dp"
34+
android:singleLine="true"
35+
android:ellipsize="marquee"
36+
android:fadingEdge="horizontal"
37+
/>
38+
</LinearLayout>
39+
<LinearLayout
40+
android:id="@+id/actions"
41+
android:layout_width="match_parent"
42+
android:layout_height="40dp"
43+
android:layout_marginTop="48dp"
44+
android:orientation="horizontal"
45+
android:visibility="gone"
46+
>
47+
<ImageView
48+
android:id="@+id/action0"
49+
android:layout_width="0dp"
50+
android:layout_height="match_parent"
51+
android:layout_weight="1"
52+
android:visibility="gone"
53+
/>
54+
<ImageView
55+
android:id="@+id/action1"
56+
android:layout_width="0dp"
57+
android:layout_height="match_parent"
58+
android:layout_weight="1"
59+
android:visibility="gone"
60+
/>
61+
<ImageView
62+
android:id="@+id/action2"
63+
android:layout_width="0dp"
64+
android:layout_height="match_parent"
65+
android:layout_weight="1"
66+
android:visibility="gone"
67+
/>
68+
</LinearLayout>
69+
</FrameLayout>

core/res/res/values/public.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@
194194
<java-symbol type="id" name="zoomIn" />
195195
<java-symbol type="id" name="zoomMagnify" />
196196
<java-symbol type="id" name="zoomOut" />
197+
<java-symbol type="id" name="actions" />
198+
<java-symbol type="id" name="action0" />
199+
<java-symbol type="id" name="action1" />
200+
<java-symbol type="id" name="action2" />
197201

198202
<java-symbol type="attr" name="actionModeShareDrawable" />
199203
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -1062,6 +1066,7 @@
10621066
<java-symbol type="layout" name="zoom_container" />
10631067
<java-symbol type="layout" name="zoom_controls" />
10641068
<java-symbol type="layout" name="zoom_magnify" />
1069+
<java-symbol type="layout" name="notification_intruder_content" />
10651070

10661071
<java-symbol type="anim" name="slide_in_child_bottom" />
10671072
<java-symbol type="anim" name="slide_in_right" />

0 commit comments

Comments
 (0)