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