Merge "To prevent MMS get the incorrect resource on MSIM device" into qt-dev
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d303ba5..e033528 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -29,6 +29,8 @@
     <uses-permission android:name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/>
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
 
+    <protected-broadcast android:name="android.settings.ENABLE_MMS_DATA_REQUEST"/>
+
     <application android:label="MmsService"
                  android:process="com.android.phone"
                  android:usesCleartextTraffic="true">
diff --git a/src/com/android/mms/service/MmsHttpClient.java b/src/com/android/mms/service/MmsHttpClient.java
index 7ca012c..ea2f3d7 100644
--- a/src/com/android/mms/service/MmsHttpClient.java
+++ b/src/com/android/mms/service/MmsHttpClient.java
@@ -137,6 +137,8 @@
             connection.setDoInput(true);
             connection.setConnectTimeout(
                     mmsConfig.getInt(SmsManager.MMS_CONFIG_HTTP_SOCKET_TIMEOUT));
+            connection.setReadTimeout(
+                    mmsConfig.getInt(SmsManager.MMS_CONFIG_HTTP_SOCKET_TIMEOUT));
             // ------- COMMON HEADERS ---------
             // Header: Accept
             connection.setRequestProperty(HEADER_ACCEPT, HEADER_VALUE_ACCEPT);
diff --git a/src/com/android/mms/service/MmsService.java b/src/com/android/mms/service/MmsService.java
index ff937ea..b255234 100644
--- a/src/com/android/mms/service/MmsService.java
+++ b/src/com/android/mms/service/MmsService.java
@@ -33,15 +33,19 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.provider.Telephony;
 import android.service.carrier.CarrierMessagingService;
 import android.telephony.SmsManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.data.ApnSetting;
 import android.text.TextUtils;
 import android.util.SparseArray;
 
 import com.android.internal.telephony.IMms;
+
 import com.google.android.mms.MmsException;
 import com.google.android.mms.pdu.DeliveryInd;
 import com.google.android.mms.pdu.GenericPdu;
@@ -100,6 +104,10 @@
     // A cache of MmsNetworkManager for SIMs
     private final SparseArray<MmsNetworkManager> mNetworkManagerCache = new SparseArray<>();
 
+    // The default TelephonyManager and a cache of TelephonyManagers for individual subscriptions
+    private TelephonyManager mDefaultTelephonyManager;
+    private final SparseArray<TelephonyManager> mTelephonyManagerCache = new SparseArray<>();
+
     // The current SIM ID for the running requests. Only one SIM can send/download MMS at a time.
     private int mCurrentSubId;
     // The current running MmsRequest count.
@@ -121,6 +129,23 @@
         }
     }
 
