Update the look of the notifications.  Includes adding a new Notification.Builder class.

Change-Id: I7c57b81c45defe77d6f3d22472e9cf8432bbed03
diff --git a/api/current.xml b/api/current.xml
index 3ccb4e9..495d11d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -32205,7 +32205,7 @@
  type="android.app.Notification"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="icon" type="int">
@@ -32254,7 +32254,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="context" type="android.content.Context">
@@ -32524,6 +32524,16 @@
  visibility="public"
 >
 </field>
+<field name="largeIcon"
+ type="android.graphics.Bitmap"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="ledARGB"
  type="int"
  transient="false"
@@ -32574,27 +32584,6 @@
  visibility="public"
 >
 </field>
-<field name="tickerIcons"
- type="android.graphics.Bitmap[]"
- transient="false"
- volatile="false"
- value="null"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
-<field name="tickerSubtitle"
- type="java.lang.CharSequence"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="tickerText"
  type="java.lang.CharSequence"
  transient="false"
@@ -32605,8 +32594,8 @@
  visibility="public"
 >
 </field>
-<field name="tickerTitle"
- type="java.lang.CharSequence"
+<field name="tickerView"
+ type="android.widget.RemoteViews"
  transient="false"
  volatile="false"
  static="false"
@@ -32637,6 +32626,321 @@
 >
 </field>
 </class>
+<class name="Notification.Builder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Notification.Builder"
+ type="android.app.Notification.Builder"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+</constructor>
+<method name="getNotification"
+ return="android.app.Notification"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setAutoCancel"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="autoCancel" type="boolean">
+</parameter>
+</method>
+<method name="setContent"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
+<method name="setContentInfo"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="info" type="java.lang.CharSequence">
+</parameter>
+</method>
+<method name="setContentIntent"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+</method>
+<method name="setContentText"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="text" type="java.lang.CharSequence">
+</parameter>
+</method>
+<method name="setContentTitle"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="title" type="java.lang.CharSequence">
+</parameter>
+</method>
+<method name="setDefaults"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="defaults" type="int">
+</parameter>
+</method>
+<method name="setDeleteIntent"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+</method>
+<method name="setFullScreenIntent"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+<parameter name="highPriority" type="boolean">
+</parameter>
+</method>
+<method name="setLargeIcon"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="icon" type="android.graphics.Bitmap">
+</parameter>
+</method>
+<method name="setLights"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="argb" type="int">
+</parameter>
+<parameter name="onMs" type="int">
+</parameter>
+<parameter name="offMs" type="int">
+</parameter>
+</method>
+<method name="setOngoing"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="ongoing" type="boolean">
+</parameter>
+</method>
+<method name="setOnlyAlertOnce"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="onlyAlertOnce" type="boolean">
+</parameter>
+</method>
+<method name="setSmallIcon"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="icon" type="int">
+</parameter>
+</method>
+<method name="setSmallIcon"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="icon" type="int">
+</parameter>
+<parameter name="level" type="int">
+</parameter>
+</method>
+<method name="setSmallIconNumber"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="number" type="int">
+</parameter>
+</method>
+<method name="setSound"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="sound" type="android.net.Uri">
+</parameter>
+<parameter name="streamType" type="int">
+</parameter>
+</method>
+<method name="setTicker"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tickerText" type="java.lang.CharSequence">
+</parameter>
+</method>
+<method name="setTicker"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="tickerText" type="java.lang.CharSequence">
+</parameter>
+<parameter name="views" type="android.widget.RemoteViews">
+</parameter>
+</method>
+<method name="setVibrate"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pattern" type="long[]">
+</parameter>
+</method>
+<method name="setWhen"
+ return="android.app.Notification.Builder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="when" type="long">
+</parameter>
+</method>
+</class>
 <class name="NotificationManager"
  extends="java.lang.Object"
  abstract="false"
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index e602518..09319b9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -29,6 +29,7 @@
 import android.text.TextUtils;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
+import android.util.Slog;
 import android.widget.RemoteViews;
 
 /**
@@ -41,6 +42,8 @@
  */
 public class Notification implements Parcelable
 {
+    private static final String TAG = "Notification";
+
     /**
      * Use all default values (where applicable).
      */
@@ -84,6 +87,15 @@
     public int icon;
 
     /**
+     * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
+     * leave it at its default value of 0.
+     *
+     * @see android.widget.ImageView#setImageLevel
+     * @see android.graphics.drawable#setLevel
+     */
+    public int iconLevel;
+
+    /**
      * The number of events that this notification represents.  For example, in a new mail
      * notification, this could be the number of unread messages.  This number is superimposed over
      * the icon in the status bar.  If the number is 0 or negative, it is not shown in the status
@@ -132,38 +144,15 @@
      * text for when the text scrolls in and when it is displayed all at once
      * in conjunction with one or more icons.
      *
-     * @see #tickerTitle
-     * @see #tickerSubtitle
-     * @see #tickerIcons
+     * @see #tickerView
      */
     public CharSequence tickerText;
 
     /**
-     * The title line for the ticker over a the fat status bar on xlarge devices.
-     *
-     * @see #tickerText
-     * @see #tickerSubtitle
-     * @see #tickerIcons
+     * The view to show as the ticker in the status bar when the notification
+     * is posted.
      */
-    public CharSequence tickerTitle;
-
-    /**
-     * The subtitle line for the ticker over a the fat status bar on xlarge devices.
-     *
-     * @see #tickerText
-     * @see #tickerTitle
-     * @see #tickerIcons
-     */
-    public CharSequence tickerSubtitle;
-
-    /**
-     * The icons to show to the left of the other ticker fields.
-     *
-     * @see #tickerText
-     * @see #tickerTitle
-     * @see #tickerSubtitle
-     */
-    public Bitmap[] tickerIcons;
+    public RemoteViews tickerView;
 
     /**
      * The view that will represent this notification in the expanded status bar.
@@ -171,13 +160,9 @@
     public RemoteViews contentView;
 
     /**
-     * If the icon in the status bar is to have more than one level, you can set this.  Otherwise,
-     * leave it at its default value of 0.
-     *
-     * @see android.widget.ImageView#setImageLevel
-     * @see android.graphics.drawable#setLevel
+     * The bitmap that may escape the bounds of the panel and bar.
      */
-    public int iconLevel;
+    public Bitmap largeIcon;
 
     /**
      * The sound to play.
@@ -327,6 +312,7 @@
 
     /**
      * Constructs a Notification object with everything set to 0.
+     * You might want to consider using {@link Builder} instead.
      */
     public Notification()
     {
@@ -334,7 +320,6 @@
     }
 
     /**
-     * @deprecated use {@link #Notification(int,CharSequence,long)} and {@link #setLatestEventInfo}.
      * @hide
      */
     public Notification(Context context, int icon, CharSequence tickerText, long when,
@@ -356,7 +341,10 @@
      *                      activates.
      * @param when          The time to show in the time field.  In the System.currentTimeMillis
      *                      timebase.
+     *
+     * @deprecated Use {@link Builder} instead.
      */
+    @Deprecated
     public Notification(int icon, CharSequence tickerText, long when)
     {
         this.icon = icon;
@@ -384,19 +372,7 @@
             tickerText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
         }
         if (parcel.readInt() != 0) {
-            tickerTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
-        }
-        if (parcel.readInt() != 0) {
-            tickerSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
-        }
-        final int tickerIconCount = parcel.readInt();
-        if (tickerIconCount >= 0) {
-            tickerIcons = new Bitmap[tickerIconCount];
-            for (int i=0; i<tickerIconCount; i++) {
-                if (parcel.readInt() != 0) {
-                    tickerIcons[i] = Bitmap.CREATOR.createFromParcel(parcel);
-                }
-            }
+            tickerView = RemoteViews.CREATOR.createFromParcel(parcel);
         }
         if (parcel.readInt() != 0) {
             contentView = RemoteViews.CREATOR.createFromParcel(parcel);
@@ -434,18 +410,8 @@
         if (this.tickerText != null) {
             that.tickerText = this.tickerText.toString();
         }
-        if (this.tickerTitle != null) {
-            that.tickerTitle = this.tickerTitle.toString();
-        }
-        if (this.tickerSubtitle != null) {
-            that.tickerSubtitle = this.tickerSubtitle.toString();
-        }
-        if (this.tickerIcons != null) {
-            final int N = this.tickerIcons.length;
-            that.tickerIcons = new Bitmap[N];
-            for (int i=0; i<N; i++) {
-                that.tickerIcons[i] = Bitmap.createBitmap(this.tickerIcons[i]);
-            }
+        if (this.tickerView != null) {
+            that.tickerView = this.tickerView.clone();
         }
         if (this.contentView != null) {
             that.contentView = this.contentView.clone();
@@ -503,32 +469,12 @@
         } else {
             parcel.writeInt(0);
         }
-        if (tickerTitle != null) {
+        if (tickerView != null) {
             parcel.writeInt(1);
-            TextUtils.writeToParcel(tickerTitle, parcel, flags);
+            tickerView.writeToParcel(parcel, 0);
         } else {
             parcel.writeInt(0);
         }
-        if (tickerSubtitle != null) {
-            parcel.writeInt(1);
-            TextUtils.writeToParcel(tickerSubtitle, parcel, flags);
-        } else {
-            parcel.writeInt(0);
-        }
-        if (tickerIcons != null) {
-            final int N = tickerIcons.length;
-            parcel.writeInt(N);
-            for (int i=0; i<N; i++) {
-                if (tickerIcons[i] != null) {
-                    parcel.writeInt(1);
-                    tickerIcons[i].writeToParcel(parcel, flags);
-                } else {
-                    parcel.writeInt(0);
-                }
-            }
-        } else {
-            parcel.writeInt(-1);
-        }
         if (contentView != null) {
             parcel.writeInt(1);
             contentView.writeToParcel(parcel, 0);
@@ -591,7 +537,10 @@
      * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} flag, which requires
      * that you take care of task management as described in 
      * <a href="{@docRoot}guide/topics/fundamentals.html#lcycles">Application Fundamentals: Activities and Tasks</a>.
+     * 
+     * @deprecated Use {@link Builder} instead.
      */
+    @Deprecated
     public void setLatestEventInfo(Context context,
             CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
         RemoteViews contentView = new RemoteViews(context.getPackageName(),
@@ -651,4 +600,214 @@
         sb.append(")");
         return sb.toString();
     }
+
+    public static class Builder {
+        private Context mContext;
+
+        private long mWhen;
+        private int mSmallIcon;
+        private int mSmallIconLevel;
+        private int mSmallIconNumber;
+        private CharSequence mContentTitle;
+        private CharSequence mContentText;
+        private CharSequence mContentInfo;
+        private PendingIntent mContentIntent;
+        private RemoteViews mContentView;
+        private PendingIntent mDeleteIntent;
+        private PendingIntent mFullScreenIntent;
+        private CharSequence mTickerText;
+        private RemoteViews mTickerView;
+        private Bitmap mLargeIcon;
+        private Uri mSound;
+        private int mAudioStreamType;
+        private long[] mVibrate;
+        private int mLedArgb;
+        private int mLedOnMs;
+        private int mLedOffMs;
+        private int mDefaults;
+        private int mFlags;
+
+        public Builder(Context context) {
+            mContext = context;
+            mWhen = System.currentTimeMillis();
+        }
+
+        public Builder setWhen(long when) {
+            mWhen = when;
+            return this;
+        }
+
+        public Builder setSmallIcon(int icon) {
+            mSmallIcon = icon;
+            return this;
+        }
+
+        public Builder setSmallIcon(int icon, int level) {
+            mSmallIcon = icon;
+            mSmallIconLevel = level;
+            return this;
+        }
+
+        public Builder setSmallIconNumber(int number) {
+            mSmallIconNumber = number;
+            return this;
+        }
+
+        public Builder setContentTitle(CharSequence title) {
+            mContentTitle = title;
+            return this;
+        }
+
+        public Builder setContentText(CharSequence text) {
+            mContentText = text;
+            return this;
+        }
+
+        public Builder setContentInfo(CharSequence info) {
+            mContentInfo = info;
+            return this;
+        }
+
+        public Builder setContent(RemoteViews views) {
+            mContentView = views;
+            return this;
+        }
+
+        public Builder setContentIntent(PendingIntent intent) {
+            mContentIntent = intent;
+            return this;
+        }
+
+        public Builder setDeleteIntent(PendingIntent intent) {
+            mDeleteIntent = intent;
+            return this;
+        }
+
+        public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
+            mFullScreenIntent = intent;
+            setFlag(FLAG_HIGH_PRIORITY, highPriority);
+            return this;
+        }
+
+        public Builder setTicker(CharSequence tickerText) {
+            mTickerText = tickerText;
+            return this;
+        }
+
+        public Builder setTicker(CharSequence tickerText, RemoteViews views) {
+            mTickerText = tickerText;
+            mTickerView = views;
+            return this;
+        }
+
+        public Builder setLargeIcon(Bitmap icon) {
+            mLargeIcon = icon;
+            return this;
+        }
+
+        public Builder setSound(Uri sound, int streamType) {
+            mSound = sound;
+            mAudioStreamType = streamType;
+            return this;
+        }
+
+        public Builder setVibrate(long[] pattern) {
+            mVibrate = pattern;
+            return this;
+        }
+
+        public Builder setLights(int argb, int onMs, int offMs) {
+            mLedArgb = argb;
+            mLedOnMs = onMs;
+            mLedOffMs = offMs;
+            mFlags |= FLAG_SHOW_LIGHTS;
+            return this;
+        }
+
+        public Builder setOngoing(boolean ongoing) {
+            setFlag(FLAG_ONGOING_EVENT, ongoing);
+            return this;
+        }
+
+        public Builder setOnlyAlertOnce(boolean onlyAlertOnce) {
+            setFlag(FLAG_ONLY_ALERT_ONCE, onlyAlertOnce);
+            return this;
+        }
+
+        public Builder setAutoCancel(boolean autoCancel) {
+            setFlag(FLAG_ONLY_ALERT_ONCE, autoCancel);
+            return this;
+        }
+
+        public Builder setDefaults(int defaults) {
+            mDefaults = defaults;
+            return this;
+        }
+
+        private void setFlag(int mask, boolean value) {
+            if (value) {
+                mFlags |= mask;
+            } else {
+                mFlags &= ~mask;
+            }
+        }
+
+        private RemoteViews makeContentView() {
+            if (mContentView != null) {
+                return mContentView;
+            } else {
+                RemoteViews contentView = new RemoteViews(mContext.getPackageName(),
+                        com.android.internal.R.layout.status_bar_latest_event_content);
+                if (mSmallIcon != 0) {
+                    contentView.setImageViewResource(com.android.internal.R.id.icon, mSmallIcon);
+                }
+                if (mContentTitle != null) {
+                    contentView.setTextViewText(com.android.internal.R.id.title, mContentTitle);
+                }
+                if (mContentText != null) {
+                    contentView.setTextViewText(com.android.internal.R.id.text, mContentText);
+                }
+                //TODO
+                //if (mContentInfo) {
+                //    contentVeiw.setTextViewText(com.android.internal.R.id.info, mContentInfo);
+                //}
+                if (mWhen != 0) {
+                    contentView.setLong(com.android.internal.R.id.time, "setTime", mWhen);
+                }
+                return contentView;
+            }
+        }
+
+        private RemoteViews makeTickerView() {
+            if (mTickerView != null) {
+                return mTickerView;
+            } else {
+                return makeContentView();
+            }
+        }
+
+        public Notification getNotification() {
+            Notification n = new Notification();
+            n.when = mWhen;
+            n.icon = mSmallIcon;
+            n.iconLevel = mSmallIconLevel;
+            n.number = mSmallIconNumber;
+            n.contentView = makeContentView();
+            n.contentIntent = mContentIntent;
+            n.deleteIntent = mDeleteIntent;
+            n.fullScreenIntent = mFullScreenIntent;
+            n.tickerText = mTickerText;
+            n.tickerView = makeTickerView();
+            n.largeIcon = mLargeIcon;
+            n.sound = mSound;
+            n.audioStreamType = mAudioStreamType;
+            n.vibrate = mVibrate;
+            n.ledARGB = mLedArgb;
+            n.ledOnMS = mLedOnMs;
+            n.ledOffMS = mLedOffMs;
+            n.defaults = mDefaults;
+            n.flags = mFlags;
+            return n;
+        }
+    }
 }
diff --git a/packages/SystemUI/res/drawable/ticker_background.xml b/packages/SystemUI/res/drawable/ticker_background.xml
new file mode 100644
index 0000000..7320fa0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ticker_background.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+  
+          http://www.apache.org/licenses/LICENSE-2.0
+  
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<layer-list
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:opacity="translucent"
+    >
+    <!-- the large icon extends 12dp beyond the edge of the status bar -->
+    <item
+        android:drawable="@drawable/notification_item_background_color"
+        android:top="12dp"
+        />
+</layer-list>
+
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index d11e6da..e9661a6 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -242,7 +242,7 @@
         <!-- ticker: transient incoming notification information -->
         <FrameLayout
             android:id="@+id/ticker"
-            android:layout_width="wrap_content"
+            android:layout_width="392dp"
             android:layout_height="match_parent"
             android:layout_alignParentRight="true"
             android:layout_toRightOf="@+id/systemInfo"
diff --git a/packages/SystemUI/res/layout-xlarge/ticker.xml b/packages/SystemUI/res/layout-xlarge/ticker.xml
index c8d855f..1506848 100644
--- a/packages/SystemUI/res/layout-xlarge/ticker.xml
+++ b/packages/SystemUI/res/layout-xlarge/ticker.xml
@@ -18,36 +18,13 @@
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
+    android:layout_height="wrap_content"
     android:orientation="horizontal"
     android:background="#ff000000"
     >
+    <!--
+    android:background="@drawable/ticker_background"
+    -->
 
-    <LinearLayout
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:layout_gravity="center_vertical"
-        android:orientation="vertical"
-        android:paddingLeft="12dp"
-        >
-
-        <TextView android:id="@+id/title"
-            xmlns:android="http://schemas.android.com/apk/res/android"
-            android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:textStyle="bold"
-            android:maxLines="1"
-            />
-        <TextView android:id="@+id/subtitle"
-            xmlns:android="http://schemas.android.com/apk/res/android"
-            android:textAppearance="@*android:style/TextAppearance.StatusBar.Ticker"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:maxLines="1"
-            />
-    </LinearLayout>
 
 </LinearLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 233ac45..b917324 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -464,7 +464,7 @@
         boolean immersive = false;
         try {
             immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
-            Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
+            //Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
         } catch (RemoteException ex) {
         }
         if (false && immersive) {
@@ -603,9 +603,7 @@
     }
 
     private boolean hasTicker(Notification n) {
-        return !TextUtils.isEmpty(n.tickerText)
-                || !TextUtils.isEmpty(n.tickerTitle)
-                || !TextUtils.isEmpty(n.tickerSubtitle);
+        return n.tickerView != null || !TextUtils.isEmpty(n.tickerText);
     }
 
     private void tick(StatusBarNotification n) {
@@ -1005,7 +1003,6 @@
                         } catch (RemoteException ex) {
                             // system process is dead if we're here.
                         }
-    //                    animateCollapse();
                     }
                 });
         } else {
@@ -1034,7 +1031,7 @@
             exception = e;
         }
         if (expanded == null) {
-            String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
+            final String ident = sbn.pkg + "/0x" + Integer.toHexString(sbn.id);
             Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
             return false;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
index 3c3139f..051c208 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -108,12 +108,16 @@
         }
 
         // In with the new...
