Fix 1667521 - system process crash after bad notification

The steps to reproduce this were kind of interesting.  You needed to have
a notification with a bogus RemoteViews in the first position in the list,
and then have another notification come in with an earlier timestampe.  In
that case, it would get a bad index for the new (not bogus) view that was
being added.
diff --git a/services/java/com/android/server/status/NotificationData.java b/services/java/com/android/server/status/NotificationData.java
index 0a3411a1..784b781 100644
--- a/services/java/com/android/server/status/NotificationData.java
+++ b/services/java/com/android/server/status/NotificationData.java
@@ -19,7 +19,7 @@
     public PendingIntent deleteIntent;
 
     public String toString() {
-        return "NotificationData(package=" + pkg + " tickerText=" + tickerText
+        return "NotificationData(package=" + pkg + " id=" + id + " tickerText=" + tickerText
                 + " ongoingEvent=" + ongoingEvent + " contentIntent=" + contentIntent
                 + " deleteIntent=" + deleteIntent
                 + " clearable=" + clearable
diff --git a/services/java/com/android/server/status/NotificationViewList.java b/services/java/com/android/server/status/NotificationViewList.java
index 6229292..8f1633f 100644
--- a/services/java/com/android/server/status/NotificationViewList.java
+++ b/services/java/com/android/server/status/NotificationViewList.java
@@ -104,10 +104,25 @@
         return null;
     }
 
-    // gets the index of the notification in its expanded parent view
+    // gets the index of the notification's view in its expanded parent view
     int getExpandedIndex(StatusBarNotification notification) {
         ArrayList<StatusBarNotification> list = notification.data.ongoingEvent ? mOngoing : mLatest;
-        return list.size() - indexForKey(list, notification.key) - 1;
+        final IBinder key = notification.key;
+        int index = 0;
+        // (the view order is backwards from this list order)
+        for (int i=list.size()-1; i>=0; i--) {
+            StatusBarNotification item = list.get(i);
+            if (item.key == key) {
+                return index;
+            }
+            if (item.view != null) {
+                index++;
+            }
+        }
+        Log.e(StatusBarService.TAG, "Couldn't find notification in NotificationViewList.");
+        Log.e(StatusBarService.TAG, "notification=" + notification);
+        dump(notification);
+        return 0;
     }
 
     void clearViews() {
@@ -156,6 +171,13 @@
         list.add(index, notification);
 
         if (StatusBarService.SPEW) {
+            Log.d(StatusBarService.TAG, "NotificationViewList index=" + index);
+            dump(notification);
+        }
+    }
+
+    void dump(StatusBarNotification notification) {
+        if (StatusBarService.SPEW) {
             String s = "";
             for (int i=0; i<mOngoing.size(); i++) {
                 StatusBarNotification that = mOngoing.get(i);
@@ -168,7 +190,7 @@
                 }
                 s += " ";
             }
-            Log.d(StatusBarService.TAG, "NotificationViewList ongoing index=" + index + ": " + s);
+            Log.d(StatusBarService.TAG, "NotificationViewList ongoing: " + s);
 
             s = "";
             for (int i=0; i<mLatest.size(); i++) {
@@ -182,7 +204,7 @@
                 }
                 s += " ";
             }
-            Log.d(StatusBarService.TAG, "NotificationViewList latest  index=" + index + ": " + s);
+            Log.d(StatusBarService.TAG, "NotificationViewList latest:  " + s);
         }
     }
 
diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java
index 7b722a5..ab29575 100644
--- a/services/java/com/android/server/status/StatusBarService.java
+++ b/services/java/com/android/server/status/StatusBarService.java
@@ -886,7 +886,8 @@
                 && n.contentView.getPackage() != null
                 && oldData.contentView.getPackage() != null
                 && oldData.contentView.getPackage().equals(n.contentView.getPackage())
-                && oldData.contentView.getLayoutId() == n.contentView.getLayoutId()) {
+                && oldData.contentView.getLayoutId() == n.contentView.getLayoutId()
+                && notification.view != null) {
             mNotificationData.update(notification);
             try {
                 n.contentView.reapply(mContext, notification.contentView);
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index ffc2cbc..f548145 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -121,6 +121,32 @@
             }
         },
 
+        new Test("Bad resource #2") {
+            public void run()
+            {
+                Notification n = new Notification(NotificationTestList.this,
+                            R.drawable.ic_statusbar_missedcall,
+                            null, System.currentTimeMillis()-(1000*60*60*24),
+                            "(453) 123-2328",
+                            "", null);
+                n.contentView.setInt(1 /*bogus*/, "bogus method", 666);
+                mNM.notify(2, n);
+            }
+        },
+
+        new Test("Bad resource #3") {
+            public void run()
+            {
+                Notification n = new Notification(NotificationTestList.this,
+                            R.drawable.ic_statusbar_missedcall,
+                            null, System.currentTimeMillis()-(1000*60*60*24),
+                            "(453) 123-2328",
+                            "", null);
+                n.contentView.setInt(1 /*bogus*/, "bogus method", 666);
+                mNM.notify(3, n);
+            }
+        },
+
         new Test("Times") {
             public void run()
             {
@@ -405,6 +431,16 @@
             }
         },
 
+        new Test("Persistent #3") {
+            public void run() {
+                Notification n = new Notification(R.drawable.icon2, "tock tock tock",
+                        System.currentTimeMillis());
+                n.setLatestEventInfo(NotificationTestList.this, "Persistent #3",
+                            "Notify me!!!", makeIntent());
+                mNM.notify(3, n);
+            }
+        },
+
         new Test("Persistent #2 Vibrate") {
             public void run() {
                 Notification n = new Notification(R.drawable.icon2, "tock tock tock",