Merge "Notification actions API."

This commit is contained in:
Daniel Sandler
2012-03-22 10:24:00 -07:00
committed by Android (Google) Code Review
4 changed files with 230 additions and 2 deletions

View File

@@ -3694,6 +3694,7 @@ package android.app {
public static class Notification.Builder {
ctor public Notification.Builder(android.content.Context);
method public android.app.Notification.Builder addAction(int, java.lang.CharSequence, android.app.PendingIntent);
method public android.app.Notification.Builder addKind(java.lang.String);
method public android.app.Notification getNotification();
method public android.app.Notification.Builder setAutoCancel(boolean);

View File

@@ -23,9 +23,11 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.IntProperty;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.RemoteViews;
@@ -185,6 +187,13 @@ public class Notification implements Parcelable
*/
public RemoteViews contentView;
/**
* The view that will represent this notification in the pop-up "intruder alert" dialog.
* @hide
*/
public RemoteViews intruderView;
/**
* The bitmap that may escape the bounds of the panel and bar.
*/
@@ -417,6 +426,64 @@ public class Notification implements Parcelable
private Bundle extras;
/**
* Structure to encapsulate an "action", including title and icon, that can be attached to a Notification.
* @hide
*/
private static class Action implements Parcelable {
public int icon;
public CharSequence title;
public PendingIntent actionIntent;
@SuppressWarnings("unused")
public Action() { }
private Action(Parcel in) {
icon = in.readInt();
title = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
if (in.readInt() == 1) {
actionIntent = PendingIntent.CREATOR.createFromParcel(in);
}
}
public Action(int icon_, CharSequence title_, PendingIntent intent_) {
this.icon = icon_;
this.title = title_;
this.actionIntent = intent_;
}
@Override
public Action clone() {
return new Action(
this.icon,
this.title.toString(),
this.actionIntent // safe to alias
);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeInt(icon);
TextUtils.writeToParcel(title, out, flags);
if (actionIntent != null) {
out.writeInt(1);
actionIntent.writeToParcel(out, flags);
} else {
out.writeInt(0);
}
}
public static final Parcelable.Creator<Action> CREATOR
= new Parcelable.Creator<Action>() {
public Action createFromParcel(Parcel in) {
return new Action(in);
}
public Action[] newArray(int size) {
return new Action[size];
}
};
}
private Action[] actions;
/**
* Constructs a Notification object with default values.
* You might want to consider using {@link Builder} instead.
@@ -506,12 +573,17 @@ public class Notification implements Parcelable
}
priority = parcel.readInt();
kind = parcel.createStringArray(); // may set kind to null
if (parcel.readInt() != 0) {
extras = parcel.readBundle();
}
actions = parcel.createTypedArray(Action.CREATOR);
if (parcel.readInt() != 0) {
intruderView = RemoteViews.CREATOR.createFromParcel(parcel);
}
}
@Override
@@ -571,6 +643,14 @@ public class Notification implements Parcelable
}
that.actions = new Action[this.actions.length];
for(int i=0; i<this.actions.length; i++) {
that.actions[i] = this.actions[i].clone();
}
if (this.intruderView != null) {
that.intruderView = this.intruderView.clone();
}
return that;
}
@@ -658,6 +738,15 @@ public class Notification implements Parcelable
} else {
parcel.writeInt(0);
}
parcel.writeTypedArray(actions, 0);
if (intruderView != null) {
parcel.writeInt(1);
intruderView.writeToParcel(parcel, 0);
} else {
parcel.writeInt(0);
}
}
/**
@@ -769,7 +858,14 @@ public class Notification implements Parcelable
sb.append(this.kind[i]);
}
}
sb.append("])");
sb.append("]");
if (actions != null) {
sb.append(" ");
sb.append(actions.length);
sb.append(" action");
if (actions.length > 1) sb.append("s");
}
sb.append(")");
return sb.toString();
}
@@ -821,6 +917,7 @@ public class Notification implements Parcelable
private ArrayList<String> mKindList = new ArrayList<String>(1);
private Bundle mExtras;
private int mPriority;
private ArrayList<Action> mActions = new ArrayList<Action>(3);
/**
* Constructs a new Builder with the defaults:
@@ -1203,6 +1300,19 @@ public class Notification implements Parcelable
return this;
}
/**
* Add an action to this notification. Actions are typically displayed by
* the system as a button adjacent to the notification content.
*
* @param icon Resource ID of a drawable that represents the action.
* @param title Text describing the action.
* @param intent PendingIntent to be fired when the action is invoked.
*/
public Builder addAction(int icon, CharSequence title, PendingIntent intent) {
mActions.add(new Action(icon, title, intent));
return this;
}
private void setFlag(int mask, boolean value) {
if (value) {
mFlags |= mask;
@@ -1284,6 +1394,44 @@ public class Notification implements Parcelable
}
}
private RemoteViews makeIntruderView() {
RemoteViews intruderView = new RemoteViews(mContext.getPackageName(),
R.layout.notification_intruder_content);
if (mLargeIcon != null) {
intruderView.setImageViewBitmap(R.id.icon, mLargeIcon);
intruderView.setViewVisibility(R.id.icon, View.VISIBLE);
} else if (mSmallIcon != 0) {
intruderView.setImageViewResource(R.id.icon, mSmallIcon);
intruderView.setViewVisibility(R.id.icon, View.VISIBLE);
} else {
intruderView.setViewVisibility(R.id.icon, View.GONE);
}
if (mContentTitle != null) {
intruderView.setTextViewText(R.id.title, mContentTitle);
}
if (mContentText != null) {
intruderView.setTextViewText(R.id.text, mContentText);
}
if (mActions.size() > 0) {
intruderView.setViewVisibility(R.id.actions, View.VISIBLE);
int N = mActions.size();
if (N>3) N=3;
final int[] BUTTONS = { R.id.action0, R.id.action1, R.id.action2 };
for (int i=0; i<N; i++) {
final Action action = mActions.get(i);
final int buttonId = BUTTONS[i];
intruderView.setViewVisibility(buttonId, View.VISIBLE);
intruderView.setImageViewResource(buttonId, action.icon);
intruderView.setContentDescription(buttonId, action.title);
intruderView.setOnClickPendingIntent(buttonId, action.actionIntent);
}
} else {
intruderView.setViewVisibility(R.id.actions, View.GONE);
}
return intruderView;
}
/**
* Combine all of the options that have been set and return a new {@link Notification}
* object.
@@ -1309,6 +1457,7 @@ public class Notification implements Parcelable
n.ledOffMS = mLedOffMs;
n.defaults = mDefaults;
n.flags = mFlags;
n.intruderView = makeIntruderView();
if (mLedOnMs != 0 && mLedOffMs != 0) {
n.flags |= FLAG_SHOW_LIGHTS;
}
@@ -1323,6 +1472,10 @@ public class Notification implements Parcelable
}
n.priority = mPriority;
n.extras = mExtras != null ? new Bundle(mExtras) : null;
if (mActions.size() > 0) {
n.actions = new Action[mActions.size()];
mActions.toArray(n.actions);
}
return n;
}
}

View File

@@ -0,0 +1,69 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="#FF333333"
android:padding="4dp"
>
<ImageView android:id="@+id/icon"
android:layout_width="32dp"
android:layout_height="32dp"
android:scaleType="center"
android:padding="4dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginLeft="40dp"
android:orientation="vertical"
>
<TextView android:id="@+id/title"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
/>
<TextView android:id="@+id/text"
android:textAppearance="@style/TextAppearance.StatusBar.EventContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="-4dp"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
/>
</LinearLayout>
<LinearLayout
android:id="@+id/actions"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="48dp"
android:orientation="horizontal"
android:visibility="gone"
>
<ImageView
android:id="@+id/action0"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:visibility="gone"
/>
<ImageView
android:id="@+id/action1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:visibility="gone"
/>
<ImageView
android:id="@+id/action2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:visibility="gone"
/>
</LinearLayout>
</FrameLayout>

View File

@@ -194,6 +194,10 @@
<java-symbol type="id" name="zoomIn" />
<java-symbol type="id" name="zoomMagnify" />
<java-symbol type="id" name="zoomOut" />
<java-symbol type="id" name="actions" />
<java-symbol type="id" name="action0" />
<java-symbol type="id" name="action1" />
<java-symbol type="id" name="action2" />
<java-symbol type="attr" name="actionModeShareDrawable" />
<java-symbol type="attr" name="alertDialogCenterButtons" />
@@ -1062,6 +1066,7 @@
<java-symbol type="layout" name="zoom_container" />
<java-symbol type="layout" name="zoom_controls" />
<java-symbol type="layout" name="zoom_magnify" />
<java-symbol type="layout" name="notification_intruder_content" />
<java-symbol type="anim" name="slide_in_child_bottom" />
<java-symbol type="anim" name="slide_in_right" />