-        final StatusBarNotification next = dequeue();
-        if (next != null) {
+        StatusBarNotification next = dequeue();
+        while (next != null) {
             mCurrentNotification = next;
             mCurrentView = makeTickerView(next);
-            mParent.addView(mCurrentView);
-            sendEmptyMessageDelayed(MSG_ADVANCE, ADVANCE_DELAY);
+            if (mCurrentView != null) {
+                mParent.addView(mCurrentView);
+                sendEmptyMessageDelayed(MSG_ADVANCE, ADVANCE_DELAY);
+                break;
+            }
+            next = dequeue();
         }
     }
 
@@ -139,40 +143,36 @@
         LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
 
-        int layoutId;
         ViewGroup group;
-        if (n.tickerTitle != null || n.tickerSubtitle != null) {
-            group = (ViewGroup)inflater.inflate(R.layout.ticker, mParent, false);
-            if (n.tickerTitle != null) {
-                final TextView title = (TextView)group.findViewById(R.id.title);
-                title.setText(n.tickerTitle);
+        int layoutId;
+        if (n.tickerView != null) {
+            group = (ViewGroup)inflater.inflate(R.layout.ticker, null, false);
+            View expanded = null;
+            Exception exception = null;
+            try {
+                expanded = n.tickerView.apply(mContext, group);
             }
-            if (n.tickerSubtitle != null) {
-                final TextView subtitle = (TextView)group.findViewById(R.id.subtitle);
-                subtitle.setText(n.tickerSubtitle);
+            catch (RuntimeException e) {
+                exception = e;
             }
-        } else {
+            if (expanded == null) {
+                final String ident = notification.pkg
+                        + "/0x" + Integer.toHexString(notification.id);
+                Slog.e(TAG, "couldn't inflate view for notification " + ident, exception);
+                return null;
+            }
+            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+                    ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f);
+            lp.gravity = Gravity.BOTTOM;
+            group.addView(expanded, lp);
+        } else if (n.tickerText != null) {
             group = (ViewGroup)inflater.inflate(R.layout.ticker_compat, mParent, false);
             TextView tv = (TextView)group.findViewById(R.id.text);
             tv.setText(n.tickerText);
+        } else {
+            throw new RuntimeException("tickerView==null && tickerText==null");
         }
-
-        // No more than 2 icons.
-        if (n.tickerIcons != null) {
-            int N = n.tickerIcons.length;
-            if (N > 2) {
-                N = 2;
-            }
-            for (int i=N-1; i>= 0; i--) {
-                Bitmap b = n.tickerIcons[i];
-                if (b != null) {
-                    ImageView iv = (ImageView)inflater.inflate(R.layout.ticker_icon, group, false);
-                    iv.setImageBitmap(b);
-                    group.addView(iv, 0);
-                }
-            }
-        }
-
+        // TODO: Add Large icon
         return group;
     }
 }
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 1081a20..6de7e6a 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -272,11 +272,13 @@
 
         public void onNotificationClick(String pkg, String tag, int id) {
             cancelNotification(pkg, tag, id, Notification.FLAG_AUTO_CANCEL,
-                    Notification.FLAG_FOREGROUND_SERVICE);
+                    Notification.FLAG_FOREGROUND_SERVICE, true);
         }
 
         public void onNotificationClear(String pkg, String tag, int id) {
-            cancelNotification(pkg, tag, id, 0, 0); // maybe add some flags?
+            cancelNotification(pkg, tag, id, 0,
+                Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE,
+                true);
         }
 
         public void onPanelRevealed() {
@@ -312,7 +314,7 @@
                 int uid, int initialPid, String message) {
             Slog.d(TAG, "onNotification error pkg=" + pkg + " tag=" + tag + " id=" + id
                     + "; will crashApplication(uid=" + uid + ", pid=" + initialPid + ")");
-            cancelNotification(pkg, tag, id, 0, 0);
+            cancelNotification(pkg, tag, id, 0, 0, false);
             long ident = Binder.clearCallingIdentity();
             try {
                 ActivityManagerNative.getDefault().crashApplication(uid, initialPid, pkg,
@@ -855,7 +857,20 @@
         manager.sendAccessibilityEvent(event);
     }
 
-    private void cancelNotificationLocked(NotificationRecord r) {
+    private void cancelNotificationLocked(NotificationRecord r, boolean sendDelete) {
+        // tell the app
+        if (sendDelete) {
+            if (r.notification.deleteIntent != null) {
+                try {
+                    r.notification.deleteIntent.send();
+                } catch (PendingIntent.CanceledException ex) {
+                    // do nothing - there's no relevant way to recover, and
+                    //     no reason to let this propagate
+                    Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
+                }
+            }
+        }
+
         // status bar
         if (r.notification.icon != 0) {
             long identity = Binder.clearCallingIdentity();
@@ -904,7 +919,7 @@
      * and none of the {@code mustNotHaveFlags}.
      */
     private void cancelNotification(String pkg, String tag, int id, int mustHaveFlags,
-            int mustNotHaveFlags) {
+            int mustNotHaveFlags, boolean sendDelete) {
         EventLog.writeEvent(EventLogTags.NOTIFICATION_CANCEL, pkg, id, mustHaveFlags);
 
         synchronized (mNotificationList) {
@@ -921,7 +936,7 @@
 
                 mNotificationList.remove(index);
 
-                cancelNotificationLocked(r);
+                cancelNotificationLocked(r, sendDelete);
                 updateLightsLocked();
             }
         }
@@ -954,7 +969,7 @@
                     return true;
                 }
                 mNotificationList.remove(i);
-                cancelNotificationLocked(r);
+                cancelNotificationLocked(r, false);
             }
             if (canceledSomething) {
                 updateLightsLocked();
@@ -973,7 +988,7 @@
         // Don't allow client applications to cancel foreground service notis.
         cancelNotification(pkg, tag, id, 0,
                 Binder.getCallingUid() == Process.SYSTEM_UID
-                ? 0 : Notification.FLAG_FOREGROUND_SERVICE);
+                ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false);
     }
 
     public void cancelAllNotifications(String pkg) {
@@ -1009,17 +1024,8 @@
 
                 if ((r.notification.flags & (Notification.FLAG_ONGOING_EVENT
                                 | Notification.FLAG_NO_CLEAR)) == 0) {
-                    if (r.notification.deleteIntent != null) {
-                        try {
-                            r.notification.deleteIntent.send();
-                        } catch (PendingIntent.CanceledException ex) {
-                            // do nothing - there's no relevant way to recover, and
-                            //     no reason to let this propagate
-                            Slog.w(TAG, "canceled PendingIntent for " + r.pkg, ex);
-                        }
-                    }
                     mNotificationList.remove(i);
-                    cancelNotificationLocked(r);
+                    cancelNotificationLocked(r, true);
                 }
             }
 
diff --git a/tests/StatusBar/AndroidManifest.xml b/tests/StatusBar/AndroidManifest.xml
index c1ca618..b1734bb 100644
--- a/tests/StatusBar/AndroidManifest.xml
+++ b/tests/StatusBar/AndroidManifest.xml
@@ -21,6 +21,13 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <activity android:name="NotificationBuilderTest" android:label="_Notify Builder">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
         <activity android:name="ToastTest" android:label="_Toasts">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -35,6 +42,8 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+        <activity android:name="ConfirmationActivity" android:theme="@android:style/Theme.Dialog">
+        </activity>
         <activity android:name="TestAlertActivity" android:theme="@android:style/Theme.Dialog">
         </activity>
     </application>
diff --git a/tests/StatusBar/res/layout/confirmation_activity.xml b/tests/StatusBar/res/layout/confirmation_activity.xml
new file mode 100644
index 0000000..50d1a49
--- /dev/null
+++ b/tests/StatusBar/res/layout/confirmation_activity.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    android:layout_gravity="center"
+    android:gravity="center_horizontal"
+    android:orientation="vertical"
+    >
+
+    <TextView android:id="@+id/text"
+        style="?android:attr/textAppearanceLarge"
+        android:padding="5dip"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:gravity="center"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content" />
+
+    <Button
+        android:id="@+id/ok"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="3"
+        android:onClick="dismiss"
+        android:text="Ok" />
+
+</LinearLayout>
diff --git a/tests/StatusBar/src/com/android/statusbartest/ConfirmationActivity.java b/tests/StatusBar/src/com/android/statusbartest/ConfirmationActivity.java
new file mode 100644
index 0000000..5ce8f3f
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/ConfirmationActivity.java
@@ -0,0 +1,32 @@
+package com.android.statusbartest;
+
+import android.app.Activity;
+import android.view.View;
+import android.widget.TextView;
+
+public class ConfirmationActivity extends Activity {
+    public static final String EXTRA_TITLE = "title";
+    public static final String EXTRA_TEXT = "text";
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        setContentView(R.layout.confirmation_activity);
+        setTitle(getTextExtra(EXTRA_TITLE, "Title"));
+        ((TextView)findViewById(R.id.text)).setText(getTextExtra(EXTRA_TEXT, "text"));
+        findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) {
+                    finish();
+                }
+            });
+    }
+
+    private String getTextExtra(String extra, String def) {
+        final String text = getIntent().getStringExtra(extra);
+        if (text == null) {
+            return def;
+        } else {
+            return text;
+        }
+    }
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
new file mode 100644
index 0000000..b871197
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statusbartest;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.Vibrator;
+import android.os.Handler;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.widget.RemoteViews;
+import android.os.PowerManager;
+
+public class NotificationBuilderTest extends TestActivity
+{
+    private final static String TAG = "NotificationTestList";
+
+    NotificationManager mNM;
+
+    @Override
+    protected String tag() {
+        return TAG;
+    }
+
+    @Override
+    protected Test[] tests() {
+        mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
+        
+        return mTests;
+    }
+
+    private Test[] mTests = new Test[] {
+        new Test("Cancel (1)") {
+            public void run() {
+                mNM.cancel(1);
+            }
+        },
+
+        new Test("Basic Content (1)") {
+            public void run() {
+                int id = 1;
+
+                Notification.Builder b = new Notification.Builder(NotificationBuilderTest.this);
+
+                b.setWhen(System.currentTimeMillis());
+                b.setSmallIcon(R.drawable.ic_statusbar_chat);
+                b.setContentTitle("Title");
+                b.setContentText("text\nline2");
+                b.setContentIntent(makeContentIntent(id));
+                b.setDeleteIntent(makeDeleteIntent(id));
+
+                mNM.notify(id, b.getNotification());
+            }
+        },
+    };
+
+    private PendingIntent makeContentIntent(int id) {
+        Intent intent = new Intent(this, ConfirmationActivity.class);
+        intent.setData(Uri.fromParts("content", "//status_bar_test/content/" + id, null));
+        intent.putExtra(ConfirmationActivity.EXTRA_TITLE, "Content intent");
+        intent.putExtra(ConfirmationActivity.EXTRA_TEXT, "id: " + id);
+        return PendingIntent.getActivity(this, 0, intent, 0);
+    }
+
+    private PendingIntent makeDeleteIntent(int id) {
+        Intent intent = new Intent(this, ConfirmationActivity.class);
+        intent.setData(Uri.fromParts("content", "//status_bar_test/delete/" + id, null));
+        intent.putExtra(ConfirmationActivity.EXTRA_TITLE, "Delete intent");
+        intent.putExtra(ConfirmationActivity.EXTRA_TEXT, "id: " + id);
+        return PendingIntent.getActivity(this, 0, intent, 0);
+    }
+}
+
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 2df97dc..0f0637f 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -135,95 +135,6 @@
             }
         },
 
