Skip to content

Commit 648e78f

Browse files
dsandlerAndroid (Google) Code Review
authored andcommitted
Merge "Notification actions API."
2 parents 66331b9 + a0a938c commit 648e78f

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)