/* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.mms.service; import com.google.android.mms.MmsException; import com.google.android.mms.pdu.GenericPdu; import com.google.android.mms.pdu.PduHeaders; import com.google.android.mms.pdu.PduParser; import com.google.android.mms.pdu.PduPersister; import com.google.android.mms.pdu.RetrieveConf; import com.google.android.mms.util.SqliteWrapper; import com.android.mms.service.exception.MmsHttpException; import android.app.Activity; import android.app.AppOpsManager; import android.app.PendingIntent; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.sqlite.SQLiteException; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.UserHandle; import android.provider.Telephony; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; import java.util.List; /** * Request to download an MMS */ public class DownloadRequest extends MmsRequest { private static final String LOCATION_SELECTION = Telephony.Mms.MESSAGE_TYPE + "=? AND " + Telephony.Mms.CONTENT_LOCATION + " =?"; private final String mLocationUrl; private final PendingIntent mDownloadedIntent; private final Uri mContentUri; public DownloadRequest(RequestManager manager, long subId, String locationUrl, Uri contentUri, PendingIntent downloadedIntent, String creator, Bundle configOverrides) { super(manager, null/*messageUri*/, subId, creator, configOverrides); mLocationUrl = locationUrl; mDownloadedIntent = downloadedIntent; mContentUri = contentUri; } @Override protected byte[] doHttp(Context context, MmsNetworkManager netMgr, ApnSettings apn) throws MmsHttpException { return doHttpForResolvedAddresses(context, netMgr, mLocationUrl, null/*pdu*/, HttpUtils.HTTP_GET_METHOD, apn); } @Override protected PendingIntent getPendingIntent() { return mDownloadedIntent; } @Override protected int getRunningQueue() { return MmsService.QUEUE_INDEX_DOWNLOAD; } @Override protected void updateStatus(Context context, int result, byte[] response) { if (mRequestManager.getAutoPersistingPref()) { storeInboxMessage(context, result, response); } } /** * Transfer the received response to the caller (for download requests write to content uri) * * @param fillIn the intent that will be returned to the caller * @param response the pdu to transfer */ @Override protected boolean transferResponse(Intent fillIn, final byte[] response) { return mRequestManager.writePduToContentUri(mContentUri, response); } private void storeInboxMessage(Context context, int result, byte[] response) { if (response == null || response.length < 1) { return; } final long identity = Binder.clearCallingIdentity(); try { final GenericPdu pdu = (new PduParser(response)).parse(); if (pdu == null || !(pdu instanceof RetrieveConf)) { Log.e(MmsService.TAG, "DownloadRequest.updateStatus: invalid parsed PDU"); return; } // Store the downloaded message final PduPersister persister = PduPersister.getPduPersister(context); mMessageUri = persister.persist( pdu, Telephony.Mms.Inbox.CONTENT_URI, true/*createThreadId*/, true/*groupMmsEnabled*/, null/*preOpenedFiles*/); if (mMessageUri == null) { Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not persist message"); return; } // Update some of the properties of the message ContentValues values = new ContentValues(5); values.put(Telephony.Mms.DATE, System.currentTimeMillis() / 1000L); values.put(Telephony.Mms.READ, 0); values.put(Telephony.Mms.SEEN, 0); if (!TextUtils.isEmpty(mCreator)) { values.put(Telephony.Mms.CREATOR, mCreator); } values.put(Telephony.Mms.SUB_ID, mSubId); if (SqliteWrapper.update( context, context.getContentResolver(), mMessageUri, values, null/*where*/, null/*selectionArg*/) != 1) { Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not update message"); } // Delete the corresponding NotificationInd SqliteWrapper.delete(context, context.getContentResolver(), Telephony.Mms.CONTENT_URI, LOCATION_SELECTION, new String[]{ Integer.toString(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND), mLocationUrl } ); } catch (MmsException e) { Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not persist message", e); } catch (SQLiteException e) { Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not update message", e); } catch (RuntimeException e) { Log.e(MmsService.TAG, "DownloadRequest.updateStatus: can not parse response", e); } finally { Binder.restoreCallingIdentity(identity); } } protected boolean prepareForHttpRequest() { return true; } /** * Try downloading via the carrier app by sending intent. * * @param context The context */ public void tryDownloadingByCarrierApp(Context context) { TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); Intent intent = new Intent(Telephony.Mms.Intents.MMS_DOWNLOAD_ACTION); List carrierPackages = telephonyManager.getCarrierPackageNamesForIntent( intent); if (carrierPackages == null || carrierPackages.size() != 1) { mRequestManager.addRunning(this); } else { intent.setPackage(carrierPackages.get(0)); intent.putExtra(Telephony.Mms.Intents.EXTRA_MMS_LOCATION_URL, mLocationUrl); intent.putExtra(Telephony.Mms.Intents.EXTRA_MMS_CONTENT_URI, mContentUri); intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT); context.sendOrderedBroadcastAsUser( intent, UserHandle.OWNER, android.Manifest.permission.RECEIVE_MMS, AppOpsManager.OP_RECEIVE_MMS, mCarrierAppResultReceiver, null/*scheduler*/, Activity.RESULT_CANCELED, null/*initialData*/, null/*initialExtras*/); } } @Override protected void revokeUriPermission(Context context) { context.revokeUriPermission(mContentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } }