Merge "Revert "Messaging: Show quick reply choices only on wearable devices""
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3468ac3..9793846 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -69,6 +69,7 @@
             android:configChanges="orientation|screenSize|keyboardHidden"
             android:screenOrientation="user"
             android:label="@string/app_name"
+            android:exported="true"
             android:theme="@style/BugleTheme.ConversationListActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -90,6 +91,7 @@
             android:screenOrientation="user"
             android:theme="@style/Invisible"
             android:noHistory="true"
+            android:exported="true"
             android:documentLaunchMode="always">
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
@@ -191,6 +193,7 @@
             android:parentActivityName="com.android.messaging.ui.appsettings.SettingsActivity">
             <meta-data
                 android:name="android.support.PARENT_ACTIVITY"
+                android:exported="true"
                 android:value="com.android.messaging.ui.appsettings.SettingsActivity" />
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -206,6 +209,7 @@
             android:screenOrientation="user"
             android:theme="@style/BugleTheme.DialogActivity"
             android:excludeFromRecents="true"
+            android:exported="true"
             android:documentLaunchMode="always">
             <intent-filter
                 android:label="@string/share_intent_label">
@@ -336,6 +340,7 @@
         <!-- Registered with the highest possible priority (max_int) -->
         <receiver android:name=".receiver.MmsWapPushReceiver"
                   android:enabled="false"
+                  android:exported="true"
                   android:permission="android.permission.BROADCAST_WAP_PUSH">
             <intent-filter android:priority="2147483647">
                 <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
@@ -344,6 +349,7 @@
         </receiver>
         <receiver android:name=".receiver.SmsReceiver"
                   android:enabled="false"
+                  android:exported="true"
                   android:permission="android.permission.BROADCAST_SMS">
             <intent-filter android:priority="2147483647">
                 <action android:name="android.provider.Telephony.SMS_RECEIVED" />
@@ -357,6 +363,7 @@
         <!-- Registered for a priority just ahead of inbox Messaging apps (2) -->
         <receiver android:name=".receiver.AbortMmsWapPushReceiver"
                   android:enabled="false"
+                  android:exported="true"
                   android:permission="android.permission.BROADCAST_WAP_PUSH">
             <intent-filter android:priority="3">
                 <action android:name="android.provider.Telephony.WAP_PUSH_RECEIVED" />
@@ -365,6 +372,7 @@
         </receiver>
         <receiver android:name=".receiver.AbortSmsReceiver"
                   android:enabled="false"
+                  android:exported="true"
                   android:permission="android.permission.BROADCAST_SMS">
             <intent-filter android:priority="3">
                 <action android:name="android.provider.Telephony.SMS_RECEIVED" />
@@ -373,6 +381,7 @@
 
         <!-- Intents for KLP+ Delivery -->
         <receiver android:name=".receiver.MmsWapPushDeliverReceiver"
+                  android:exported="true"
                   android:permission="android.permission.BROADCAST_WAP_PUSH">
             <intent-filter>
                 <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
@@ -380,6 +389,7 @@
             </intent-filter>
         </receiver>
         <receiver android:name=".receiver.SmsDeliverReceiver"
+                  android:exported="true"
                   android:permission="android.permission.BROADCAST_SMS">
             <intent-filter>
                 <action android:name="android.provider.Telephony.SMS_DELIVER" />
@@ -441,7 +451,8 @@
                   android:theme="@style/BugleTheme"
                   android:parentActivityName="com.android.messaging.ui.appsettings.ApnSettingsActivity"/>
 
-        <receiver android:name=".receiver.StorageStatusReceiver">
+        <receiver android:name=".receiver.StorageStatusReceiver"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.DEVICE_STORAGE_LOW" />
             </intent-filter>
@@ -450,11 +461,12 @@
             </intent-filter>
         </receiver>
 
-        <receiver android:name=".receiver.BootAndPackageReplacedReceiver">
+        <receiver android:name=".receiver.BootAndPackageReplacedReceiver"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.BOOT_COMPLETED"/>
                 <action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
-                </intent-filter>
+            </intent-filter>
         </receiver>
 
         <!-- Broadcast receiver that will be notified to reset notifications -->
