SmsManager.java revision 0da3bdb476086db02a1076780676b21e239c79d6
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.telephony; 18 19import android.app.PendingIntent; 20import android.os.RemoteException; 21import android.os.ServiceManager; 22import android.text.TextUtils; 23 24import com.android.internal.telephony.EncodeException; 25import com.android.internal.telephony.ISms; 26import com.android.internal.telephony.IccConstants; 27import com.android.internal.telephony.SmsRawData; 28 29import java.util.ArrayList; 30import java.util.Arrays; 31import java.util.List; 32 33/* 34 * TODO(code review): Curious question... Why are a lot of these 35 * methods not declared as static, since they do not seem to require 36 * any local object state? Assumedly this cannot be changed without 37 * interfering with the API... 38 */ 39 40/** 41 * Manages SMS operations such as sending data, text, and pdu SMS messages. 42 * Get this object by calling the static method SmsManager.getDefault(). 43 */ 44public final class SmsManager { 45 private static SmsManager sInstance; 46 47 /** 48 * Send a text based SMS. 49 * 50 * @param destinationAddress the address to send the message to 51 * @param scAddress is the service center address or null to use 52 * the current default SMSC 53 * @param text the body of the message to send 54 * @param sentIntent if not NULL this <code>PendingIntent</code> is 55 * broadcast when the message is sucessfully sent, or failed. 56 * The result code will be <code>Activity.RESULT_OK<code> for success, 57 * or one of these errors: 58 * <code>RESULT_ERROR_GENERIC_FAILURE</code> 59 * <code>RESULT_ERROR_RADIO_OFF</code> 60 * <code>RESULT_ERROR_NULL_PDU</code>. 61 * The per-application based SMS control checks sentIntent. If sentIntent 62 * is NULL the caller will be checked against all unknown applications, 63 * which cause smaller number of SMS to be sent in checking period. 64 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 65 * broadcast when the message is delivered to the recipient. The 66 * raw pdu of the status report is in the extended data ("pdu"). 67 * 68 * @throws IllegalArgumentException if destinationAddress or text are empty 69 */ 70 public void sendTextMessage( 71 String destinationAddress, String scAddress, String text, 72 PendingIntent sentIntent, PendingIntent deliveryIntent) { 73 if (TextUtils.isEmpty(destinationAddress)) { 74 throw new IllegalArgumentException("Invalid destinationAddress"); 75 } 76 77 if (TextUtils.isEmpty(text)) { 78 throw new IllegalArgumentException("Invalid message body"); 79 } 80 81 SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu( 82 scAddress, destinationAddress, text, (deliveryIntent != null)); 83 sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); 84 } 85 86 /** 87 * Divide a message text into several fragments, none bigger than 88 * the maximum SMS message size. 89 * 90 * @param text the original message. Must not be null. 91 * @return an <code>ArrayList</code> of strings that, in order, 92 * comprise the original message 93 */ 94 public ArrayList<String> divideMessage(String text) { 95 return SmsMessage.fragmentText(text); 96 } 97 98 /** 99 * Send a multi-part text based SMS. The callee should have already 100 * divided the message into correctly sized parts by calling 101 * <code>divideMessage</code>. 102 * 103 * @param destinationAddress the address to send the message to 104 * @param scAddress is the service center address or null to use 105 * the current default SMSC 106 * @param parts an <code>ArrayList</code> of strings that, in order, 107 * comprise the original message 108 * @param sentIntents if not null, an <code>ArrayList</code> of 109 * <code>PendingIntent</code>s (one for each message part) that is 110 * broadcast when the corresponding message part has been sent. 111 * The result code will be <code>Activity.RESULT_OK<code> for success, 112 * or one of these errors: 113 * <code>RESULT_ERROR_GENERIC_FAILURE</code> 114 * <code>RESULT_ERROR_RADIO_OFF</code> 115 * <code>RESULT_ERROR_NULL_PDU</code>. 116 * The per-application based SMS control checks sentIntent. If sentIntent 117 * is NULL the caller will be checked against all unknown applicaitons, 118 * which cause smaller number of SMS to be sent in checking period. 119 * @param deliveryIntents if not null, an <code>ArrayList</code> of 120 * <code>PendingIntent</code>s (one for each message part) that is 121 * broadcast when the corresponding message part has been delivered 122 * to the recipient. The raw pdu of the status report is in the 123 * extended data ("pdu"). 124 * 125 * @throws IllegalArgumentException if destinationAddress or data are empty 126 */ 127 public void sendMultipartTextMessage( 128 String destinationAddress, String scAddress, ArrayList<String> parts, 129 ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { 130 if (TextUtils.isEmpty(destinationAddress)) { 131 throw new IllegalArgumentException("Invalid destinationAddress"); 132 } 133 if (parts == null || parts.size() < 1) { 134 throw new IllegalArgumentException("Invalid message body"); 135 } 136 137 if (parts.size() > 1) { 138 try { 139 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 140 if (iccISms != null) { 141 iccISms.sendMultipartText(destinationAddress, scAddress, parts, 142 sentIntents, deliveryIntents); 143 } 144 } catch (RemoteException ex) { 145 // ignore it 146 } 147 } else { 148 PendingIntent sentIntent = null; 149 PendingIntent deliveryIntent = null; 150 if (sentIntents != null && sentIntents.size() > 0) { 151 sentIntent = sentIntents.get(0); 152 } 153 if (deliveryIntents != null && deliveryIntents.size() > 0) { 154 deliveryIntent = deliveryIntents.get(0); 155 } 156 sendTextMessage(destinationAddress, scAddress, parts.get(0), 157 sentIntent, deliveryIntent); 158 } 159 } 160 161 /** 162 * Send a data based SMS to a specific application port. 163 * 164 * @param destinationAddress the address to send the message to 165 * @param scAddress is the service center address or null to use 166 * the current default SMSC 167 * @param destinationPort the port to deliver the message to 168 * @param data the body of the message to send 169 * @param sentIntent if not NULL this <code>PendingIntent</code> is 170 * broadcast when the message is sucessfully sent, or failed. 171 * The result code will be <code>Activity.RESULT_OK<code> for success, 172 * or one of these errors: 173 * <code>RESULT_ERROR_GENERIC_FAILURE</code> 174 * <code>RESULT_ERROR_RADIO_OFF</code> 175 * <code>RESULT_ERROR_NULL_PDU</code>. 176 * The per-application based SMS control checks sentIntent. If sentIntent 177 * is NULL the caller will be checked against all unknown applicaitons, 178 * which cause smaller number of SMS to be sent in checking period. 179 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 180 * broadcast when the message is delivered to the recipient. The 181 * raw pdu of the status report is in the extended data ("pdu"). 182 * 183 * @throws IllegalArgumentException if destinationAddress or data are empty 184 */ 185 public void sendDataMessage( 186 String destinationAddress, String scAddress, short destinationPort, 187 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 188 if (TextUtils.isEmpty(destinationAddress)) { 189 throw new IllegalArgumentException("Invalid destinationAddress"); 190 } 191 192 if (data == null || data.length == 0) { 193 throw new IllegalArgumentException("Invalid message data"); 194 } 195 196 SmsMessage.SubmitPdu pdus = SmsMessage.getSubmitPdu( 197 scAddress, destinationAddress, 198 destinationPort, data, (deliveryIntent != null)); 199 sendRawPdu(pdus.encodedScAddress, pdus.encodedMessage, sentIntent, deliveryIntent); 200 } 201 202 /** 203 * Send a raw SMS PDU. 204 * A PDU is a protocol data unit. It contains the message and the 205 * associated meta information. 206 * 207 * @param smsc the SMSC to send the message through, or NULL for the 208 * default SMSC 209 * @param pdu the raw PDU to send 210 * @param sentIntent if not NULL this <code>PendingIntent</code> is 211 * broadcast when the message is successfully sent, or failed. 212 * The result code will be <code>Activity.RESULT_OK<code> for success, 213 * or one of these errors: 214 * <code>RESULT_ERROR_GENERIC_FAILURE</code> 215 * <code>RESULT_ERROR_RADIO_OFF</code> 216 * <code>RESULT_ERROR_NULL_PDU</code>. 217 * The per-application based SMS control checks sentIntent. If sentIntent 218 * is NULL the caller will be checked against all unknown applications, 219 * which cause smaller number of SMS to be sent in checking period. 220 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 221 * broadcast when the message is delivered to the recipient. The 222 * raw pdu of the status report is in the extended data ("pdu"). 223 */ 224 private void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, 225 PendingIntent deliveryIntent) { 226 try { 227 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 228 if (iccISms != null) { 229 iccISms.sendRawPdu(smsc, pdu, sentIntent, deliveryIntent); 230 } 231 } catch (RemoteException ex) { 232 // ignore it 233 } 234 } 235 236 /** 237 * Get the default instance of the SmsManager 238 * 239 * @return the default instance of the SmsManager 240 */ 241 public static SmsManager getDefault() { 242 if (sInstance == null) { 243 sInstance = new SmsManager(); 244 } 245 return sInstance; 246 } 247 248 private SmsManager() { 249 //nothing 250 } 251 252 /** 253 * Copy a raw SMS PDU to the ICC. 254 * ICC (Integrated Circuit Card) is the card of the device. 255 * For example, this can be the SIM or USIM for GSM. 256 * 257 * @param smsc the SMSC for this message, or NULL for the default SMSC 258 * @param pdu the raw PDU to store 259 * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, 260 * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) 261 * @return true for success 262 * 263 * {@hide} 264 */ 265 public boolean copyMessageToIcc(byte[] smsc, byte[] pdu, int status) { 266 boolean success = false; 267 268 try { 269 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 270 if (iccISms != null) { 271 success = iccISms.copyMessageToIccEf(status, pdu, smsc); 272 } 273 } catch (RemoteException ex) { 274 // ignore it 275 } 276 277 return success; 278 } 279 280 /** 281 * Delete the specified message from the ICC. 282 * ICC (Integrated Circuit Card) is the card of the device. 283 * For example, this can be the SIM or USIM for GSM. 284 * 285 * @param messageIndex is the record index of the message on ICC 286 * @return true for success 287 * 288 * {@hide} 289 */ 290 public boolean 291 deleteMessageFromIcc(int messageIndex) { 292 boolean success = false; 293 byte[] pdu = new byte[IccConstants.SMS_RECORD_LENGTH-1]; 294 Arrays.fill(pdu, (byte)0xff); 295 296 try { 297 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 298 if (iccISms != null) { 299 success = iccISms.updateMessageOnIccEf(messageIndex, STATUS_ON_ICC_FREE, pdu); 300 } 301 } catch (RemoteException ex) { 302 // ignore it 303 } 304 305 return success; 306 } 307 308 /** 309 * Update the specified message on the ICC. 310 * ICC (Integrated Circuit Card) is the card of the device. 311 * For example, this can be the SIM or USIM for GSM. 312 * 313 * @param messageIndex record index of message to update 314 * @param newStatus new message status (STATUS_ON_ICC_READ, 315 * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, 316 * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) 317 * @param pdu the raw PDU to store 318 * @return true for success 319 * 320 * {@hide} 321 */ 322 public boolean updateMessageOnIcc(int messageIndex, int newStatus, byte[] pdu) { 323 boolean success = false; 324 325 try { 326 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 327 if (iccISms != null) { 328 success = iccISms.updateMessageOnIccEf(messageIndex, newStatus, pdu); 329 } 330 } catch (RemoteException ex) { 331 // ignore it 332 } 333 334 return success; 335 } 336 337 /** 338 * Retrieves all messages currently stored on ICC. 339 * ICC (Integrated Circuit Card) is the card of the device. 340 * For example, this can be the SIM or USIM for GSM. 341 * 342 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects 343 * 344 * {@hide} 345 */ 346 public ArrayList<SmsMessage> getAllMessagesFromIcc() { 347 List<SmsRawData> records = null; 348 349 try { 350 ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms")); 351 if (iccISms != null) { 352 records = iccISms.getAllMessagesFromIccEf(); 353 } 354 } catch (RemoteException ex) { 355 // ignore it 356 } 357 358 return createMessageListFromRawRecords(records); 359 } 360 361 /** 362 * Create a list of <code>SmsMessage</code>s from a list of RawSmsData 363 * records returned by <code>getAllMessagesFromIcc()</code> 364 * 365 * @param records SMS EF records, returned by 366 * <code>getAllMessagesFromIcc</code> 367 * @return <code>ArrayList</code> of <code>SmsMessage</code> objects. 368 */ 369 private ArrayList<SmsMessage> createMessageListFromRawRecords(List<SmsRawData> records) { 370 ArrayList<SmsMessage> messages = new ArrayList<SmsMessage>(); 371 if (records != null) { 372 int count = records.size(); 373 for (int i = 0; i < count; i++) { 374 SmsRawData data = records.get(i); 375 // List contains all records, including "free" records (null) 376 if (data != null) { 377 SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes()); 378 messages.add(sms); 379 } 380 } 381 } 382 return messages; 383 } 384 385 // see SmsMessage.getStatusOnIcc 386 387 /** Free space (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 388 static public final int STATUS_ON_ICC_FREE = 0; 389 390 /** Received and read (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 391 static public final int STATUS_ON_ICC_READ = 1; 392 393 /** Received and unread (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 394 static public final int STATUS_ON_ICC_UNREAD = 3; 395 396 /** Stored and sent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 397 static public final int STATUS_ON_ICC_SENT = 5; 398 399 /** Stored and unsent (TS 51.011 10.5.3 / 3GPP2 C.S0023 3.4.27). */ 400 static public final int STATUS_ON_ICC_UNSENT = 7; 401 402 // SMS send failure result codes 403 404 /** Generic failure cause */ 405 static public final int RESULT_ERROR_GENERIC_FAILURE = 1; 406 /** Failed because radio was explicitly turned off */ 407 static public final int RESULT_ERROR_RADIO_OFF = 2; 408 /** Failed because no pdu provided */ 409 static public final int RESULT_ERROR_NULL_PDU = 3; 410 /** Failed because service is currently unavailable */ 411 static public final int RESULT_ERROR_NO_SERVICE = 4; 412} 413