12d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen/* 22d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * Copyright (C) 2014 The Android Open Source Project 32d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * 42d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * Licensed under the Apache License, Version 2.0 (the "License"); 52d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * you may not use this file except in compliance with the License. 62d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * You may obtain a copy of the License at 72d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * 82d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * http://www.apache.org/licenses/LICENSE-2.0 92d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * 102d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * Unless required by applicable law or agreed to in writing, software 112d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * distributed under the License is distributed on an "AS IS" BASIS, 122d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * See the License for the specific language governing permissions and 142d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * limitations under the License. 152d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen */ 162d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen 172d860e9479ac9390efeb1ddaf94217f478666a54Ye Wenpackage com.android.mms.service; 182d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen 1918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.MmsException; 2018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.pdu.DeliveryInd; 2118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.pdu.GenericPdu; 2218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.pdu.NotificationInd; 2318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.pdu.PduComposer; 2418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.pdu.PduParser; 2518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.pdu.PduPersister; 2618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.pdu.ReadOrigInd; 2718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.pdu.RetrieveConf; 2818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.pdu.SendReq; 2918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport com.google.android.mms.util.SqliteWrapper; 3018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 3149b04614ece9f1a46acc5f69141e7e2d6736a5fbYe Wenimport com.android.internal.telephony.IMms; 328c027a60c84d23672647a3775190ee3fa7655b34Ye Wenimport com.android.internal.telephony.SmsApplication; 332d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen 34b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wenimport android.app.Activity; 352d860e9479ac9390efeb1ddaf94217f478666a54Ye Wenimport android.app.PendingIntent; 362d860e9479ac9390efeb1ddaf94217f478666a54Ye Wenimport android.app.Service; 37b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport android.content.ContentResolver; 3818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport android.content.ContentUris; 3918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport android.content.ContentValues; 40b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport android.content.Context; 412d860e9479ac9390efeb1ddaf94217f478666a54Ye Wenimport android.content.Intent; 428c027a60c84d23672647a3775190ee3fa7655b34Ye Wenimport android.content.SharedPreferences; 4318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport android.database.Cursor; 4418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport android.database.sqlite.SQLiteException; 4518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport android.net.Uri; 4618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport android.os.Binder; 478a79dc0267f021de60f321e621691370b79cb81aShri Bordeimport android.os.Bundle; 48c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenimport android.os.Handler; 49c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenimport android.os.HandlerThread; 502d860e9479ac9390efeb1ddaf94217f478666a54Ye Wenimport android.os.IBinder; 51c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenimport android.os.Looper; 52b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport android.os.ParcelFileDescriptor; 530527dc4edc5e8be417edc74031a209070a28547aYe Wenimport android.os.Process; 54c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wenimport android.os.Message; 552d860e9479ac9390efeb1ddaf94217f478666a54Ye Wenimport android.os.RemoteException; 5618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport android.provider.Telephony; 5718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport android.telephony.SmsManager; 5818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wenimport android.text.TextUtils; 592d860e9479ac9390efeb1ddaf94217f478666a54Ye Wenimport android.util.Log; 602d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen 61b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport java.io.IOException; 62b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport java.util.Arrays; 63b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport java.util.concurrent.Callable; 64b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wenimport java.util.concurrent.ConcurrentHashMap; 65b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport java.util.concurrent.ExecutorService; 66b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport java.util.concurrent.Executors; 67b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport java.util.concurrent.Future; 68b83f2faa04dc275b6779644308384459ffcff63fJulian Odellimport java.util.concurrent.TimeUnit; 69b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen 702d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen/** 712d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen * System service to process MMS API requests 722d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen */ 73b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wenpublic class MmsService extends Service implements MmsRequest.RequestManager { 74c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen public static final String TAG = "MmsService"; 75b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen 76b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen public static final int QUEUE_INDEX_SEND = 0; 77b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen public static final int QUEUE_INDEX_DOWNLOAD = 1; 78b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen 798c027a60c84d23672647a3775190ee3fa7655b34Ye Wen private static final String SHARED_PREFERENCES_NAME = "mmspref"; 808c027a60c84d23672647a3775190ee3fa7655b34Ye Wen private static final String PREF_AUTO_PERSISTING = "autopersisting"; 818c027a60c84d23672647a3775190ee3fa7655b34Ye Wen 82b83f2faa04dc275b6779644308384459ffcff63fJulian Odell // Maximum time to spend waiting to read data from a content provider before failing with error. 83b83f2faa04dc275b6779644308384459ffcff63fJulian Odell private static final int TASK_TIMEOUT_MS = 30 * 1000; 84b83f2faa04dc275b6779644308384459ffcff63fJulian Odell // Maximum size of MMS service supports - used on occassions when MMS messages are processed 85b83f2faa04dc275b6779644308384459ffcff63fJulian Odell // in a carrier independent manner (for example for imports and drafts) and the carrier 86b83f2faa04dc275b6779644308384459ffcff63fJulian Odell // specific size limit should not be used (as it could be lower on some carriers). 87b83f2faa04dc275b6779644308384459ffcff63fJulian Odell private static final int MAX_MMS_FILE_SIZE = 8 * 1024 * 1024; 88b83f2faa04dc275b6779644308384459ffcff63fJulian Odell 89b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen // Pending requests that are currently executed by carrier app 90b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen // TODO: persist this in case MmsService crashes 91b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen private final ConcurrentHashMap<Integer, MmsRequest> mPendingRequests = 92b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen new ConcurrentHashMap<Integer, MmsRequest>(); 93b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen 94b83f2faa04dc275b6779644308384459ffcff63fJulian Odell private final ExecutorService mExecutor = Executors.newCachedThreadPool(); 95b83f2faa04dc275b6779644308384459ffcff63fJulian Odell 96b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen @Override 97b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen public void addPending(int key, MmsRequest request) { 98b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen mPendingRequests.put(key, request); 99b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } 100c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen 101c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen /** 102c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * A thread-based request queue for executing the MMS requests in serial order 103c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen */ 104c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen private class RequestQueue extends Handler { 105c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen public RequestQueue(Looper looper) { 106c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen super(looper); 107c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 108c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen 109c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen @Override 110c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen public void handleMessage(Message msg) { 111c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen final MmsRequest request = (MmsRequest) msg.obj; 112c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen if (request != null) { 113c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen request.execute(MmsService.this, mMmsNetworkManager); 114c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 115c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 116c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 117c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen 1180527dc4edc5e8be417edc74031a209070a28547aYe Wen private void enforceSystemUid() { 1190527dc4edc5e8be417edc74031a209070a28547aYe Wen if (Binder.getCallingUid() != Process.SYSTEM_UID) { 1200527dc4edc5e8be417edc74031a209070a28547aYe Wen throw new SecurityException("Only system can call this service"); 1210527dc4edc5e8be417edc74031a209070a28547aYe Wen } 1220527dc4edc5e8be417edc74031a209070a28547aYe Wen } 1230527dc4edc5e8be417edc74031a209070a28547aYe Wen 1242d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen private IMms.Stub mStub = new IMms.Stub() { 1252d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen @Override 126b83f2faa04dc275b6779644308384459ffcff63fJulian Odell public void sendMessage(long subId, String callingPkg, Uri contentUri, 1273e40f4c4a8c82e795a5cea235d52eacd177c0a69Ye Wen String locationUrl, Bundle configOverrides, PendingIntent sentIntent) 128b83f2faa04dc275b6779644308384459ffcff63fJulian Odell throws RemoteException { 129c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen Log.d(TAG, "sendMessage"); 1300527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 131b83f2faa04dc275b6779644308384459ffcff63fJulian Odell final SendRequest request = new SendRequest(MmsService.this, subId, contentUri, 132c984707ecf54d545a4a5809c6ce1d18bf7cee61eYe Wen null/*messageUri*/, locationUrl, sentIntent, callingPkg, configOverrides); 1338c027a60c84d23672647a3775190ee3fa7655b34Ye Wen if (SmsApplication.shouldWriteMessageForPackage(callingPkg, MmsService.this)) { 1348c027a60c84d23672647a3775190ee3fa7655b34Ye Wen // Store the message in outbox first before sending 1358c027a60c84d23672647a3775190ee3fa7655b34Ye Wen request.storeInOutbox(MmsService.this); 1368c027a60c84d23672647a3775190ee3fa7655b34Ye Wen } 137b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen // Try sending via carrier app 138b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen request.trySendingByCarrierApp(MmsService.this); 1392d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen } 1402d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen 1412d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen @Override 14218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen public void downloadMessage(long subId, String callingPkg, String locationUrl, 1433e40f4c4a8c82e795a5cea235d52eacd177c0a69Ye Wen Uri contentUri, Bundle configOverrides, 144b83f2faa04dc275b6779644308384459ffcff63fJulian Odell PendingIntent downloadedIntent) throws RemoteException { 145c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen Log.d(TAG, "downloadMessage: " + locationUrl); 1460527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 147b83f2faa04dc275b6779644308384459ffcff63fJulian Odell final DownloadRequest request = new DownloadRequest(MmsService.this, subId, 148b83f2faa04dc275b6779644308384459ffcff63fJulian Odell locationUrl, contentUri, downloadedIntent, callingPkg, configOverrides); 149b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen // Try downloading via carrier app 150b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen request.tryDownloadingByCarrierApp(MmsService.this); 151b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } 152b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen 153b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen @Override 154f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang public void updateMmsSendStatus(int messageRef, byte[] pdu, int status) { 155f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang Log.d(TAG, "updateMmsSendStatus: ref=" + messageRef 156f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang + ", pdu=" + (pdu == null ? null : pdu.length) + ", status=" + status); 1570527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 158b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen final MmsRequest request = mPendingRequests.get(messageRef); 159b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen if (request != null) { 160f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang if (status != SmsManager.MMS_ERROR_RETRY) { 161f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang // Sent completed (maybe success or fail) by carrier app, finalize the request. 162f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang request.processResult(MmsService.this, status, pdu); 163b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } else { 164b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen // Failed, try sending via carrier network 165b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen addRunning(request); 166b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } 167b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } else { 168b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen // Really wrong here: can't find the request to update 169b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen Log.e(TAG, "Failed to find the request to update send status"); 170b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } 171b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } 172b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen 173b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen @Override 174f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang public void updateMmsDownloadStatus(int messageRef, int status) { 175f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang Log.d(TAG, "updateMmsDownloadStatus: ref=" + messageRef + ", status=" + status); 1760527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 177b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen final MmsRequest request = mPendingRequests.get(messageRef); 178b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen if (request != null) { 179f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang if (status != SmsManager.MMS_ERROR_RETRY) { 180f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang // Downloaded completed (maybe success or fail) by carrier app, finalize the 181f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang // request. 182f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang request.processResult(MmsService.this, status, null/*response*/); 183b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } else { 184b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen // Failed, try downloading via the carrier network 185b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen addRunning(request); 186b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } 187b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } else { 188b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen // Really wrong here: can't find the request to update 189b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen Log.e(TAG, "Failed to find the request to update download status"); 190b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } 1912d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen } 19218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 19318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen @Override 1948a79dc0267f021de60f321e621691370b79cb81aShri Borde public Bundle getCarrierConfigValues(long subId) { 1958a79dc0267f021de60f321e621691370b79cb81aShri Borde Log.d(TAG, "getCarrierConfigValues"); 19676b0e8693a8004001663044f5188d5b9fe4203e8Tom Taylor final MmsConfig mmsConfig = MmsConfigManager.getInstance().getMmsConfigBySubId(subId); 19776b0e8693a8004001663044f5188d5b9fe4203e8Tom Taylor if (mmsConfig == null) { 1988a79dc0267f021de60f321e621691370b79cb81aShri Borde return new Bundle(); 19976b0e8693a8004001663044f5188d5b9fe4203e8Tom Taylor } 2008a79dc0267f021de60f321e621691370b79cb81aShri Borde return mmsConfig.getCarrierConfigValues(); 20118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 20218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 20318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen @Override 20418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen public Uri importTextMessage(String callingPkg, String address, int type, String text, 20518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen long timestampMillis, boolean seen, boolean read) { 20618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.d(TAG, "importTextMessage"); 2070527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 20818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return importSms(address, type, text, timestampMillis, seen, read, callingPkg); 20918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 21018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 21118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen @Override 212b83f2faa04dc275b6779644308384459ffcff63fJulian Odell public Uri importMultimediaMessage(String callingPkg, Uri contentUri, 213b83f2faa04dc275b6779644308384459ffcff63fJulian Odell String messageId, long timestampSecs, boolean seen, boolean read) { 21418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.d(TAG, "importMultimediaMessage"); 2150527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 216b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return importMms(contentUri, messageId, timestampSecs, seen, read, callingPkg); 21718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 21818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 21918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen @Override 22018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen public boolean deleteStoredMessage(String callingPkg, Uri messageUri) 22118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen throws RemoteException { 22218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.d(TAG, "deleteStoredMessage " + messageUri); 2230527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 22418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (!isSmsMmsContentUri(messageUri)) { 22518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "deleteStoredMessage: invalid message URI: " + messageUri.toString()); 22618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 22718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 228c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 229c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 230c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 23118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final long identity = Binder.clearCallingIdentity(); 23218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 23318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (getContentResolver().delete( 23418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen messageUri, null/*where*/, null/*selectionArgs*/) != 1) { 23518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "deleteStoredMessage: failed to delete"); 23618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 23718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 23818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (SQLiteException e) { 23918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "deleteStoredMessage: failed to delete", e); 24018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } finally { 24118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Binder.restoreCallingIdentity(identity); 24218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 24318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return true; 24418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 24518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 24618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen @Override 24718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen public boolean deleteStoredConversation(String callingPkg, long conversationId) 24818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen throws RemoteException { 24918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.d(TAG, "deleteStoredConversation " + conversationId); 2500527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 25118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (conversationId == -1) { 25218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "deleteStoredConversation: invalid thread id"); 25318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 25418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 25518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final Uri uri = ContentUris.withAppendedId( 25618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Telephony.Threads.CONTENT_URI, conversationId); 257c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 258c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 259c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 26018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final long identity = Binder.clearCallingIdentity(); 26118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 26218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (getContentResolver().delete(uri, null, null) != 1) { 26318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "deleteStoredConversation: failed to delete"); 26418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 26518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 26618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (SQLiteException e) { 26718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "deleteStoredConversation: failed to delete", e); 26818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } finally { 26918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Binder.restoreCallingIdentity(identity); 27018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 27118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return true; 27218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 27318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 27418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen @Override 27518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen public boolean updateStoredMessageStatus(String callingPkg, Uri messageUri, 27618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen ContentValues statusValues) throws RemoteException { 27718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.d(TAG, "updateStoredMessageStatus " + messageUri); 2780527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 27918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return updateMessageStatus(messageUri, statusValues); 28018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 28118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 28218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen @Override 2832704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen public boolean archiveStoredConversation(String callingPkg, long conversationId, 2842704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen boolean archived) throws RemoteException { 2852704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen Log.d(TAG, "archiveStoredConversation " + conversationId + " " + archived); 2862704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen if (conversationId == -1) { 2872704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen Log.e(TAG, "archiveStoredConversation: invalid thread id"); 2882704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen return false; 2892704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen } 2902704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen return archiveConversation(conversationId, archived); 2912704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen } 2922704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen 2932704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen @Override 29418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen public Uri addTextMessageDraft(String callingPkg, String address, String text) 29518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen throws RemoteException { 29618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.d(TAG, "addTextMessageDraft"); 2970527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 29818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return addSmsDraft(address, text, callingPkg); 29918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 30018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 30118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen @Override 302b83f2faa04dc275b6779644308384459ffcff63fJulian Odell public Uri addMultimediaMessageDraft(String callingPkg, Uri contentUri) 30318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen throws RemoteException { 30418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.d(TAG, "addMultimediaMessageDraft"); 3050527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 306b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return addMmsDraft(contentUri, callingPkg); 30718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 30818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 30918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen @Override 31018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen public void sendStoredMessage(long subId, String callingPkg, Uri messageUri, 3113e40f4c4a8c82e795a5cea235d52eacd177c0a69Ye Wen Bundle configOverrides, PendingIntent sentIntent) throws RemoteException { 312f6d88a72cd01ecaf9f0319249e239afc008f1ac8Cheuksan Wang throw new UnsupportedOperationException(); 31318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 3146f31811156a8aeef55011749c25d7c98d7a7a7ddShishir Agrawal 3158c027a60c84d23672647a3775190ee3fa7655b34Ye Wen @Override 3168c027a60c84d23672647a3775190ee3fa7655b34Ye Wen public void setAutoPersisting(String callingPkg, boolean enabled) throws RemoteException { 3178c027a60c84d23672647a3775190ee3fa7655b34Ye Wen Log.d(TAG, "setAutoPersisting " + enabled); 3180527dc4edc5e8be417edc74031a209070a28547aYe Wen enforceSystemUid(); 3198c027a60c84d23672647a3775190ee3fa7655b34Ye Wen final SharedPreferences preferences = getSharedPreferences( 3208c027a60c84d23672647a3775190ee3fa7655b34Ye Wen SHARED_PREFERENCES_NAME, MODE_PRIVATE); 3218c027a60c84d23672647a3775190ee3fa7655b34Ye Wen final SharedPreferences.Editor editor = preferences.edit(); 3228c027a60c84d23672647a3775190ee3fa7655b34Ye Wen editor.putBoolean(PREF_AUTO_PERSISTING, enabled); 3238c027a60c84d23672647a3775190ee3fa7655b34Ye Wen editor.apply(); 3248c027a60c84d23672647a3775190ee3fa7655b34Ye Wen } 3258c027a60c84d23672647a3775190ee3fa7655b34Ye Wen 3268c027a60c84d23672647a3775190ee3fa7655b34Ye Wen @Override 3278c027a60c84d23672647a3775190ee3fa7655b34Ye Wen public boolean getAutoPersisting() throws RemoteException { 3288c027a60c84d23672647a3775190ee3fa7655b34Ye Wen Log.d(TAG, "getAutoPersisting"); 3298c027a60c84d23672647a3775190ee3fa7655b34Ye Wen return getAutoPersistingPref(); 3308c027a60c84d23672647a3775190ee3fa7655b34Ye Wen } 3312d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen }; 3322d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen 333c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen // Request queue threads 334c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen // 0: send queue 335c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen // 1: download queue 336c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen private final RequestQueue[] mRequestQueues = new RequestQueue[2]; 337c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen 338c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen // Manages MMS connectivity related stuff 339c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen private final MmsNetworkManager mMmsNetworkManager = new MmsNetworkManager(this); 340c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen 341c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen /** 342c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * Lazy start the request queue threads 343c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * 344c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen * @param queueIndex index of the queue to start 345c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen */ 346c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen private void startRequestQueueIfNeeded(int queueIndex) { 347c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen if (queueIndex < 0 || queueIndex >= mRequestQueues.length) { 348c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen return; 349c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 350c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen synchronized (this) { 351c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen if (mRequestQueues[queueIndex] == null) { 352c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen final HandlerThread thread = 353c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen new HandlerThread("MmsService RequestQueue " + queueIndex); 354c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen thread.start(); 355c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen mRequestQueues[queueIndex] = new RequestQueue(thread.getLooper()); 356c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 357c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 358c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 359c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen 360b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen @Override 361b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen public void addRunning(MmsRequest request) { 362b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen if (request == null) { 363b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen return; 364b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen } 365b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen final int queue = request.getRunningQueue(); 366b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen startRequestQueueIfNeeded(queue); 367c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen final Message message = Message.obtain(); 368c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen message.obj = request; 369b786d3ea3daf4a91119ea06c532fe7ef5835944cYe Wen mRequestQueues[queue].sendMessage(message); 370c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 371c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen 3722d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen @Override 3732d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen public IBinder onBind(Intent intent) { 3742d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen return mStub; 3752d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen } 3762d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen 3772d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen public final IBinder asBinder() { 3782d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen return mStub; 3792d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen } 3802d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen 3812d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen @Override 3822d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen public void onCreate() { 3832d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen super.onCreate(); 384c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen Log.d(TAG, "onCreate"); 385c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen // Load mms_config 386c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen // TODO (ywen): make sure we start request queues after mms_config is loaded 38776b0e8693a8004001663044f5188d5b9fe4203e8Tom Taylor MmsConfigManager.getInstance().init(this); 388c91cc9d4a5aa12a570a3b35a12b3e34a6a9eeb51Ye Wen } 38918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 39018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen private Uri importSms(String address, int type, String text, long timestampMillis, 39118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen boolean seen, boolean read, String creator) { 39218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Uri insertUri = null; 39318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen switch (type) { 39418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen case SmsManager.SMS_TYPE_INCOMING: 39518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen insertUri = Telephony.Sms.Inbox.CONTENT_URI; 39618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 39718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen break; 39818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen case SmsManager.SMS_TYPE_OUTGOING: 39918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen insertUri = Telephony.Sms.Sent.CONTENT_URI; 40018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen break; 40118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 40218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (insertUri == null) { 40318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "importTextMessage: invalid message type for importing: " + type); 40418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 40518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 40618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final ContentValues values = new ContentValues(6); 40718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.ADDRESS, address); 40818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.DATE, timestampMillis); 40918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.SEEN, seen ? 1 : 0); 41018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.READ, read ? 1 : 0); 41118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.BODY, text); 41218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (!TextUtils.isEmpty(creator)) { 41318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.CREATOR, creator); 41418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 415c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 416c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 417c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 41818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final long identity = Binder.clearCallingIdentity(); 41918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 42018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return getContentResolver().insert(insertUri, values); 42118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (SQLiteException e) { 42218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "importTextMessage: failed to persist imported text message", e); 42318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } finally { 42418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Binder.restoreCallingIdentity(identity); 42518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 42618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 42718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 42818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 429b83f2faa04dc275b6779644308384459ffcff63fJulian Odell private Uri importMms(Uri contentUri, String messageId, long timestampSecs, 43018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen boolean seen, boolean read, String creator) { 431b83f2faa04dc275b6779644308384459ffcff63fJulian Odell byte[] pduData = readPduFromContentUri(contentUri, MAX_MMS_FILE_SIZE); 43218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (pduData == null || pduData.length < 1) { 43318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "importMessage: empty PDU"); 43418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 43518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 436c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 437c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 438c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 43918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final long identity = Binder.clearCallingIdentity(); 44018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 44118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final GenericPdu pdu = (new PduParser(pduData)).parse(); 44218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (pdu == null) { 44318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "importMessage: can't parse input PDU"); 44418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 44518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 44618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Uri insertUri = null; 44718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (pdu instanceof SendReq) { 44818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen insertUri = Telephony.Mms.Sent.CONTENT_URI; 44918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } else if (pdu instanceof RetrieveConf || 45018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen pdu instanceof NotificationInd || 45118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen pdu instanceof DeliveryInd || 45218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen pdu instanceof ReadOrigInd) { 45318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen insertUri = Telephony.Mms.Inbox.CONTENT_URI; 45418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 45518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (insertUri == null) { 45618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "importMessage; invalid MMS type: " + pdu.getClass().getCanonicalName()); 45718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 45818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 45918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final PduPersister persister = PduPersister.getPduPersister(this); 46018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final Uri uri = persister.persist( 46118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen pdu, 46218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen insertUri, 46318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen true/*createThreadId*/, 46418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen true/*groupMmsEnabled*/, 46518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen null/*preOpenedFiles*/); 46618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (uri == null) { 46718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "importMessage: failed to persist message"); 46818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 46918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 47018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final ContentValues values = new ContentValues(5); 47118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (!TextUtils.isEmpty(messageId)) { 47218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.MESSAGE_ID, messageId); 47318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 47418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (timestampSecs != -1) { 47518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.DATE, timestampSecs); 47618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 47718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.READ, seen ? 1 : 0); 47818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.SEEN, read ? 1 : 0); 47918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (!TextUtils.isEmpty(creator)) { 48018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.CREATOR, creator); 48118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 48218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (SqliteWrapper.update(this, getContentResolver(), uri, values, 48318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen null/*where*/, null/*selectionArg*/) != 1) { 48418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "importMessage: failed to update message"); 48518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 48618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return uri; 48718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (RuntimeException e) { 48818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "importMessage: failed to parse input PDU", e); 48918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (MmsException e) { 49018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "importMessage: failed to persist message", e); 49118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } finally { 49218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Binder.restoreCallingIdentity(identity); 49318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 49418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 49518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 49618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 49718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen private static boolean isSmsMmsContentUri(Uri uri) { 49818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final String uriString = uri.toString(); 49918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (!uriString.startsWith("content://sms/") && !uriString.startsWith("content://mms/")) { 50018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 50118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 50218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (ContentUris.parseId(uri) == -1) { 50318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 50418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 50518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return true; 50618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 50718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 50818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen private boolean updateMessageStatus(Uri messageUri, ContentValues statusValues) { 50918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (!isSmsMmsContentUri(messageUri)) { 51018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "updateMessageStatus: invalid messageUri: " + messageUri.toString()); 51118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 51218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 51318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (statusValues == null) { 51418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.w(TAG, "updateMessageStatus: empty values to update"); 51518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 51618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 51718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final ContentValues values = new ContentValues(); 51818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (statusValues.containsKey(SmsManager.MESSAGE_STATUS_READ)) { 51918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final Integer val = statusValues.getAsInteger(SmsManager.MESSAGE_STATUS_READ); 52018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (val != null) { 52118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen // MMS uses the same column name 52218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.READ, val); 52318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 52418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } else if (statusValues.containsKey(SmsManager.MESSAGE_STATUS_SEEN)) { 52518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final Integer val = statusValues.getAsInteger(SmsManager.MESSAGE_STATUS_SEEN); 52618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (val != null) { 52718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen // MMS uses the same column name 52818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.SEEN, val); 52918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 53018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 53118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (values.size() < 1) { 53218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.w(TAG, "updateMessageStatus: no value to update"); 53318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 53418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 535c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 536c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 537c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 53818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final long identity = Binder.clearCallingIdentity(); 53918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 54018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (getContentResolver().update( 54118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen messageUri, values, null/*where*/, null/*selectionArgs*/) != 1) { 54218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "updateMessageStatus: failed to update database"); 54318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 54418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 54518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return true; 54618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (SQLiteException e) { 54718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "updateMessageStatus: failed to update database", e); 54818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } finally { 54918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Binder.restoreCallingIdentity(identity); 55018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 55118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 55218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 55318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 5542704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen private static final String ARCHIVE_CONVERSATION_SELECTION = Telephony.Threads._ID + "=?"; 5552704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen private boolean archiveConversation(long conversationId, boolean archived) { 5562704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen final ContentValues values = new ContentValues(1); 5572704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen values.put(Telephony.Threads.ARCHIVED, archived ? 1 : 0); 558c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 559c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 560c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 5612704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen final long identity = Binder.clearCallingIdentity(); 5622704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen try { 5632704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen if (getContentResolver().update( 5642704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen Telephony.Threads.CONTENT_URI, 5652704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen values, 5662704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen ARCHIVE_CONVERSATION_SELECTION, 5672704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen new String[] { Long.toString(conversationId)}) != 1) { 5682704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen Log.e(TAG, "archiveConversation: failed to update database"); 5692704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen return false; 5702704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen } 5712704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen return true; 5722704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen } catch (SQLiteException e) { 5732704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen Log.e(TAG, "archiveConversation: failed to update database", e); 5742704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen } finally { 5752704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen Binder.restoreCallingIdentity(identity); 5762704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen } 5772704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen return false; 5782704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen } 5792704c4bf1d52cb7a5d6d77c042b9448f38d3ca3cYe Wen 58018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen private Uri addSmsDraft(String address, String text, String creator) { 58118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final ContentValues values = new ContentValues(5); 58218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.ADDRESS, address); 58318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.BODY, text); 58418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.READ, 1); 58518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Sms.SEEN, 1); 58618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (!TextUtils.isEmpty(creator)) { 58718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.CREATOR, creator); 58818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 589c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 590c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 591c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 59218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final long identity = Binder.clearCallingIdentity(); 59318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 59418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return getContentResolver().insert(Telephony.Sms.Draft.CONTENT_URI, values); 59518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (SQLiteException e) { 59618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "addSmsDraft: failed to store draft message", e); 59718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } finally { 59818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Binder.restoreCallingIdentity(identity); 59918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 60018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 60118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 60218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 603b83f2faa04dc275b6779644308384459ffcff63fJulian Odell private Uri addMmsDraft(Uri contentUri, String creator) { 604b83f2faa04dc275b6779644308384459ffcff63fJulian Odell byte[] pduData = readPduFromContentUri(contentUri, MAX_MMS_FILE_SIZE); 60518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (pduData == null || pduData.length < 1) { 60618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "addMmsDraft: empty PDU"); 60718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 60818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 609c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 610c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 611c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 61218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final long identity = Binder.clearCallingIdentity(); 61318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 61418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final GenericPdu pdu = (new PduParser(pduData)).parse(); 61518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (pdu == null) { 61618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "addMmsDraft: can't parse input PDU"); 61718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 61818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 61918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (!(pdu instanceof SendReq)) { 62018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "addMmsDraft; invalid MMS type: " + pdu.getClass().getCanonicalName()); 62118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 62218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 62318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final PduPersister persister = PduPersister.getPduPersister(this); 62418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final Uri uri = persister.persist( 62518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen pdu, 62618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Telephony.Mms.Draft.CONTENT_URI, 62718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen true/*createThreadId*/, 62818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen true/*groupMmsEnabled*/, 62918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen null/*preOpenedFiles*/); 63018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (uri == null) { 63118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "addMmsDraft: failed to persist message"); 63218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 63318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 63418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final ContentValues values = new ContentValues(3); 63518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.READ, 1); 63618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.SEEN, 1); 63718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (!TextUtils.isEmpty(creator)) { 63818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen values.put(Telephony.Mms.CREATOR, creator); 63918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 64018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (SqliteWrapper.update(this, getContentResolver(), uri, values, 64118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen null/*where*/, null/*selectionArg*/) != 1) { 64218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "addMmsDraft: failed to update message"); 64318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 64418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return uri; 64518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (RuntimeException e) { 64618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "addMmsDraft: failed to parse input PDU", e); 64718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (MmsException e) { 64818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "addMmsDraft: failed to persist message", e); 64918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } finally { 65018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Binder.restoreCallingIdentity(identity); 65118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 65218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 65318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 65418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 65518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen private boolean isFailedOrDraft(Uri messageUri) { 656c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 657c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 658c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 659c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen final long identity = Binder.clearCallingIdentity(); 66018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Cursor cursor = null; 66118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 66218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen cursor = getContentResolver().query( 66318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen messageUri, 66418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen new String[]{ Telephony.Mms.MESSAGE_BOX }, 66518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen null/*selection*/, 66618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen null/*selectionArgs*/, 66718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen null/*sortOrder*/); 66818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (cursor != null && cursor.moveToFirst()) { 66918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final int box = cursor.getInt(0); 67018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return box == Telephony.Mms.MESSAGE_BOX_DRAFTS 67118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen || box == Telephony.Mms.MESSAGE_BOX_FAILED; 67218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 67318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (SQLiteException e) { 67418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "isFailedOrDraft: query message type failed", e); 67518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } finally { 67618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (cursor != null) { 67718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen cursor.close(); 67818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 679c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen Binder.restoreCallingIdentity(identity); 68018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 68118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return false; 68218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 68318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 68418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen private byte[] loadPdu(Uri messageUri) { 685c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Clear the calling identity and query the database using the phone user id 686c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // Otherwise the AppOps check in TelephonyProvider would complain about mismatch 687c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen // between the calling uid and the package uid 688c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen final long identity = Binder.clearCallingIdentity(); 68918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 69018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final PduPersister persister = PduPersister.getPduPersister(this); 69118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final GenericPdu pdu = persister.load(messageUri); 69218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (pdu == null) { 69318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "loadPdu: failed to load PDU from " + messageUri.toString()); 69418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 69518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 69618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen final PduComposer composer = new PduComposer(this, pdu); 69718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return composer.make(); 69818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (MmsException e) { 69918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "loadPdu: failed to load PDU from " + messageUri.toString(), e); 70018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (RuntimeException e) { 70118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen Log.e(TAG, "loadPdu: failed to serialize PDU", e); 702c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen } finally { 703c0c6d5e594fc05e3790555d2470f8f05dc055ba0Ye Wen Binder.restoreCallingIdentity(identity); 70418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 70518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen return null; 70618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 70718aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen 70818aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen private void returnUnspecifiedFailure(PendingIntent pi) { 70918aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen if (pi != null) { 71018aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen try { 71118aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen pi.send(SmsManager.MMS_ERROR_UNSPECIFIED); 71218aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } catch (PendingIntent.CanceledException e) { 71318aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen // ignore 71418aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 71518aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 71618aabe2742cbaffc3c8293cfb3ce2841fe82326dYe Wen } 7178c027a60c84d23672647a3775190ee3fa7655b34Ye Wen 7188c027a60c84d23672647a3775190ee3fa7655b34Ye Wen @Override 7198c027a60c84d23672647a3775190ee3fa7655b34Ye Wen public boolean getAutoPersistingPref() { 7208c027a60c84d23672647a3775190ee3fa7655b34Ye Wen final SharedPreferences preferences = getSharedPreferences( 7218c027a60c84d23672647a3775190ee3fa7655b34Ye Wen SHARED_PREFERENCES_NAME, MODE_PRIVATE); 7228c027a60c84d23672647a3775190ee3fa7655b34Ye Wen return preferences.getBoolean(PREF_AUTO_PERSISTING, false); 7238c027a60c84d23672647a3775190ee3fa7655b34Ye Wen } 724b83f2faa04dc275b6779644308384459ffcff63fJulian Odell 725b83f2faa04dc275b6779644308384459ffcff63fJulian Odell /** 726b83f2faa04dc275b6779644308384459ffcff63fJulian Odell * Read pdu from content provider uri 727b83f2faa04dc275b6779644308384459ffcff63fJulian Odell * @param contentUri content provider uri from which to read 728b83f2faa04dc275b6779644308384459ffcff63fJulian Odell * @param maxSize maximum number of bytes to read 729b83f2faa04dc275b6779644308384459ffcff63fJulian Odell * @return pdu bytes if succeeded else null 730b83f2faa04dc275b6779644308384459ffcff63fJulian Odell */ 731b83f2faa04dc275b6779644308384459ffcff63fJulian Odell public byte[] readPduFromContentUri(final Uri contentUri, final int maxSize) { 732b83f2faa04dc275b6779644308384459ffcff63fJulian Odell Callable<byte[]> copyPduToArray = new Callable<byte[]>() { 733b83f2faa04dc275b6779644308384459ffcff63fJulian Odell public byte[] call() { 734b83f2faa04dc275b6779644308384459ffcff63fJulian Odell ParcelFileDescriptor.AutoCloseInputStream inStream = null; 735b83f2faa04dc275b6779644308384459ffcff63fJulian Odell try { 736b83f2faa04dc275b6779644308384459ffcff63fJulian Odell ContentResolver cr = MmsService.this.getContentResolver(); 737b83f2faa04dc275b6779644308384459ffcff63fJulian Odell ParcelFileDescriptor pduFd = cr.openFileDescriptor(contentUri, "r"); 738b83f2faa04dc275b6779644308384459ffcff63fJulian Odell inStream = new ParcelFileDescriptor.AutoCloseInputStream(pduFd); 739b83f2faa04dc275b6779644308384459ffcff63fJulian Odell // Request one extra byte to make sure file not bigger than maxSize 740b83f2faa04dc275b6779644308384459ffcff63fJulian Odell byte[] tempBody = new byte[maxSize+1]; 741b83f2faa04dc275b6779644308384459ffcff63fJulian Odell int bytesRead = inStream.read(tempBody, 0, maxSize+1); 742b83f2faa04dc275b6779644308384459ffcff63fJulian Odell if (bytesRead == 0) { 743b83f2faa04dc275b6779644308384459ffcff63fJulian Odell Log.e(MmsService.TAG, "MmsService.readPduFromContentUri: empty PDU"); 744b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return null; 745b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 746b83f2faa04dc275b6779644308384459ffcff63fJulian Odell if (bytesRead <= maxSize) { 747b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return Arrays.copyOf(tempBody, bytesRead); 748b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 749b83f2faa04dc275b6779644308384459ffcff63fJulian Odell Log.e(MmsService.TAG, "MmsService.readPduFromContentUri: PDU too large"); 750b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return null; 751b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } catch (IOException ex) { 752b83f2faa04dc275b6779644308384459ffcff63fJulian Odell Log.e(MmsService.TAG, 753b83f2faa04dc275b6779644308384459ffcff63fJulian Odell "MmsService.readPduFromContentUri: IO exception reading PDU", ex); 754b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return null; 755b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } finally { 756b83f2faa04dc275b6779644308384459ffcff63fJulian Odell if (inStream != null) { 757b83f2faa04dc275b6779644308384459ffcff63fJulian Odell try { 758b83f2faa04dc275b6779644308384459ffcff63fJulian Odell inStream.close(); 759b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } catch (IOException ex) { 760b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 761b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 762b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 763b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 764b83f2faa04dc275b6779644308384459ffcff63fJulian Odell }; 765b83f2faa04dc275b6779644308384459ffcff63fJulian Odell 766b83f2faa04dc275b6779644308384459ffcff63fJulian Odell Future<byte[]> pendingResult = mExecutor.submit(copyPduToArray); 767b83f2faa04dc275b6779644308384459ffcff63fJulian Odell try { 768b83f2faa04dc275b6779644308384459ffcff63fJulian Odell byte[] pdu = pendingResult.get(TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS); 769b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return pdu; 770b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } catch (Exception e) { 771b83f2faa04dc275b6779644308384459ffcff63fJulian Odell // Typically a timeout occurred - cancel task 772b83f2faa04dc275b6779644308384459ffcff63fJulian Odell pendingResult.cancel(true); 773b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 774b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return null; 775b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 776b83f2faa04dc275b6779644308384459ffcff63fJulian Odell 777b83f2faa04dc275b6779644308384459ffcff63fJulian Odell /** 778b83f2faa04dc275b6779644308384459ffcff63fJulian Odell * Write pdu bytes to content provider uri 779b83f2faa04dc275b6779644308384459ffcff63fJulian Odell * @param contentUri content provider uri to which bytes should be written 780b83f2faa04dc275b6779644308384459ffcff63fJulian Odell * @param pdu Bytes to write 781b83f2faa04dc275b6779644308384459ffcff63fJulian Odell * @return true if all bytes successfully written else false 782b83f2faa04dc275b6779644308384459ffcff63fJulian Odell */ 783b83f2faa04dc275b6779644308384459ffcff63fJulian Odell public boolean writePduToContentUri(final Uri contentUri, final byte[] pdu) { 784b83f2faa04dc275b6779644308384459ffcff63fJulian Odell Callable<Boolean> copyDownloadedPduToOutput = new Callable<Boolean>() { 785b83f2faa04dc275b6779644308384459ffcff63fJulian Odell public Boolean call() { 786b83f2faa04dc275b6779644308384459ffcff63fJulian Odell ParcelFileDescriptor.AutoCloseOutputStream outStream = null; 787b83f2faa04dc275b6779644308384459ffcff63fJulian Odell try { 788b83f2faa04dc275b6779644308384459ffcff63fJulian Odell ContentResolver cr = MmsService.this.getContentResolver(); 789b83f2faa04dc275b6779644308384459ffcff63fJulian Odell ParcelFileDescriptor pduFd = cr.openFileDescriptor(contentUri, "w"); 790b83f2faa04dc275b6779644308384459ffcff63fJulian Odell outStream = new ParcelFileDescriptor.AutoCloseOutputStream(pduFd); 791b83f2faa04dc275b6779644308384459ffcff63fJulian Odell outStream.write(pdu); 792b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return Boolean.TRUE; 793b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } catch (IOException ex) { 794b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return Boolean.FALSE; 795b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } finally { 796b83f2faa04dc275b6779644308384459ffcff63fJulian Odell if (outStream != null) { 797b83f2faa04dc275b6779644308384459ffcff63fJulian Odell try { 798b83f2faa04dc275b6779644308384459ffcff63fJulian Odell outStream.close(); 799b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } catch (IOException ex) { 800b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 801b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 802b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 803b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 804b83f2faa04dc275b6779644308384459ffcff63fJulian Odell }; 805b83f2faa04dc275b6779644308384459ffcff63fJulian Odell 806b83f2faa04dc275b6779644308384459ffcff63fJulian Odell Future<Boolean> pendingResult = mExecutor.submit(copyDownloadedPduToOutput); 807b83f2faa04dc275b6779644308384459ffcff63fJulian Odell try { 808b83f2faa04dc275b6779644308384459ffcff63fJulian Odell Boolean succeeded = pendingResult.get(TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS); 809b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return succeeded == Boolean.TRUE; 810b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } catch (Exception e) { 811b83f2faa04dc275b6779644308384459ffcff63fJulian Odell // Typically a timeout occurred - cancel task 812b83f2faa04dc275b6779644308384459ffcff63fJulian Odell pendingResult.cancel(true); 813b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 814b83f2faa04dc275b6779644308384459ffcff63fJulian Odell return false; 815b83f2faa04dc275b6779644308384459ffcff63fJulian Odell } 8162d860e9479ac9390efeb1ddaf94217f478666a54Ye Wen} 817