@@ -472,7 +484,8 @@
             </intent-filter>
         </receiver>
 
-        <receiver android:name=".receiver.DefaultSmsSubscriptionChangeReceiver">
+        <receiver android:name=".receiver.DefaultSmsSubscriptionChangeReceiver"
+            android:exported="true">
             <intent-filter>
                 <action android:name="android.telephony.action.DEFAULT_SMS_SUBSCRIPTION_CHANGED"/>
             </intent-filter>
@@ -480,6 +493,7 @@
 
         <!-- Widget that displays the conversation list -->
         <receiver android:name=".widget.BugleWidgetProvider"
+                android:exported="true"
                 android:label="@string/widget_conversation_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@@ -490,6 +504,7 @@
 
         <!-- Widget that displays the messages of a single conversation -->
         <receiver android:name=".widget.WidgetConversationProvider"
+                android:exported="true"
                 android:label="@string/widget_conversation_name">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
@@ -508,6 +523,7 @@
 
         <activity android:name=".ui.WidgetPickConversationActivity"
             android:theme="@style/BugleTheme"
+                android:exported="true"
             android:label="@string/app_name" >
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
diff --git a/res/layout/apn_preference_layout.xml b/res/layout/apn_preference_layout.xml
index 8b864f6..12693d4 100644
--- a/res/layout/apn_preference_layout.xml
+++ b/res/layout/apn_preference_layout.xml
@@ -38,7 +38,7 @@
         android:background="?android:attr/selectableItemBackground">
 
         <TextView
-            android:id="@+id/title"
+            android:id="@android:id/title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:focusable="true"
@@ -46,7 +46,7 @@
             android:textAppearance="?android:attr/textAppearanceListItem" />
 
         <TextView
