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 DownloadRequest(RequestManager manager, long subId, String locationUrl, Uri contentUri, PendingIntent downloadedIntent, String creator, Bundle configOverrides)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 doHttp(Context context, MmsNetworkManager netMgr, ApnSettings apn)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 getPendingIntent()79 protected PendingIntent getPendingIntent() { 80 return mDownloadedIntent; 81 } 82 83 @Override getRunningQueue()84 protected int getRunningQueue() { 85 return MmsService.QUEUE_INDEX_DOWNLOAD; 86 } 87 88 @Override updateStatus(Context context, int result, byte[] response)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 transferResponse(Intent fillIn, final byte[] response)102 protected boolean transferResponse(Intent fillIn, final byte[] response) { 103 return mRequestManager.writePduToContentUri(mContentUri, response); 104 } 105 storeInboxMessage(Context context, int result, byte[] response)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 prepareForHttpRequest()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 */ tryDownloadingByCarrierApp(Context context)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 revokeUriPermission(Context context)205 protected void revokeUriPermission(Context context) { 206 context.revokeUriPermission(mContentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 207 } 208 } 209