The large icon for notifications.

Change-Id: I8537c602b5b5fca03be8980295bfa28330543669
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 7eab7c8..3af6917 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -34,6 +34,8 @@
 import android.view.View;
 import android.widget.RemoteViews;
 
+import com.android.internal.R;
+
 /**
  * A class that represents how a persistent notification is to be presented to
  * the user using the {@link android.app.NotificationManager}.
@@ -379,6 +381,9 @@
         if (parcel.readInt() != 0) {
             contentView = RemoteViews.CREATOR.createFromParcel(parcel);
         }
+        if (parcel.readInt() != 0) {
+            largeIcon = Bitmap.CREATOR.createFromParcel(parcel);
+        }
         defaults = parcel.readInt();
         flags = parcel.readInt();
         if (parcel.readInt() != 0) {
@@ -418,6 +423,9 @@
         if (this.contentView != null) {
             that.contentView = this.contentView.clone();
         }
+        if (this.largeIcon != null) {
+            that.largeIcon = Bitmap.createBitmap(this.largeIcon);
+        }
         that.iconLevel = that.iconLevel;
         that.sound = this.sound; // android.net.Uri is immutable
         that.audioStreamType = this.audioStreamType;
@@ -483,6 +491,12 @@
         } else {
             parcel.writeInt(0);
         }
+        if (largeIcon != null) {
+            parcel.writeInt(1);
+            largeIcon.writeToParcel(parcel, 0);
+        } else {
+            parcel.writeInt(0);
+        }
 
         parcel.writeInt(defaults);
         parcel.writeInt(this.flags);
@@ -546,18 +560,18 @@
     public void setLatestEventInfo(Context context,
             CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
         RemoteViews contentView = new RemoteViews(context.getPackageName(),
-                com.android.internal.R.layout.status_bar_latest_event_content);
+                R.layout.status_bar_latest_event_content);
         if (this.icon != 0) {
-            contentView.setImageViewResource(com.android.internal.R.id.icon, this.icon);
+            contentView.setImageViewResource(R.id.icon, this.icon);
         }
         if (contentTitle != null) {
-            contentView.setTextViewText(com.android.internal.R.id.title, contentTitle);
+            contentView.setTextViewText(R.id.title, contentTitle);
         }
         if (contentText != null) {
-            contentView.setTextViewText(com.android.internal.R.id.text, contentText);
+            contentView.setTextViewText(R.id.text, contentText);
         }
         if (this.when != 0) {
-            contentView.setLong(com.android.internal.R.id.time, "setTime", when);
+            contentView.setLong(R.id.time, "setTime", when);
         }
 
         this.contentView = contentView;
@@ -754,36 +768,41 @@
             }
         }
 
+        private RemoteViews makeRemoteViews(int resId) {
+            RemoteViews contentView = new RemoteViews(mContext.getPackageName(), resId);
+            if (mSmallIcon != 0) {
+                contentView.setImageViewResource(R.id.icon, mSmallIcon);
+            }
+            if (mContentTitle != null) {
+                contentView.setTextViewText(R.id.title, mContentTitle);
+            }
+            if (mContentText != null) {
+                contentView.setTextViewText(R.id.text, mContentText);
+            }
+            if (mContentInfo != null) {
+                contentView.setTextViewText(R.id.info, mContentInfo);
+            } else if (mNumber > 0) {
+                NumberFormat f = NumberFormat.getIntegerInstance();
+                contentView.setTextViewText(R.id.info, f.format(mNumber));
+                contentView.setFloat(R.id.info, "setTextSize",
+                        mContext.getResources().getDimensionPixelSize(
+                            R.dimen.status_bar_content_number_size));
+            } else {
+                contentView.setViewVisibility(R.id.info, View.GONE);
+            }
+            if (mWhen != 0) {
+                contentView.setLong(R.id.time, "setTime", mWhen);
+            }
+            return contentView;
+        }
+
         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);
-                }
-                if (mContentInfo != null) {
-                    contentView.setTextViewText(com.android.internal.R.id.info, mContentInfo);
-                } else if (mNumber > 0) {
-                    NumberFormat f = NumberFormat.getIntegerInstance();
-                    contentView.setTextViewText(com.android.internal.R.id.info, f.format(mNumber));
-                    contentView.setFloat(com.android.internal.R.id.info, "setTextSize",
-                            mContext.getResources().getDimensionPixelSize(
-                                com.android.internal.R.dimen.status_bar_content_number_size));
-                } else {
-                    contentView.setViewVisibility(com.android.internal.R.id.info, View.GONE);
-                }
-                if (mWhen != 0) {
-                    contentView.setLong(com.android.internal.R.id.time, "setTime", mWhen);
-                }
-                return contentView;
+                    return makeRemoteViews(mLargeIcon == null
+                            ? R.layout.status_bar_latest_event_content
+                        : R.layout.status_bar_latest_event_content_large_icon);
             }
         }
 
@@ -791,7 +810,13 @@
             if (mTickerView != null) {
                 return mTickerView;
             } else {
-                return makeContentView();
+                if (mContentView == null) {
+                    return makeRemoteViews(mLargeIcon == null
+                            ? R.layout.status_bar_latest_event_ticker
+                            : R.layout.status_bar_latest_event_ticker_large_icon);
+                } else {
+                    return null;
+                }
             }
         }
 
diff --git a/core/res/res/layout-xlarge/status_bar_latest_event_content.xml b/core/res/res/layout-xlarge/status_bar_latest_event_content.xml
index d71bcd8..3afd08a 100644
--- a/core/res/res/layout-xlarge/status_bar_latest_event_content.xml
+++ b/core/res/res/layout-xlarge/status_bar_latest_event_content.xml
@@ -2,20 +2,19 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     >
-
     <ImageView android:id="@+id/icon"
         android:layout_width="48dp"
         android:layout_height="64dp"
+        android:layout_marginLeft="4dp"
         android:scaleType="center"
         />
-
     <LinearLayout
         android:layout_width="0dp"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:layout_weight="1"
         android:orientation="vertical"
-        android:paddingLeft="16dp"
+        android:paddingLeft="8dp"
         >
         <TextView android:id="@+id/title"
             android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Title"
@@ -40,6 +39,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
+        android:paddingLeft="8dp"
         />
 </LinearLayout>
 
diff --git a/core/res/res/layout-xlarge/status_bar_latest_event_content_large_icon.xml b/core/res/res/layout-xlarge/status_bar_latest_event_content_large_icon.xml
new file mode 100644
index 0000000..9dcc7c7
--- /dev/null
+++ b/core/res/res/layout-xlarge/status_bar_latest_event_content_large_icon.xml
@@ -0,0 +1,43 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    >
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_weight="1"
+        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:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            />
+    </LinearLayout>
+    <TextView android:id="@+id/info"
+        android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:paddingLeft="8dp"
+        />
+    <ImageView android:id="@+id/icon"
+        android:layout_width="48dp"
+        android:layout_height="64dp"
+        android:scaleType="center"
+        />
+</LinearLayout>
+
diff --git a/core/res/res/layout-xlarge/status_bar_latest_event_ticker.xml b/core/res/res/layout-xlarge/status_bar_latest_event_ticker.xml
new file mode 100644
index 0000000..4861d84
--- /dev/null
+++ b/core/res/res/layout-xlarge/status_bar_latest_event_ticker.xml
@@ -0,0 +1,43 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/status_bar_height"
+    >
+    <ImageView android:id="@+id/icon"
+        android:layout_width="48dp"
+        android:layout_height="64dp"
+        android:scaleType="center"
+        />
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingLeft="16dp"
+        >
+        <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:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            />
+    </LinearLayout>
+    <TextView android:id="@+id/info"
+        android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        />
+</LinearLayout>
+
diff --git a/core/res/res/layout-xlarge/status_bar_latest_event_ticker_large_icon.xml b/core/res/res/layout-xlarge/status_bar_latest_event_ticker_large_icon.xml
new file mode 100644
index 0000000..4f4afd2
--- /dev/null
+++ b/core/res/res/layout-xlarge/status_bar_latest_event_ticker_large_icon.xml
@@ -0,0 +1,43 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    >
+    <LinearLayout
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingLeft="16dp"
+        >
+        <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:singleLine="true"
+            android:ellipsize="marquee"
+            android:fadingEdge="horizontal"
+            />
+    </LinearLayout>
+    <TextView android:id="@+id/info"
+        android:textAppearance="@style/TextAppearance.StatusBar.EventContent.Info"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        />
+    <ImageView android:id="@+id/icon"
+        android:layout_width="48dp"
+        android:layout_height="64dp"
+        android:scaleType="center"
+        />
+</LinearLayout>
+
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_latest_event.xml b/packages/SystemUI/res/layout-xlarge/status_bar_latest_event.xml
index b6679a5..3633227 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_latest_event.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_latest_event.xml
@@ -13,13 +13,24 @@
         android:src="@drawable/status_bar_veto"
         android:scaleType="center"
         android:background="#ff000000"
+        android:paddingRight="8dp"
         />
 
+    <ImageView
+        android:id="@+id/large_icon"
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:scaleType="center"
+        />
+        <!-- TODO: scaleType should be top-left but ImageView doesn't support that. -->
+
     <com.android.systemui.statusbar.LatestItemView android:id="@+id/content"
         android:layout_width="wrap_content"
         android:layout_height="64sp"
         android:layout_alignParentTop="true"
-        android:layout_alignParentLeft="true"
+        android:layout_toRightOf="@id/large_icon"
         android:layout_toLeftOf="@id/veto"
         android:layout_marginLeft="16dp"
         android:focusable="true"
diff --git a/packages/SystemUI/res/layout-xlarge/ticker.xml b/packages/SystemUI/res/layout-xlarge/ticker.xml
index d3a52c5..10acb13 100644
--- a/packages/SystemUI/res/layout-xlarge/ticker.xml
+++ b/packages/SystemUI/res/layout-xlarge/ticker.xml
@@ -27,5 +27,13 @@
     android:background="@drawable/ticker_background"
     -->
 
+    <ImageView
+        android:id="@+id/large_icon"
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:scaleType="center"
+        android:visibility="gone"
+        />
+        <!-- TODO: scaleType should be top-left but ImageView doesn't support that. -->
 
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout-xlarge/ticker_compat.xml b/packages/SystemUI/res/layout-xlarge/ticker_compat.xml
index 5703896..90d4133 100644
--- a/packages/SystemUI/res/layout-xlarge/ticker_compat.xml
+++ b/packages/SystemUI/res/layout-xlarge/ticker_compat.xml
@@ -23,10 +23,19 @@
     android:background="#ff1d1d1d"
     >
 
-    <ImageView android:id="@+id/icon"
+    <ImageView
+        android:id="@+id/large_icon"
+        android:layout_width="60dp"
+        android:layout_height="60dp"
+        android:scaleType="center"
+        android:visibility="gone"
+        />
+    
+    <ImageView android:id="@+id/left_icon"
         android:layout_width="64dp"
         android:layout_height="match_parent"
         android:scaleType="center"
+        android:visibility="gone"
         />
 
     <TextView android:id="@+id/text"
@@ -39,4 +48,11 @@
         android:maxLines="2"
         />
 
+    <ImageView android:id="@+id/right_icon"
+        android:layout_width="64dp"
+        android:layout_height="match_parent"
+        android:scaleType="center"
+        android:visibility="gone"
+        />
+
 </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 b917324..7cc546a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -1009,6 +1009,15 @@
             vetoButton.setVisibility(View.INVISIBLE);
         }
 
+        // the large icon
+        ImageView largeIcon = (ImageView)row.findViewById(R.id.large_icon);
+        if (sbn.notification.largeIcon != null) {
+            largeIcon.setImageBitmap(sbn.notification.largeIcon);
+        } else {
+            largeIcon.getLayoutParams().width = 0;
+            largeIcon.setVisibility(View.INVISIBLE);
+        }
+
         // bind the click event to the content area
         ViewGroup content = (ViewGroup)row.findViewById(R.id.content);
         // XXX: update to allow controls within notification views
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 73dbdc38..cf4db41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletTicker.java
@@ -148,6 +148,12 @@
 
         ViewGroup group;
         int layoutId;
+        int iconId;
+        if (n.largeIcon != null) {
+            iconId = R.id.right_icon;
+        } else {
+            iconId = R.id.left_icon;
+        }
         if (n.tickerView != null) {
             group = (ViewGroup)inflater.inflate(R.layout.ticker, null, false);
             View expanded = null;
@@ -172,14 +178,19 @@
             group = (ViewGroup)inflater.inflate(R.layout.ticker_compat, mParent, false);
             final Drawable icon = StatusBarIconView.getIcon(mContext,
                     new StatusBarIcon(notification.pkg, n.icon, n.iconLevel, 0));
-            ImageView iv = (ImageView)group.findViewById(R.id.icon);
+            ImageView iv = (ImageView)group.findViewById(iconId);
             iv.setImageDrawable(icon);
+            iv.setVisibility(View.VISIBLE);
             TextView tv = (TextView)group.findViewById(R.id.text);
             tv.setText(n.tickerText);
         } else {
             throw new RuntimeException("tickerView==null && tickerText==null");
         }
-        // TODO: Add Large icon
+        ImageView largeIcon = (ImageView)group.findViewById(R.id.large_icon);
+        if (n.largeIcon != null) {
+            largeIcon.setImageBitmap(n.largeIcon);
+            largeIcon.setVisibility(View.VISIBLE);
+        }
         return group;
     }
 }
diff --git a/tests/StatusBar/res/drawable-mdpi/pineapple.png b/tests/StatusBar/res/drawable-mdpi/pineapple.png
new file mode 100644
index 0000000..7377b96
--- /dev/null
+++ b/tests/StatusBar/res/drawable-mdpi/pineapple.png
Binary files differ
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
index fddb4d5..3c26212 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationBuilderTest.java
@@ -62,57 +62,63 @@
         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));
+                final Notification.Builder b = makeBasicBuilder(this, id);
 
                 mNM.notify(id, b.getNotification());
             }
         },
 
-        new Test("Basic Content w/ Info (1)") {
+        new Test("Content w/ Info (1)") {
             public void run() {
                 int id = 1;
+                final Notification.Builder b = makeBasicBuilder(this, id);
 
-                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));
                 b.setContentInfo("Snoozed");
 
                 mNM.notify(id, b.getNotification());
             }
         },
 
-        new Test("Basic Content w/ Number (1)") {
+        new Test("w/ Number (1)") {
             public void run() {
                 int id = 1;
+                final Notification.Builder b = makeBasicBuilder(this, id);
 
-                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));
                 b.setNumber(12345);
 
                 mNM.notify(id, b.getNotification());
             }
         },
+
+        new Test("w/ Number and Large Icon (1)") {
+            public void run() {
+                int id = 1;
+                final Notification.Builder b = makeBasicBuilder(this, id);
+
+                b.setNumber(42);
+
+                final BitmapDrawable bd = (BitmapDrawable)getResources().getDrawable(
+                        R.drawable.pineapple);
+                b.setLargeIcon(Bitmap.createBitmap(bd.getBitmap()));
+
+                mNM.notify(id, b.getNotification());
+            }
+        },
     };
 
+    private Notification.Builder makeBasicBuilder(Test t, int id) {
+        final Notification.Builder b = new Notification.Builder(this);
+
+        b.setWhen(System.currentTimeMillis());
+        b.setSmallIcon(R.drawable.ic_statusbar_chat);
+        b.setContentTitle("Notification builder Test");
+        b.setContentText(t.name + "\nhappy notifying");
+        b.setContentIntent(makeContentIntent(id));
+        b.setDeleteIntent(makeDeleteIntent(id));
+
+        return b;
+    }
+
     private PendingIntent makeContentIntent(int id) {
         Intent intent = new Intent(this, ConfirmationActivity.class);
         intent.setData(Uri.fromParts("content", "//status_bar_test/content/" + id, null));