-            android:id="@+id/summary"
+            android:id="@android:id/summary"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_below="@android:id/title"
diff --git a/src/android/support/v7/mms/MmsManager.java b/src/android/support/v7/mms/MmsManager.java
index 4a72a32..642a141 100644
--- a/src/android/support/v7/mms/MmsManager.java
+++ b/src/android/support/v7/mms/MmsManager.java
@@ -135,13 +135,13 @@
      */
     public static void sendMultimediaMessage(int subId, Context context, Uri contentUri,
             String locationUrl, PendingIntent sentIntent) {
-        if (Utils.hasMmsApi() && !sForceLegacyMms) {
+        if (shouldUseLegacyMms()) {
+            MmsService.startRequest(context, new SendRequest(locationUrl, contentUri, sentIntent));
+        } else {
             subId = Utils.getEffectiveSubscriptionId(subId);
             final SmsManager smsManager = Utils.getSmsManager(subId);
             smsManager.sendMultimediaMessage(context, contentUri, locationUrl,
                     getConfigOverrides(subId), sentIntent);
-        } else {
-            MmsService.startRequest(context, new SendRequest(locationUrl, contentUri, sentIntent));
         }
     }
 
@@ -157,18 +157,27 @@
      */
     public static void downloadMultimediaMessage(int subId, Context context, String locationUrl,
             Uri contentUri, PendingIntent downloadedIntent) {
-        if (Utils.hasMmsApi() && !sForceLegacyMms) {
+        if (shouldUseLegacyMms()) {
+            MmsService.startRequest(context,
+                    new DownloadRequest(locationUrl, contentUri, downloadedIntent));
+        } else {
             subId = Utils.getEffectiveSubscriptionId(subId);
             final SmsManager smsManager = Utils.getSmsManager(subId);
             smsManager.downloadMultimediaMessage(context, locationUrl, contentUri,
                     getConfigOverrides(subId), downloadedIntent);
-        } else {
-            MmsService.startRequest(context,
-                    new DownloadRequest(locationUrl, contentUri, downloadedIntent));
         }
     }
 
     /**
+     * Checks if we should use legacy APIs for MMS.
+     *
+     * @return true if forced to use legacy APIs or platform doesn't supports MMS APIs.
+     */
+    public static boolean shouldUseLegacyMms() {
+        return sForceLegacyMms || !Utils.hasMmsApi();
+    }
+
+    /**
      * Get carrier configuration values overrides when platform MMS API is called.
      * We only need to compute this if customized carrier config values loader or
      * user agent info loader are set
diff --git a/src/com/android/messaging/datamodel/MessageNotificationState.java b/src/com/android/messaging/datamodel/MessageNotificationState.java
index 68d8538..f0e8364 100644
--- a/src/com/android/messaging/datamodel/MessageNotificationState.java
+++ b/src/com/android/messaging/datamodel/MessageNotificationState.java
@@ -100,7 +100,6 @@
     protected CharSequence mContent = null;
     protected Uri mAttachmentUri = null;
     protected String mAttachmentType = null;
-    protected boolean mTickerNoContent;
 
     @Override
     protected Uri getAttachmentUri() {
@@ -1088,8 +1087,10 @@
         }
         if (state != null && LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
             LogUtil.v(TAG, "MessageNotificationState: Notification state created"
-                    + ", title = " + LogUtil.sanitizePII(state.mTitle)
-                    + ", content = " + LogUtil.sanitizePII(state.mContent.toString()));
+                    + ", title = "
+                    + (state.mTickerSender != null ? state.mTickerSender : state.mTitle)
+                    + ", content = "
+                    + (state.mTickerText != null ? state.mTickerText : state.mContent));
         }
         return state;
     }
@@ -1129,8 +1130,9 @@
     protected CharSequence getTicker() {
         return BugleNotifications.buildColonSeparatedMessage(
                 mTickerSender != null ? mTickerSender : mTitle,
-                mTickerText != null ? mTickerText : (mTickerNoContent ? null : mContent), null,
-                        null);
+                mTickerText != null ? mTickerText : mContent,
+                null,
+                null);
     }
 
     private static CharSequence convertHtmlAndStripUrls(final String s) {
diff --git a/src/com/android/messaging/datamodel/action/ProcessDownloadedMmsAction.java b/src/com/android/messaging/datamodel/action/ProcessDownloadedMmsAction.java
index 07e2cfb..60d3e35 100644
--- a/src/com/android/messaging/datamodel/action/ProcessDownloadedMmsAction.java
+++ b/src/com/android/messaging/datamodel/action/ProcessDownloadedMmsAction.java
@@ -83,7 +83,7 @@
     // Set when message downloaded by us (legacy)
     private static final String KEY_STATUS = "status";
     private static final String KEY_RAW_STATUS = "raw_status";
-    private static final String KEY_MMS_URI =  "mms_uri";
+    private static final String KEY_MMS_URI = "mms_uri";
 
     // Used to send a deferred response in response to auto-download failure
     private static final String KEY_SEND_DEFERRED_RESP_STATUS = "send_deferred_resp_status";
@@ -329,6 +329,8 @@
         if (response == null) {
             // No message download to process; doBackgroundWork sent a notify deferred response
             Assert.isTrue(actionParameters.getBoolean(KEY_SEND_DEFERRED_RESP_STATUS));
+            ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(
+                    true /* failed */, this);
             return null;
         }
 
@@ -343,7 +345,9 @@
 
         final int subId = actionParameters.getInt(KEY_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID);
         // If we were trying to auto-download but have failed need to send the deferred response
