Home | History | Annotate | Download | only in service
      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