-        new Test("Ticker 1 line & icon") {
-            public void run() {
-                Notification n = new Notification(R.drawable.icon1, "tick tick tick",
-                        mActivityCreateTime);
-                n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
-                            "This is a notification!!!", makeIntent());
-                n.tickerIcons = new Bitmap[1];
-                n.tickerIcons[0] = loadBitmap(R.drawable.icon3);
-                mNM.notify(1, n);
-            }
-        },
-
-        new Test("Ticker 2 lines") {
-            public void run() {
-                Notification n = new Notification(R.drawable.icon1, "tick tick tick\ntock tock",
-                        mActivityCreateTime);
-                n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
-                            "This is a notification!!!", makeIntent());
-                mNM.notify(1, n);
-            }
-        },
-
-        new Test("Ticker title") {
-            public void run() {
-                Notification n = new Notification(R.drawable.icon1, null,
-                        mActivityCreateTime);
-                n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
-                            "This is a notification!!!", makeIntent());
-                n.tickerTitle = "This is a title";
-                mNM.notify(1, n);
-            }
-        },
-
-        new Test("Ticker subtitle") {
-            public void run() {
-                Notification n = new Notification(R.drawable.icon1, null,
-                        mActivityCreateTime);
-                n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
-                            "This is a notification!!!", makeIntent());
-                n.tickerSubtitle = "and a subtitle";
-                mNM.notify(1, n);
-            }
-        },
-
-        new Test("Ticker title & subtitle") {
-            public void run() {
-                Notification n = new Notification(R.drawable.icon1, null,
-                        mActivityCreateTime);
-                n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
-                            "This is a notification!!!", makeIntent());
-                n.tickerTitle = "This is a title it is really really longggggg long long long long";
-                n.tickerSubtitle = "and a subtitle it is really really longggggg long long long long long long long long long long long long long long long long";
-                mNM.notify(1, n);
-            }
-        },
-
-        new Test("Ticker text, title & subtitle") {
-            public void run() {
-                Notification n = new Notification(R.drawable.icon1, "not visible",
-                        mActivityCreateTime);
-                n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
-                            "This is a notification!!!", makeIntent());
-                n.tickerTitle = "This is a title";
-                n.tickerSubtitle = "and a subtitle";
-                mNM.notify(1, n);
-            }
-        },
-
-        new Test("Ticker title, subtitle & 2 icons") {
-            public void run() {
-                Notification n = new Notification(R.drawable.icon1, null,
-                        mActivityCreateTime);
-                n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
-                            "This is a notification!!!", makeIntent());
-                n.tickerTitle = "This is a title";
-                n.tickerSubtitle = "and a subtitle";
-
-                n.tickerIcons = new Bitmap[2];
-                n.tickerIcons[0] = loadBitmap(R.drawable.icon3);
-                n.tickerIcons[1] = loadBitmap(R.drawable.app_gmail);
-
-                mNM.notify(1, n);
-                /*
-                n.tickerIcons[0].recycle();
-                n.tickerIcons[1].recycle();
-                */
-            }
-        },
-
         new Test("No view") {
             public void run() {
                 Notification n = new Notification(R.drawable.icon1, "No view",