-        if (autoDownload && message == null && status == MmsUtils.MMS_REQUEST_MANUAL_RETRY) {
+        final boolean needToSendDeferredResp =
+                autoDownload && (status == MmsUtils.MMS_REQUEST_MANUAL_RETRY);
+        if (needToSendDeferredResp) {
             final String transactionId = actionParameters.getString(KEY_TRANSACTION_ID);
             final String contentLocation = actionParameters.getString(KEY_CONTENT_LOCATION);
             sendDeferredRespStatus(messageId, transactionId, contentLocation, subId);
@@ -373,7 +377,11 @@
         }
 
         final boolean failed = (messageUri == null);
-        ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(failed, this);
+        // Scheduling pending messages. If auto downloading is failed and it needs to send the
+        // deferred response, Skip it here and it will be scheduled after sending the response.
+        if (!needToSendDeferredResp) {
+            ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(failed, this);
+        }
         if (failed) {
             BugleNotifications.update(false, BugleNotifications.UPDATE_ERRORS);
         }
diff --git a/src/com/android/messaging/datamodel/action/ProcessPendingMessagesAction.java b/src/com/android/messaging/datamodel/action/ProcessPendingMessagesAction.java
index f164148..1a3eb63 100644
--- a/src/com/android/messaging/datamodel/action/ProcessPendingMessagesAction.java
+++ b/src/com/android/messaging/datamodel/action/ProcessPendingMessagesAction.java
@@ -301,12 +301,16 @@
         unregister(subId);
 
         if (PhoneUtils.getDefault().isDefaultSmsApp()) {
-            queueActions(this);
+            if (!queueActions(this)) {
+                LogUtil.v(TAG, "ProcessPendingMessagesAction: rescheduling");
+                // TODO: Need to clear retry count here?
+                scheduleProcessPendingMessagesAction(true /* failed */, this);
+            }
         } else {
             if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
                 LogUtil.v(TAG, "ProcessPendingMessagesAction: Not default SMS app; rescheduling");
             }
-            scheduleProcessPendingMessagesAction(true, this);
+            scheduleProcessPendingMessagesAction(true /* failed */, this);
         }
 
         return null;
diff --git a/src/com/android/messaging/datamodel/action/ProcessSentMessageAction.java b/src/com/android/messaging/datamodel/action/ProcessSentMessageAction.java
index f408e47..489a0f1 100644
--- a/src/com/android/messaging/datamodel/action/ProcessSentMessageAction.java
+++ b/src/com/android/messaging/datamodel/action/ProcessSentMessageAction.java
@@ -207,6 +207,8 @@
         if (message == null) {
             LogUtil.w(TAG, "ProcessSentMessageAction: Sent message " + messageId
                     + " missing from local database");
+            ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(
+                    true /* failed */, processingAction);
             return;
         }
         final String conversationId = message.getConversationId();
diff --git a/src/com/android/messaging/datamodel/action/SendMessageAction.java b/src/com/android/messaging/datamodel/action/SendMessageAction.java
index d7ebe8f..35e6280 100644
--- a/src/com/android/messaging/datamodel/action/SendMessageAction.java
+++ b/src/com/android/messaging/datamodel/action/SendMessageAction.java
@@ -44,7 +44,6 @@
  * Action used to send an outgoing message. It writes MMS messages to the telephony db
  * ({@link InsertNewMessageAction}) writes SMS messages to the telephony db). It also
  * initiates the actual sending. It will all be used for re-sending a failed message.
- * NOTE: This action must queue a ProcessPendingMessagesAction when it is done (success or failure).
  * <p>
  * This class is public (not package-private) because the SMS/MMS (e.g. MmsUtils) classes need to
  * access the EXTRA_* fields for setting up the 'sent' pending intent.
@@ -294,9 +293,6 @@
                 MmsUtils.MMS_REQUEST_MANUAL_RETRY, MessageData.RAW_TELEPHONY_STATUS_UNDEFINED,
                 isSms, this, subId, resultCode, httpStatusCode);
 
-        // Whether we succeeded or failed we will check and maybe schedule some more work
-        ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(true, this);
-
         return null;
     }
 
