1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/* 2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project 3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License"); 5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License. 6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at 7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * http://www.apache.org/licenses/LICENSE-2.0 9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software 11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS, 12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and 14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License. 15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage android.support.v7.mms; 18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.app.PendingIntent; 20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.ContentResolver; 21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context; 22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Intent; 23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.net.Uri; 24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Bundle; 25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Parcel; 26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.ParcelFileDescriptor; 27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Parcelable; 28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.telephony.SmsManager; 29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.text.TextUtils; 30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.util.Log; 31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.io.IOException; 33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.concurrent.Callable; 34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.concurrent.Future; 35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.concurrent.TimeUnit; 36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/** 38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Request to send an MMS 39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddclass SendRequest extends MmsRequest { 41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Max send response PDU size in bytes (exceeding this may cause problem with 42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // system intent delivery). 43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static final int MAX_SEND_RESPONSE_SIZE = 1000 * 1024; 44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private byte[] mPduData; 46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd SendRequest(final String locationUrl, final Uri pduUri, final PendingIntent sentIntent) { 48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super(locationUrl, pduUri, sentIntent); 49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected boolean loadRequest(final Context context, final Bundle mmsConfig) { 53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mPduData = readPduFromContentUri( 54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd context, 55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mPduUri, 56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mmsConfig.getInt( 57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_SIZE, 58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd CarrierConfigValuesLoader.CONFIG_MAX_MESSAGE_SIZE_DEFAULT)); 59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return (mPduData != null); 60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected boolean transferResponse(final Context context, final Intent fillIn, 64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final byte[] response) { 65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // SendConf pdus are always small and can be included in the intent 66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (response != null && fillIn != null) { 67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (response.length > MAX_SEND_RESPONSE_SIZE) { 68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // If the response PDU is too large, it won't be able to fit in 69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // the PendingIntent to be transferred via system IPC. 70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return false; 71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd fillIn.putExtra(SmsManager.EXTRA_MMS_DATA, response); 73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return true; 75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected byte[] doHttp(Context context, MmsNetworkManager netMgr, ApnSettingsLoader.Apn apn, 79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Bundle mmsConfig, String userAgent, String uaProfUrl) throws MmsHttpException { 80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final MmsHttpClient httpClient = netMgr.getHttpClient(); 81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return httpClient.execute(getHttpRequestUrl(apn), mPduData, MmsHttpClient.METHOD_POST, 82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd !TextUtils.isEmpty(apn.getMmsProxy()), apn.getMmsProxy(), apn.getMmsProxyPort(), 83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd mmsConfig, userAgent, uaProfUrl); 84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd @Override 87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd protected String getHttpRequestUrl(final ApnSettingsLoader.Apn apn) { 88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return !TextUtils.isEmpty(mLocationUrl) ? mLocationUrl : apn.getMmsc(); 89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Read pdu from content provider uri 93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param contentUri content provider uri from which to read 95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param maxSize maximum number of bytes to read 96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return pdu bytes if succeeded else null 97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public byte[] readPduFromContentUri(final Context context, final Uri contentUri, 99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int maxSize) { 100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (contentUri == null) { 101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Callable<byte[]> copyPduToArray = new Callable<byte[]>() { 104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public byte[] call() { 105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd ParcelFileDescriptor.AutoCloseInputStream inStream = null; 106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ContentResolver cr = context.getContentResolver(); 108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ParcelFileDescriptor pduFd = cr.openFileDescriptor(contentUri, "r"); 109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd inStream = new ParcelFileDescriptor.AutoCloseInputStream(pduFd); 110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Request one extra byte to make sure file not bigger than maxSize 111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final byte[] readBuf = new byte[maxSize+1]; 112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int bytesRead = inStream.read(readBuf, 0, maxSize+1); 113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (bytesRead <= 0) { 114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Log.e(MmsService.TAG, "Reading PDU from sender: empty PDU"); 115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (bytesRead > maxSize) { 118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Log.e(MmsService.TAG, "Reading PDU from sender: PDU too large"); 119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Copy and return the exact length of bytes 122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final byte[] result = new byte[bytesRead]; 123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd System.arraycopy(readBuf, 0, result, 0, bytesRead); 124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return result; 125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (IOException e) { 126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Log.e(MmsService.TAG, "Reading PDU from sender: IO exception", e); 127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } finally { 129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (inStream != null) { 130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd inStream.close(); 132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (IOException ex) { 133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Ignore 134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }; 139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Future<byte[]> pendingResult = mPduTransferExecutor.submit(copyPduToArray); 140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd try { 141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return pendingResult.get(TASK_TIMEOUT_MS, TimeUnit.MILLISECONDS); 142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } catch (Exception e) { 143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Typically a timeout occurred - cancel task 144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd pendingResult.cancel(true); 145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static final Parcelable.Creator<SendRequest> CREATOR 150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd = new Parcelable.Creator<SendRequest>() { 151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public SendRequest createFromParcel(Parcel in) { 152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return new SendRequest(in); 153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public SendRequest[] newArray(int size) { 156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return new SendRequest[size]; 157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }; 159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private SendRequest(Parcel in) { 161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd super(in); 162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd} 164