NotificationTransaction.java revision 512681a5702e1ba6df0b7298c7737598a4e9aa8e
1/* 2 * Copyright (C) 2007-2008 Esmertec AG. 3 * Copyright (C) 2007-2008 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.mms.transaction; 19 20import static com.android.mms.transaction.TransactionState.FAILED; 21import static com.android.mms.transaction.TransactionState.INITIALIZED; 22import static com.android.mms.transaction.TransactionState.SUCCESS; 23import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF; 24import static com.google.android.mms.pdu.PduHeaders.STATUS_DEFERRED; 25import static com.google.android.mms.pdu.PduHeaders.STATUS_RETRIEVED; 26import static com.google.android.mms.pdu.PduHeaders.STATUS_UNRECOGNIZED; 27 28import com.android.mms.MmsConfig; 29import com.android.mms.util.DownloadManager; 30import com.android.mms.util.Recycler; 31import com.google.android.mms.MmsException; 32import com.google.android.mms.pdu.GenericPdu; 33import com.google.android.mms.pdu.NotificationInd; 34import com.google.android.mms.pdu.NotifyRespInd; 35import com.google.android.mms.pdu.PduComposer; 36import com.google.android.mms.pdu.PduHeaders; 37import com.google.android.mms.pdu.PduParser; 38import com.google.android.mms.pdu.PduPersister; 39import com.google.android.mms.util.SqliteWrapper; 40 41import android.content.Context; 42import android.database.Cursor; 43import android.net.Uri; 44import android.provider.Telephony.Mms; 45import android.provider.Telephony.Mms.Inbox; 46import android.telephony.TelephonyManager; 47import android.util.Config; 48import android.util.Log; 49 50import java.io.IOException; 51 52/** 53 * The NotificationTransaction is responsible for handling multimedia 54 * message notifications (M-Notification.ind). It: 55 * 56 * <ul> 57 * <li>Composes the notification response (M-NotifyResp.ind). 58 * <li>Sends the notification response to the MMSC server. 59 * <li>Stores the notification indication. 60 * <li>Notifies the TransactionService about succesful completion. 61 * </ul> 62 * 63 * NOTE: This MMS client handles all notifications with a <b>deferred 64 * retrieval</b> response. The transaction service, upon succesful 65 * completion of this transaction, will trigger a retrieve transaction 66 * in case the client is in immediate retrieve mode. 67 */ 68public class NotificationTransaction extends Transaction implements Runnable { 69 private static final String TAG = "NotificationTransaction"; 70 private static final boolean DEBUG = false; 71 private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV; 72 73 private Uri mUri; 74 private NotificationInd mNotificationInd; 75 private String mContentLocation; 76 77 public NotificationTransaction( 78 Context context, int serviceId, 79 TransactionSettings connectionSettings, String uriString) { 80 super(context, serviceId, connectionSettings); 81 82 mUri = Uri.parse(uriString); 83 84 try { 85 mNotificationInd = (NotificationInd) 86 PduPersister.getPduPersister(context).load(mUri); 87 } catch (MmsException e) { 88 Log.e(TAG, "Failed to load NotificationInd from: " + uriString, e); 89 throw new IllegalArgumentException(); 90 } 91 92 mId = new String(mNotificationInd.getTransactionId()); 93 mContentLocation = new String(mNotificationInd.getContentLocation()); 94 95 // Attach the transaction to the instance of RetryScheduler. 96 attach(RetryScheduler.getInstance(context)); 97 } 98 99 /** 100 * This constructor is only used for test purposes. 101 */ 102 public NotificationTransaction( 103 Context context, int serviceId, 104 TransactionSettings connectionSettings, NotificationInd ind) { 105 super(context, serviceId, connectionSettings); 106 107 try { 108 mUri = PduPersister.getPduPersister(context).persist( 109 ind, Inbox.CONTENT_URI); 110 } catch (MmsException e) { 111 Log.e(TAG, "Failed to save NotificationInd in constructor.", e); 112 throw new IllegalArgumentException(); 113 } 114 115 mNotificationInd = ind; 116 mId = new String(ind.getTransactionId()); 117 } 118 119 /* 120 * (non-Javadoc) 121 * @see com.google.android.mms.Transaction#process() 122 */ 123 @Override 124 public void process() { 125 new Thread(this).start(); 126 } 127 128 public void run() { 129 DownloadManager downloadManager = DownloadManager.getInstance(); 130 boolean autoDownload = downloadManager.isAuto(); 131 boolean dataSuspended = (TelephonyManager.getDefault().getDataState() == 132 TelephonyManager.DATA_SUSPENDED); 133 try { 134 if (LOCAL_LOGV) { 135 Log.v(TAG, "Notification transaction launched: " + this); 136 } 137 138 // By default, we set status to STATUS_DEFERRED because we 139 // should response MMSC with STATUS_DEFERRED when we cannot 140 // download a MM immediately. 141 int status = STATUS_DEFERRED; 142 // Don't try to download when data is suspended, as it will fail, so defer download 143 if (!autoDownload || dataSuspended) { 144 downloadManager.markState(mUri, DownloadManager.STATE_UNSTARTED); 145 sendNotifyRespInd(status); 146 return; 147 } 148 149 downloadManager.markState(mUri, DownloadManager.STATE_DOWNLOADING); 150 151 if (LOCAL_LOGV) { 152 Log.v(TAG, "Content-Location: " + mContentLocation); 153 } 154 155 byte[] retrieveConfData = null; 156 // We should catch exceptions here to response MMSC 157 // with STATUS_DEFERRED. 158 try { 159 retrieveConfData = getPdu(mContentLocation); 160 } catch (IOException e) { 161 mTransactionState.setState(FAILED); 162 } 163 164 if (retrieveConfData != null) { 165 GenericPdu pdu = new PduParser(retrieveConfData).parse(); 166 if ((pdu == null) || (pdu.getMessageType() != MESSAGE_TYPE_RETRIEVE_CONF)) { 167 Log.e(TAG, "Invalid M-RETRIEVE.CONF PDU."); 168 mTransactionState.setState(FAILED); 169 status = STATUS_UNRECOGNIZED; 170 } else { 171 // Save the received PDU (must be a M-RETRIEVE.CONF). 172 PduPersister p = PduPersister.getPduPersister(mContext); 173 Uri uri = p.persist(pdu, Inbox.CONTENT_URI); 174 // We have successfully downloaded the new MM. Delete the 175 // M-NotifyResp.ind from Inbox. 176 SqliteWrapper.delete(mContext, mContext.getContentResolver(), 177 mUri, null, null); 178 // Notify observers with newly received MM. 179 mUri = uri; 180 status = STATUS_RETRIEVED; 181 } 182 } 183 184 if (LOCAL_LOGV) { 185 Log.v(TAG, "status=0x" + Integer.toHexString(status)); 186 } 187 188 // Check the status and update the result state of this Transaction. 189 switch (status) { 190 case STATUS_RETRIEVED: 191 mTransactionState.setState(SUCCESS); 192 break; 193 case STATUS_DEFERRED: 194 // STATUS_DEFERRED, may be a failed immediate retrieval. 195 if (mTransactionState.getState() == INITIALIZED) { 196 mTransactionState.setState(SUCCESS); 197 } 198 break; 199 } 200 201 sendNotifyRespInd(status); 202 203 // Make sure this thread isn't over the limits in message count. 204 Recycler.getMmsRecycler().deleteOldMessagesInSameThreadAsMessage(mContext, mUri); 205 } catch (Throwable t) { 206 Log.e(TAG, Log.getStackTraceString(t)); 207 } finally { 208 mTransactionState.setContentUri(mUri); 209 if (!autoDownload || dataSuspended) { 210 // Always mark the transaction successful for deferred 211 // download since any error here doesn't make sense. 212 mTransactionState.setState(SUCCESS); 213 } 214 if (mTransactionState.getState() != SUCCESS) { 215 mTransactionState.setState(FAILED); 216 Log.e(TAG, "NotificationTransaction failed."); 217 } 218 notifyObservers(); 219 } 220 } 221 222 private void sendNotifyRespInd(int status) throws MmsException, IOException { 223 // Create the M-NotifyResp.ind 224 NotifyRespInd notifyRespInd = new NotifyRespInd( 225 PduHeaders.CURRENT_MMS_VERSION, 226 mNotificationInd.getTransactionId(), 227 status); 228 229 // Pack M-NotifyResp.ind and send it 230 if(MmsConfig.getNotifyWapMMSC()) { 231 sendPdu(new PduComposer(mContext, notifyRespInd).make(), mContentLocation); 232 } else { 233 sendPdu(new PduComposer(mContext, notifyRespInd).make()); 234 } 235 } 236 237 @Override 238 public int getType() { 239 return NOTIFICATION_TRANSACTION; 240 } 241} 242