diff --git a/src/com/android/messaging/datamodel/data/ConversationMessageData.java b/src/com/android/messaging/datamodel/data/ConversationMessageData.java
index 19e1b97..2a85277 100644
--- a/src/com/android/messaging/datamodel/data/ConversationMessageData.java
+++ b/src/com/android/messaging/datamodel/data/ConversationMessageData.java
@@ -523,7 +523,8 @@
     }
 
     public boolean getIsSendComplete() {
-        return mStatus == MessageData.BUGLE_STATUS_OUTGOING_COMPLETE;
+        return (mStatus == MessageData.BUGLE_STATUS_OUTGOING_COMPLETE
+                || mStatus == MessageData.BUGLE_STATUS_OUTGOING_DELIVERED);
     }
 
     public String getSenderFullName() {
@@ -575,8 +576,9 @@
     public boolean getCanForwardMessage() {
         // Even for outgoing messages, we only allow forwarding if the message has finished sending
         // as media often has issues when send isn't complete
-        return (mStatus == MessageData.BUGLE_STATUS_OUTGOING_COMPLETE ||
-                mStatus == MessageData.BUGLE_STATUS_INCOMING_COMPLETE);
+        return (mStatus == MessageData.BUGLE_STATUS_OUTGOING_COMPLETE
+                || mStatus == MessageData.BUGLE_STATUS_OUTGOING_DELIVERED
+                || mStatus == MessageData.BUGLE_STATUS_INCOMING_COMPLETE);
     }
 
     public boolean getCanCopyMessageToClipboard() {
diff --git a/src/com/android/messaging/datamodel/data/DraftMessageData.java b/src/com/android/messaging/datamodel/data/DraftMessageData.java
index 7a7199a..f63c27f 100644
--- a/src/com/android/messaging/datamodel/data/DraftMessageData.java
+++ b/src/com/android/messaging/datamodel/data/DraftMessageData.java
@@ -339,11 +339,23 @@
      */
     private boolean addOneAttachmentNoNotify(final MessagePartData attachment) {
         Assert.isTrue(attachment.isAttachment());
+        // Check duplication.
+        for (final MessagePartData existingAttachment : mAttachments) {
+            if (existingAttachment.getContentUri().equals(attachment.getContentUri())) {
+                // Destroy existing attachment and replace with new attachment instead of destroying
+                // new one so that mSelectedImages in GalleryGridView could be maintained correctly.
+                mAttachments.remove(existingAttachment);
+                existingAttachment.destroyAsync();
+                addAttachment(attachment, null /*pendingAttachment*/);
+                return false;
+            }
+        }
+
         final boolean reachedLimit = getAttachmentCount() >= getAttachmentLimit();
-        if (reachedLimit || containsAttachment(attachment.getContentUri())) {
-            // Never go over the limit. Never add duplicated attachments.
+        if (reachedLimit) {
+            // Never go over the limit.
             attachment.destroyAsync();
-            return reachedLimit;
+            return true;
         } else {
             addAttachment(attachment, null /*pendingAttachment*/);
             return false;
diff --git a/src/com/android/messaging/datamodel/data/MessageData.java b/src/com/android/messaging/datamodel/data/MessageData.java
index a8c8bc1..b2cab48 100644
--- a/src/com/android/messaging/datamodel/data/MessageData.java
+++ b/src/com/android/messaging/datamodel/data/MessageData.java
@@ -582,7 +582,7 @@
             // primary user.
             return false;
         }
-        // Should show option for manual download iff status is manual download or failed
+        // Should show option for manual download if status is manual download or failed
         return (status == BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED ||
                 status == BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD ||
                 // If debug is enabled, allow to download an expired or unavailable message.
@@ -596,7 +596,7 @@
             // primary user.
             return false;
         }
-        // Can download iff status is retrying auto/manual downloading
+        // Can download if status is retrying auto/manual downloading
         return (mStatus == BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD ||
                 mStatus == BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD);
     }
@@ -607,7 +607,7 @@
             // primary user.
             return false;
         }
-        // Can redownload iff status is manual download not started or download failed
+        // Can redownload if status is manual download not started or download failed
         return (mStatus == BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED ||
                 mStatus == BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD ||
                 // If debug is enabled, allow to download an expired or unavailable message.
@@ -616,12 +616,12 @@
     }
 
     static boolean getShowResendMessage(final int status) {
-        // Should show option to resend iff status is failed
+        // Should show option to resend if status is failed
         return (status == BUGLE_STATUS_OUTGOING_FAILED);
     }
 
     static boolean getOneClickResendMessage(final int status, final int rawStatus) {
-        // Should show option to resend iff status is failed
+        // Should show option to resend if status is failed
         return (status == BUGLE_STATUS_OUTGOING_FAILED
                 && rawStatus == RAW_TELEPHONY_STATUS_UNDEFINED);
     }
diff --git a/src/com/android/messaging/ui/SnackBarManager.java b/src/com/android/messaging/ui/SnackBarManager.java
index e107999..d5ca870 100644
--- a/src/com/android/messaging/ui/SnackBarManager.java
+++ b/src/com/android/messaging/ui/SnackBarManager.java
@@ -25,6 +25,7 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.MeasureSpec;
+import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
@@ -86,6 +87,23 @@
         }
     };
 
