Merge "Notification actions API."
diff --git a/api/current.txt b/api/current.txt
index 1393eb0..20b0be6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3694,6 +3694,7 @@
 
   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);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5325af0..04ab407 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -23,9 +23,11 @@
 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 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.
      */
@@ -418,6 +427,64 @@
     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 @@
         }
 
         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 @@
 
         }
 
+        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 @@
         } 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 @@
                 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 @@
         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 @@
             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 @@
             }
         }
 
+        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 @@
             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 @@
             }
             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;
         }
     }
diff --git a/core/res/res/layout/notification_intruder_content.xml b/core/res/res/layout/notification_intruder_content.xml
new file mode 100644
index 0000000..61be5f5
--- /dev/null
+++ b/core/res/res/layout/notification_intruder_content.xml
@@ -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>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index ea1a70a..047e6ed 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -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" />