DO NOT MERGE - Merge Android R QPR1

Bug: 172690556
Merged-In: I341535e9c45171c5ab73e27017721a78a97a36a0
Change-Id: I3a175dec77dde6054d77c59b27714a9cffb1ff20
diff --git a/src/com/android/car/messenger/MessageNotificationDelegate.java b/src/com/android/car/messenger/MessageNotificationDelegate.java
index 2b7126b..5fa6db0 100644
--- a/src/com/android/car/messenger/MessageNotificationDelegate.java
+++ b/src/com/android/car/messenger/MessageNotificationDelegate.java
@@ -56,15 +56,14 @@
 import com.bumptech.glide.request.transition.Transition;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Consumer;
-import java.util.stream.Collectors;
 
 /** Delegate class responsible for handling messaging service actions */
 public class MessageNotificationDelegate extends BaseNotificationDelegate implements
@@ -77,6 +76,7 @@
     /** Tracks whether a projection application is active in the foreground. **/
     private ProjectionStateListener mProjectionStateListener;
     private CompletableFuture<Void> mPhoneNumberInfoFuture;
+    private Locale mGeneratedGroupConversationTitlesLocale;
     private static int mBitmapSize;
     private static float mCornerRadiusPercent;
     private static boolean mShouldLoadExistingMessages;
@@ -149,9 +149,14 @@
 
     @Override
     public void onDeviceDisconnected(BluetoothDevice device) {
-        logd(TAG, "Device disconnected: " + device.getAddress());
-        cleanupMessagesAndNotifications(key -> key.matches(device.getAddress()));
-        mBtDeviceAddressToConnectionTimestamp.remove(device.getAddress());
+        String deviceAddress = device.getAddress();
+        logd(TAG, "Device disconnected: " + deviceAddress);
+        cleanupMessagesAndNotifications(key -> key.matches(deviceAddress));
+        mBtDeviceAddressToConnectionTimestamp.remove(deviceAddress);
+        mSenderToLargeIconBitmap.entrySet().removeIf(entry ->
+                entry.getKey().getDeviceId().equals(deviceAddress));
+        mGeneratedGroupConversationTitles.removeIf(
+                convoKey -> convoKey.getDeviceId().equals(deviceAddress));
     }
 
     @Override
@@ -250,6 +255,7 @@
         mUriToSenderNameMap.clear();
         mSenderToLargeIconBitmap.clear();
         mBtDeviceAddressToConnectionTimestamp.clear();
+        mGeneratedGroupConversationTitles.clear();
     }
 
     /**
@@ -392,6 +398,13 @@
      */
     private void setGroupConversationTitle(ConversationKey conversationKey) {
         ConversationNotificationInfo notificationInfo = mNotificationInfos.get(conversationKey);
+        Locale locale = Locale.getDefault();
+
+        // Do not reuse the old titles if locale has changed. The new locale might need different
+        // formatting or text direction.
+        if (locale != mGeneratedGroupConversationTitlesLocale) {
+            mGeneratedGroupConversationTitles.clear();
+        }
         if (!notificationInfo.isGroupConvo()
                 || mGeneratedGroupConversationTitles.contains(conversationKey)) {
             return;
@@ -410,22 +423,12 @@
             }
         }
 
-        notificationInfo.setConvoTitle(constructGroupConversationTitle(names));
-        if (allNamesLoaded) mGeneratedGroupConversationTitles.add(conversationKey);
-    }
-
-    /**
-     * Given a name of all the participants in a group conversation (some names might be phone
-     * numbers), this function creates the conversation title putting the names in alphabetical
-     * order first, then adding any phone numbers. This title should not exceed the
-     * mNotificationConversationTitleLength, so not all participants' names are guaranteed to be
-     * in the conversation title.
-     */
-    private String constructGroupConversationTitle(List<String> names) {
-        Collections.sort(names, Utils.ALPHA_THEN_NUMERIC_COMPARATOR);
-
-        return names.stream().map(String::valueOf).collect(
-                Collectors.joining(mContext.getString(R.string.name_separator)));
+        notificationInfo.setConvoTitle(Utils.constructGroupConversationTitle(names,
+                mContext.getString(R.string.name_separator), mNotificationConversationTitleLength));
+        if (allNamesLoaded) {
+            mGeneratedGroupConversationTitlesLocale = locale;
+            mGeneratedGroupConversationTitles.add(conversationKey);
+        }
     }
 
     private void loadPhoneNumberInfo(@Nullable String phoneNumber,