+    private final OnAttachStateChangeListener mAttachStateChangeListener =
+            new OnAttachStateChangeListener() {
+                @Override
+                public void onViewDetachedFromWindow(View v) {
+                    // Dismiss the PopupWindow and clear SnackBarManager state.
+                    mHideHandler.removeCallbacks(mDismissRunnable);
+                    mPopupWindow.dismiss();
+
+                    mCurrentSnackBar = null;
+                    mNextSnackBar = null;
+                    mIsCurrentlyDismissing = false;
+                }
+
+                @Override
+                public void onViewAttachedToWindow(View v) {}
+            };
+
     private final int mTranslationDurationMs;
     private final Handler mHideHandler;
 
@@ -181,6 +199,7 @@
             mPopupWindow.showAsDropDown(anchorView, 0, getRelativeOffset(snackBar));
         }
 
+        snackBar.getParentView().addOnAttachStateChangeListener(mAttachStateChangeListener);
 
         // Animate the toast bar into view.
         placeSnackBarOffScreen(snackBar);
@@ -238,6 +257,8 @@
                     // PopupWindow.dismiss() will fire an IllegalArgumentException if the activity
                     // has already ended while we were animating
                 }
+                snackBar.getParentView()
+                        .removeOnAttachStateChangeListener(mAttachStateChangeListener);
 
                 mCurrentSnackBar = null;
                 mIsCurrentlyDismissing = false;
diff --git a/src/com/android/messaging/ui/appsettings/ApnPreference.java b/src/com/android/messaging/ui/appsettings/ApnPreference.java
index c5cc85a..64358eb 100644
--- a/src/com/android/messaging/ui/appsettings/ApnPreference.java
+++ b/src/com/android/messaging/ui/appsettings/ApnPreference.java
@@ -26,7 +26,6 @@
 import android.widget.CompoundButton;
 import android.widget.RadioButton;
 import android.widget.RelativeLayout;
-import android.widget.TextView;
 
 import com.android.messaging.R;
 import com.android.messaging.datamodel.data.ParticipantData;
@@ -81,7 +80,7 @@
             } else {
                 rb.setVisibility(View.GONE);
             }
-            setApnRadioButtonContentDescription(rb);
+            rb.setContentDescription(getTitle());
         }
 
         View textLayout = view.findViewById(R.id.text_layout);
@@ -92,13 +91,6 @@
         return view;
     }
 
-    public void setApnRadioButtonContentDescription(final CompoundButton buttonView) {
-        final View widget = (View) buttonView.getParent();
-        final TextView tv = (TextView) widget.findViewById(R.id.title);
-        final String apnTitle = tv.getText().toString();
-        buttonView.setContentDescription(apnTitle);
-    }
-
     public boolean isChecked() {
         return getKey().equals(mSelectedKey);
     }
@@ -128,7 +120,7 @@
             mCurrentChecked = null;
             mSelectedKey = null;
         }