+    private TelephonyManager getTelephonyManager(int subId) {
+        synchronized (mTelephonyManagerCache) {
+            if (mDefaultTelephonyManager == null) {
+                mDefaultTelephonyManager = (TelephonyManager) this.getSystemService(
+                        Context.TELEPHONY_SERVICE);
+            }
+
+            TelephonyManager subSpecificTelephonyManager = mTelephonyManagerCache.get(subId);
+            if (subSpecificTelephonyManager == null) {
+                subSpecificTelephonyManager = mDefaultTelephonyManager.createForSubscriptionId(
+                        subId);
+                mTelephonyManagerCache.put(subId, subSpecificTelephonyManager);
+            }
+            return subSpecificTelephonyManager;
+        }
+    }
+
     private void enforceSystemUid() {
         if (Binder.getCallingUid() != Process.SYSTEM_UID) {
             throw new SecurityException("Only system can call this service");
@@ -140,8 +165,7 @@
     @Nullable
     private String getCarrierMessagingServicePackageIfExists(int subId) {
         Intent intent = new Intent(CarrierMessagingService.SERVICE_INTERFACE);
-        TelephonyManager telephonyManager =
-                (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
+        TelephonyManager telephonyManager = getTelephonyManager(subId);
         List<String> carrierPackages = telephonyManager.getCarrierPackageNamesForIntentAndPhone(
                 intent, SubscriptionManager.getPhoneId(subId));
 
@@ -155,8 +179,7 @@
     private IMms.Stub mStub = new IMms.Stub() {
         @Override
         public void sendMessage(int subId, String callingPkg, Uri contentUri,
-                String locationUrl, Bundle configOverrides, PendingIntent sentIntent)
-                        throws RemoteException {
+                String locationUrl, Bundle configOverrides, PendingIntent sentIntent) {
             LogUtil.d("sendMessage");
             enforceSystemUid();
 
@@ -169,6 +192,15 @@
                 return;
             }
 
+            // Make sure subId has MMS data
+            if (!getTelephonyManager(subId).isDataEnabledForApn(ApnSetting.TYPE_MMS)) {
+                LogUtil.w("Subscription with id: " + subId
+                        + " cannot send MMS, data connection is not available");
+                sendSettingsIntentForFailedMms(/*isIncoming=*/ false, subId);
+                sendErrorInPendingIntent(sentIntent);
+                return;
+            }
+
             final SendRequest request = new SendRequest(MmsService.this, subId, contentUri,
                     locationUrl, sentIntent, callingPkg, configOverrides, MmsService.this);
 
@@ -186,13 +218,22 @@
         @Override
         public void downloadMessage(int subId, String callingPkg, String locationUrl,
                 Uri contentUri, Bundle configOverrides,
-                PendingIntent downloadedIntent) throws RemoteException {
+                PendingIntent downloadedIntent) {
             LogUtil.d("downloadMessage: " + MmsHttpClient.redactUrlForNonVerbose(locationUrl));
             enforceSystemUid();
 
             // Make sure the subId is correct
             subId = checkSubId(subId);
 
+            // Make sure subId has MMS data
+            if (!getTelephonyManager(subId).isDataEnabledForApn(ApnSetting.TYPE_MMS)) {
+                LogUtil.w("Subscription with id: " + subId
+                        + " cannot download MMS, data connection is not available");
+                sendSettingsIntentForFailedMms(/*isIncoming=*/ true, subId);
+                sendErrorInPendingIntent(downloadedIntent);
+                return;
+            }
+
             // If the subId is no longer active it could be caused by
             // an MVNO using multiple subIds, so we should try to
             // download anyway.
@@ -399,6 +440,19 @@
         }
     }
 
+    private void sendSettingsIntentForFailedMms(boolean isIncoming, int subId) {
+        Intent intent = new Intent(Settings.ACTION_ENABLE_MMS_DATA_REQUEST);
+
+        intent.putExtra(Settings.EXTRA_ENABLE_MMS_DATA_REQUEST_REASON,
+                isIncoming ? Settings.ENABLE_MMS_DATA_REQUEST_REASON_INCOMING_MMS
+                        : Settings.ENABLE_MMS_DATA_REQUEST_REASON_OUTGOING_MMS);
+
+        intent.putExtra(Settings.EXTRA_SUB_ID, subId);
+
+        this.sendBroadcastAsUser(intent, UserHandle.SYSTEM,
+                android.Manifest.permission.NETWORK_SETTINGS);
+    }
+
     private void addToRunningRequestQueueSynchronized(final MmsRequest request) {
         LogUtil.d("Add request to running queue for subId " + request.getSubId());
         // Update current state of running requests
@@ -648,6 +702,7 @@
     }
 
     private static final String ARCHIVE_CONVERSATION_SELECTION = Telephony.Threads._ID + "=?";
+
     private boolean archiveConversation(long conversationId, boolean archived) {
         final ContentValues values = new ContentValues(1);
         values.put(Telephony.Threads.ARCHIVED, archived ? 1 : 0);
@@ -660,7 +715,7 @@
                     Telephony.Threads.CONTENT_URI,
                     values,
                     ARCHIVE_CONVERSATION_SELECTION,
-                    new String[] { Long.toString(conversationId)}) != 1) {
+                    new String[] {Long.toString(conversationId)}) != 1) {
                 LogUtil.e("archiveConversation: failed to update database");
                 return false;
             }
@@ -782,8 +837,9 @@
 
     /**
      * Read pdu from content provider uri
+     *
      * @param contentUri content provider uri from which to read
-     * @param maxSize maximum number of bytes to read
+     * @param maxSize    maximum number of bytes to read
      * @return pdu bytes if succeeded else null
      */
     public byte[] readPduFromContentUri(final Uri contentUri, final int maxSize) {
@@ -798,8 +854,8 @@
                     ParcelFileDescriptor pduFd = cr.openFileDescriptor(contentUri, "r");
                     inStream = new ParcelFileDescriptor.AutoCloseInputStream(pduFd);
                     // Request one extra byte to make sure file not bigger than maxSize
-                    byte[] tempBody = new byte[maxSize+1];
-                    int bytesRead = inStream.read(tempBody, 0, maxSize+1);
+                    byte[] tempBody = new byte[maxSize + 1];
+                    int bytesRead = inStream.read(tempBody, 0, maxSize + 1);
                     if (bytesRead == 0) {
                         LogUtil.e("Read empty PDU");
                         return null;
@@ -835,8 +891,9 @@
 
     /**
      * Write pdu bytes to content provider uri
+     *
      * @param contentUri content provider uri to which bytes should be written
-     * @param pdu Bytes to write
+     * @param pdu        Bytes to write
      * @return true if all bytes successfully written else false
      */
     public boolean writePduToContentUri(final Uri contentUri, final byte[] pdu) {