Merge "Speculative fix: ensure avatars are not created with empty email addresses" into ub-gmail-ur14-dev
diff --git a/src/com/android/mail/browse/ConversationItemViewModel.java b/src/com/android/mail/browse/ConversationItemViewModel.java
index 84cf59a..a54fcfe 100644
--- a/src/com/android/mail/browse/ConversationItemViewModel.java
+++ b/src/com/android/mail/browse/ConversationItemViewModel.java
@@ -337,14 +337,19 @@
          * Removes the name and email address of the participant of this avatar.
          */
         public void clear() {
-            populate(null, null);
+            mName = null;
+            mEmailAddress = null;
         }
 
         /**
          * @param name the name of the participant of this avatar
-         * @param emailAddress the email address of the participant of this avatar
+         * @param emailAddress the email address of the participant of this avatar; may not be null
          */
         public void populate(String name, String emailAddress) {
+            if (TextUtils.isEmpty(emailAddress)) {
+                throw new IllegalArgumentException("email address may not be null or empty");
+            }
+
             mName = name;
             mEmailAddress = emailAddress;
         }
@@ -354,7 +359,7 @@
          *      avatar image; <tt>false</tt> otherwise
          */
         public boolean isNotPopulated() {
-            return mEmailAddress == null;
+            return TextUtils.isEmpty(mEmailAddress);
         }
     }
 }
\ No newline at end of file
diff --git a/src/com/android/mail/browse/SendersView.java b/src/com/android/mail/browse/SendersView.java
index 6ce12cb..898568c 100644
--- a/src/com/android/mail/browse/SendersView.java
+++ b/src/com/android/mail/browse/SendersView.java
@@ -418,8 +418,12 @@
             // search for the last sender that is not the current account
             for (int i = conversationInfo.participantInfos.size() - 1; i >= 0; i--) {
                 final ParticipantInfo participant = conversationInfo.participantInfos.get(i);
+                // empty name implies it is the current account and should not be chosen
                 if (!TextUtils.isEmpty(participant.name)) {
-                    senderAvatarModel.populate(participant.name, participant.email);
+                    // use the participant name in place of unusable email addresses
+                    final String senderEmail = TextUtils.isEmpty(participant.email) ?
+                            participant.name : participant.email;
+                    senderAvatarModel.populate(participant.name, senderEmail);
                     break;
                 }
             }
diff --git a/tests/src/com/android/mail/browse/SendersFormattingTests.java b/tests/src/com/android/mail/browse/SendersFormattingTests.java
index cbfb7ac..14b31ec 100644
--- a/tests/src/com/android/mail/browse/SendersFormattingTests.java
+++ b/tests/src/com/android/mail/browse/SendersFormattingTests.java
@@ -139,10 +139,31 @@
         SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames,
                 senderAvatarModel, account, false, false);
 
+        // b is the first unread message with a valid email address
         assertEquals("b@b.com", senderAvatarModel.getEmailAddress());
         assertEquals("b", senderAvatarModel.getName());
     }
 
+    public void testSenderAvatarDoesNotChooseEmptyEmailAddress() {
+        final ConversationInfo conv = createConversationInfo();
+        conv.addParticipant(new ParticipantInfo("a", "a@a.com", 0, true));
+        conv.addParticipant(new ParticipantInfo("b", "", 0, false));
+        conv.addParticipant(new ParticipantInfo("c", "c@c.com", 0, false));
+
+        final ArrayList<SpannableString> styledSenders = Lists.newArrayList();
+        final ArrayList<String> displayableSenderNames = Lists.newArrayList();
+        final ConversationItemViewModel.SenderAvatarModel senderAvatarModel =
+                new ConversationItemViewModel.SenderAvatarModel();
+
+        final Account account = createAccount();
+        SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames,
+                senderAvatarModel, account, false, false);
+
+        // b is unread but has an invalid email address so email address is set to the name
+        assertEquals("b", senderAvatarModel.getEmailAddress());
+        assertEquals("b", senderAvatarModel.getName());
+    }
+
     public void testSenderAvatarIsLastSenderIfAllMessagesAreRead() {
         final ConversationInfo conv = createConversationInfo();
         conv.addParticipant(new ParticipantInfo("a", "a@a.com", 0, true));
@@ -158,10 +179,31 @@
         SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames,
                 senderAvatarModel, account, false, false);
 
+        // all are read, so c is chosen because it is the last sender
         assertEquals("c@c.com", senderAvatarModel.getEmailAddress());
         assertEquals("c", senderAvatarModel.getName());
     }
 
+    public void testSenderAvatarIsLastSenderWithValidEmailAddressIfAllMessagesAreRead() {
+        final ConversationInfo conv = createConversationInfo();
+        conv.addParticipant(new ParticipantInfo("a", "a@a.com", 0, true));
+        conv.addParticipant(new ParticipantInfo("b", "b@b.com", 0, true));
+        conv.addParticipant(new ParticipantInfo("c", "", 0, true));
+
+        final ArrayList<SpannableString> styledSenders = Lists.newArrayList();
+        final ArrayList<String> displayableSenderNames = Lists.newArrayList();
+        final ConversationItemViewModel.SenderAvatarModel senderAvatarModel =
+                new ConversationItemViewModel.SenderAvatarModel();
+
+        final Account account = createAccount();
+        SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames,
+                senderAvatarModel, account, false, false);
+
+        // all are read, c has an invalid email address, so email address is set to the name
+        assertEquals("c", senderAvatarModel.getEmailAddress());
+        assertEquals("c", senderAvatarModel.getName());
+    }
+
     public void testSenderAvatarIsLastSenderThatIsNotTheCurrentAccountIfAllMessagesAreRead() {
         final ConversationInfo conv = createConversationInfo();
         conv.addParticipant(new ParticipantInfo("a", "a@a.com", 0, true));
@@ -178,6 +220,7 @@
         SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames,
                 senderAvatarModel, account, false, false);
 
+        // c is the last sender, but it is the current account, so b is chosen instead
         assertEquals("b@b.com", senderAvatarModel.getEmailAddress());
         assertEquals("b", senderAvatarModel.getName());
     }
@@ -196,6 +239,7 @@
         SendersView.format(getContext(), conv, "", 100, styledSenders, displayableSenderNames,
                 senderAvatarModel, account, false, false);
 
+        // only one sender exists and it is the current account, so the current account is chosen
         assertEquals("fflintstone@example.com", senderAvatarModel.getEmailAddress());
         assertEquals("Fred Flintstone", senderAvatarModel.getName());
     }