-        setApnRadioButtonContentDescription(buttonView);
+        buttonView.setContentDescription(getTitle());
     }
 
     public void onClick(android.view.View v) {
diff --git a/src/com/android/messaging/ui/appsettings/ApnSettingsActivity.java b/src/com/android/messaging/ui/appsettings/ApnSettingsActivity.java
index 8b4644e..13f775a 100644
--- a/src/com/android/messaging/ui/appsettings/ApnSettingsActivity.java
+++ b/src/com/android/messaging/ui/appsettings/ApnSettingsActivity.java
@@ -274,7 +274,7 @@
             if (!mUnavailable) {
                 menu.add(0, MENU_NEW, 0,
                         getResources().getString(R.string.menu_new_apn))
-                        .setIcon(R.drawable.ic_add_gray)
+                        .setIcon(R.drawable.ic_add_white)
                         .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
                 menu.add(0, MENU_RESTORE, 0,
                         getResources().getString(R.string.menu_restore_default_apn))
diff --git a/src/com/android/messaging/ui/appsettings/PerSubscriptionSettingsActivity.java b/src/com/android/messaging/ui/appsettings/PerSubscriptionSettingsActivity.java
index 7ab5dc7..18a3f47 100644
--- a/src/com/android/messaging/ui/appsettings/PerSubscriptionSettingsActivity.java
+++ b/src/com/android/messaging/ui/appsettings/PerSubscriptionSettingsActivity.java
@@ -28,10 +28,12 @@
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceScreen;
-import androidx.core.app.NavUtils;
 import android.text.TextUtils;
 import android.view.MenuItem;
 
+import androidx.appcompat.mms.MmsManager;
+import androidx.core.app.NavUtils;
+
 import com.android.messaging.Factory;
 import com.android.messaging.R;
 import com.android.messaging.datamodel.ParticipantRefresh;
@@ -159,17 +161,18 @@
             }
 
             // Access Point Names (APNs)
-            final Preference apnsPref = findPreference(getString(R.string.sms_apns_key));
+            final PreferenceScreen apnsScreen =
+                    (PreferenceScreen) findPreference(getString(R.string.sms_apns_key));
 
-            if (MmsUtils.useSystemApnTable() && !ApnDatabase.doesDatabaseExist()) {
-                // Don't remove the ability to edit the local APN prefs if this device lets us
+            if (!MmsManager.shouldUseLegacyMms()
+                    || (MmsUtils.useSystemApnTable() && !ApnDatabase.doesDatabaseExist())) {
+                // 1) Remove the ability to edit the local APN prefs if it doesn't use legacy APIs.
+                // 2) Don't remove the ability to edit the local APN prefs if this device lets us
                 // access the system APN, but we can't find the MCC/MNC in the APN table and we
                 // created the local APN table in case the MCC/MNC was in there. In other words,
                 // if the local APN table exists, let the user edit it.
-                advancedCategory.removePreference(apnsPref);
+                advancedCategory.removePreference((Preference) apnsScreen);
             } else {
-                final PreferenceScreen apnsScreen = (PreferenceScreen) findPreference(
-                        getString(R.string.sms_apns_key));
                 apnsScreen.setIntent(UIIntents.get()
                         .getApnSettingsIntent(getPreferenceScreen().getContext(), mSubId));
             }
@@ -183,7 +186,9 @@
                 autoRetrieveMmsPreference.setEnabled(false);
                 final Preference deliveryReportsPreference =
                         findPreference(getString(R.string.delivery_reports_pref_key));
-                deliveryReportsPreference.setEnabled(false);
+                if (deliveryReportsPreference != null) {
+                    deliveryReportsPreference.setEnabled(false);
+                }
             }
         }
 
diff --git a/src/com/android/messaging/ui/conversation/ConversationMessageView.java b/src/com/android/messaging/ui/conversation/ConversationMessageView.java
index 20c986d..928c215 100644
--- a/src/com/android/messaging/ui/conversation/ConversationMessageView.java
+++ b/src/com/android/messaging/ui/conversation/ConversationMessageView.java
@@ -377,6 +377,7 @@
                 // FALL THROUGH HERE
 
             case MessageData.BUGLE_STATUS_OUTGOING_COMPLETE:
+            case MessageData.BUGLE_STATUS_OUTGOING_DELIVERED:
             case MessageData.BUGLE_STATUS_INCOMING_COMPLETE:
             default:
                 if (!mData.getCanClusterWithNextMessage()) {
diff --git a/src/com/android/messaging/widget/WidgetConversationService.java b/src/com/android/messaging/widget/WidgetConversationService.java
index 4fd3934..5b8587b 100644
--- a/src/com/android/messaging/widget/WidgetConversationService.java
+++ b/src/com/android/messaging/widget/WidgetConversationService.java
@@ -330,6 +330,7 @@
                     // FALL THROUGH HERE
 
                 case MessageData.BUGLE_STATUS_OUTGOING_COMPLETE:
+                case MessageData.BUGLE_STATUS_OUTGOING_DELIVERED:
                 case MessageData.BUGLE_STATUS_INCOMING_COMPLETE:
                 default:
                     if (!message.getCanClusterWithNextMessage()) {