1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.mms.service; 18 19 import com.google.android.mms.MmsException; 20 import com.google.android.mms.pdu.GenericPdu; 21 import com.google.android.mms.pdu.PduHeaders; 22 import com.google.android.mms.pdu.PduParser; 23 import com.google.android.mms.pdu.PduPersister; 24 import com.google.android.mms.pdu.RetrieveConf; 25 import com.google.android.mms.util.SqliteWrapper; 26 27 import com.android.mms.service.exception.MmsHttpException; 28 29 import android.app.Activity; 30 import android.app.AppOpsManager; 31 import android.app.PendingIntent; 32 import android.content.ContentValues; 33 import android.content.Context; 34 import android.content.Intent; 35 import android.database.sqlite.SQLiteException; 36 import android.net.Uri; 37 import android.os.Binder; 38 import android.os.Bundle; 39 import android.os.UserHandle; 40 import android.provider.Telephony; 41 import android.telephony.TelephonyManager; 42 import android.text.TextUtils; 43 import android.util.Log; 44 45 import java.util.List; 46 47 /** 48 * Request to download an MMS 49 */ 50 public class DownloadRequest extends MmsRequest { 51 private static final String LOCATION_SELECTION = 52 Telephony.Mms.MESSAGE_TYPE + "=? AND " + Telephony.Mms.CONTENT_LOCATION + " =?"; 53 54 private final String mLocationUrl; 55 private final PendingIntent mDownloadedIntent; 56 private final Uri mContentUri; 57 58 public DownloadRequest(RequestManager manager, long subId, String locationUrl, 59 Uri contentUri, PendingIntent downloadedIntent, String creator, 60 Bundle configOverrides) { 61 super(manager, null/*messageUri*/, subId, creator, configOverrides); 62 mLocationUrl = locationUrl; 63 mDownloadedIntent = downloadedIntent; 64 mContentUri = contentUri; 65 } 66 67 @Override 68 protected byte[] doHttp(Context context, MmsNetworkManager netMgr, ApnSettings apn) 69 throws MmsHttpException { 70 return doHttpForResolvedAddresses(context, 71 netMgr, 72 mLocationUrl, 73 null/*pdu*/, 74 HttpUtils.HTTP_GET_METHOD, 75 apn); 76 } 77 78 @Override 79 protected PendingIntent getPendingIntent() { 80 return mDownloadedIntent; 81 } 82 83 @Override 84 protected int getRunningQueue() { 85 return MmsService.QUEUE_INDEX_DOWNLOAD; 86 } 87 88 @Override 89 protected void updateStatus(Context context, int result, byte[] response) { 90 if (mRequestManager.getAutoPersistingPref()) { 91 storeInboxMessage(context, result, response); 92 } 93 } 94 95 /** 96 * Transfer the received response to the caller (for download requests write to content uri) 97 * 98 * @param fillIn the intent that will be returned to the caller 99 * @param response the pdu to transfer 100 */ 101 @Override 102 protected boolean transferResponse(Intent fillIn, final byte[] response) { 103 return mRequestManager.writePduToContentUri(mContentUri, response); 104 } 105 106 private void storeInboxMessage(Context context, int result, byte[] response) { 107 if (response == null || response.length < 1) { 108 return; 109 } 110 final long identity = Binder.clearCallingIdentity(); 111 try { 112 final GenericPdu pdu = (new PduParser(response)).parse(); 113 if (pdu == null || !(pdu instanceof RetrieveConf)) { 114 Log.e(MmsService.TAG, "DownloadRequest.updateStatus: invalid parsed PDU"); 115 return; 116 } 117 // Store the downloaded message 118 final PduPersister persister = PduPersister.getPduPersister(context); 119 mMessageUri = persister.persist( 120 pdu, 121 Telephony.Mms.Inbox.CONTENT_URI, 122 true/*createThreadId*/, 123 true/*groupMmsEnabled*/, 124 null/*preOpenedFiles*/); 125 if (mMessageUri == null) { 126 Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not persist message"); 127 return; 128 } 129 // Update some of the properties of the message 130 ContentValues values = new ContentValues(5); 131 values.put(Telephony.Mms.DATE, System.currentTimeMillis() / 1000L); 132 values.put(Telephony.Mms.READ, 0); 133 values.put(Telephony.Mms.SEEN, 0); 134 if (!TextUtils.isEmpty(mCreator)) { 135 values.put(Telephony.Mms.CREATOR, mCreator); 136 } 137 values.put(Telephony.Mms.SUB_ID, mSubId); 138 if (SqliteWrapper.update( 139 context, 140 context.getContentResolver(), 141 mMessageUri, 142 values, 143 null/*where*/, 144 null/*selectionArg*/) != 1) { 145 Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not update message"); 146 } 147 // Delete the corresponding NotificationInd 148 SqliteWrapper.delete(context, 149 context.getContentResolver(), 150 Telephony.Mms.CONTENT_URI, 151 LOCATION_SELECTION, 152 new String[]{ 153 Integer.toString(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND), 154 mLocationUrl 155 } 156 ); 157 } catch (MmsException e) { 158 Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not persist message", e); 159 } catch (SQLiteException e) { 160 Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not update message", e); 161 } catch (RuntimeException e) { 162 Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not parse response", e); 163 } finally { 164 Binder.restoreCallingIdentity(identity); 165 } 166 } 167 168 protected boolean prepareForHttpRequest() { 169 return true; 170 } 171 172 /** 173 * Try downloading via the carrier app by sending intent. 174 * 175 * @param context The context 176 */ 177 public void tryDownloadingByCarrierApp(Context context) { 178 TelephonyManager telephonyManager = 179 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 180 Intent intent = new Intent(Telephony.Mms.Intents.MMS_DOWNLOAD_ACTION); 181 List<String> carrierPackages = telephonyManager.getCarrierPackageNamesForIntent( 182 intent); 183 184 if (carrierPackages == null || carrierPackages.size() != 1) { 185 mRequestManager.addRunning(this); 186 } else { 187 intent.setPackage(carrierPackages.get(0)); 188 intent.putExtra(Telephony.Mms.Intents.EXTRA_MMS_LOCATION_URL, mLocationUrl); 189 intent.putExtra(Telephony.Mms.Intents.EXTRA_MMS_CONTENT_URI, mContentUri); 190 intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); 191 context.sendOrderedBroadcastAsUser( 192 intent, 193 UserHandle.OWNER, 194 android.Manifest.permission.RECEIVE_MMS, 195 AppOpsManager.OP_RECEIVE_MMS, 196 mCarrierAppResultReceiver, 197 null/*scheduler*/, 198 Activity.RESULT_CANCELED, 199 null/*initialData*/, 200 null/*initialExtras*/); 201 } 202 } 203 204 @Override 205 protected void revokeUriPermission(Context context) { 206 context.revokeUriPermission(mContentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 207 } 208 } 209