IccSmsInterfaceManager.java revision a8467dd0c524787104b1ccdddc5e8af10ba729ed
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 com.android.internal.telephony; 18 19import android.Manifest; 20import android.app.AppOpsManager; 21import android.app.PendingIntent; 22import android.content.Context; 23import android.os.AsyncResult; 24import android.os.Binder; 25import android.os.Handler; 26import android.os.Message; 27import android.os.ServiceManager; 28import android.telephony.Rlog; 29import android.util.Log; 30 31import com.android.internal.telephony.ISms; 32import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo; 33import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo; 34import com.android.internal.telephony.uicc.IccConstants; 35import com.android.internal.telephony.uicc.IccFileHandler; 36import com.android.internal.util.HexDump; 37 38import java.util.ArrayList; 39import java.util.Arrays; 40import java.util.List; 41 42import static android.telephony.SmsManager.STATUS_ON_ICC_FREE; 43import static android.telephony.SmsManager.STATUS_ON_ICC_READ; 44import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD; 45 46/** 47 * IccSmsInterfaceManager to provide an inter-process communication to 48 * access Sms in Icc. 49 */ 50public class IccSmsInterfaceManager { 51 static final String LOG_TAG = "IccSmsInterfaceManager"; 52 static final boolean DBG = true; 53 54 protected final Object mLock = new Object(); 55 protected boolean mSuccess; 56 private List<SmsRawData> mSms; 57 58 private CellBroadcastRangeManager mCellBroadcastRangeManager = 59 new CellBroadcastRangeManager(); 60 private CdmaBroadcastRangeManager mCdmaBroadcastRangeManager = 61 new CdmaBroadcastRangeManager(); 62 63 private static final int EVENT_LOAD_DONE = 1; 64 private static final int EVENT_UPDATE_DONE = 2; 65 protected static final int EVENT_SET_BROADCAST_ACTIVATION_DONE = 3; 66 protected static final int EVENT_SET_BROADCAST_CONFIG_DONE = 4; 67 private static final int SMS_CB_CODE_SCHEME_MIN = 0; 68 private static final int SMS_CB_CODE_SCHEME_MAX = 255; 69 70 protected PhoneBase mPhone; 71 final protected Context mContext; 72 final protected AppOpsManager mAppOps; 73 protected SMSDispatcher mDispatcher; 74 75 protected Handler mHandler = new Handler() { 76 @Override 77 public void handleMessage(Message msg) { 78 AsyncResult ar; 79 80 switch (msg.what) { 81 case EVENT_UPDATE_DONE: 82 ar = (AsyncResult) msg.obj; 83 synchronized (mLock) { 84 mSuccess = (ar.exception == null); 85 mLock.notifyAll(); 86 } 87 break; 88 case EVENT_LOAD_DONE: 89 ar = (AsyncResult)msg.obj; 90 synchronized (mLock) { 91 if (ar.exception == null) { 92 mSms = buildValidRawData((ArrayList<byte[]>) ar.result); 93 //Mark SMS as read after importing it from card. 94 markMessagesAsRead((ArrayList<byte[]>) ar.result); 95 } else { 96 if (Rlog.isLoggable("SMS", Log.DEBUG)) { 97 log("Cannot load Sms records"); 98 } 99 if (mSms != null) 100 mSms.clear(); 101 } 102 mLock.notifyAll(); 103 } 104 break; 105 case EVENT_SET_BROADCAST_ACTIVATION_DONE: 106 case EVENT_SET_BROADCAST_CONFIG_DONE: 107 ar = (AsyncResult) msg.obj; 108 synchronized (mLock) { 109 mSuccess = (ar.exception == null); 110 mLock.notifyAll(); 111 } 112 break; 113 } 114 } 115 }; 116 117 protected IccSmsInterfaceManager(PhoneBase phone) { 118 mPhone = phone; 119 mContext = phone.getContext(); 120 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 121 mDispatcher = new ImsSMSDispatcher(phone, 122 phone.mSmsStorageMonitor, phone.mSmsUsageMonitor); 123 } 124 125 protected void markMessagesAsRead(ArrayList<byte[]> messages) { 126 if (messages == null) { 127 return; 128 } 129 130 //IccFileHandler can be null, if icc card is absent. 131 IccFileHandler fh = mPhone.getIccFileHandler(); 132 if (fh == null) { 133 //shouldn't really happen, as messages are marked as read, only 134 //after importing it from icc. 135 if (Rlog.isLoggable("SMS", Log.DEBUG)) { 136 log("markMessagesAsRead - aborting, no icc card present."); 137 } 138 return; 139 } 140 141 int count = messages.size(); 142 143 for (int i = 0; i < count; i++) { 144 byte[] ba = messages.get(i); 145 if (ba[0] == STATUS_ON_ICC_UNREAD) { 146 int n = ba.length; 147 byte[] nba = new byte[n - 1]; 148 System.arraycopy(ba, 1, nba, 0, n - 1); 149 byte[] record = makeSmsRecordData(STATUS_ON_ICC_READ, nba); 150 fh.updateEFLinearFixed(IccConstants.EF_SMS, i + 1, record, null, null); 151 if (Rlog.isLoggable("SMS", Log.DEBUG)) { 152 log("SMS " + (i + 1) + " marked as read"); 153 } 154 } 155 } 156 } 157 158 protected void updatePhoneObject(PhoneBase phone) { 159 mPhone = phone; 160 mDispatcher.updatePhoneObject(phone); 161 } 162 163 protected void enforceReceiveAndSend(String message) { 164 mContext.enforceCallingPermission( 165 Manifest.permission.RECEIVE_SMS, message); 166 mContext.enforceCallingPermission( 167 Manifest.permission.SEND_SMS, message); 168 } 169 170 /** 171 * Update the specified message on the Icc. 172 * 173 * @param index record index of message to update 174 * @param status new message status (STATUS_ON_ICC_READ, 175 * STATUS_ON_ICC_UNREAD, STATUS_ON_ICC_SENT, 176 * STATUS_ON_ICC_UNSENT, STATUS_ON_ICC_FREE) 177 * @param pdu the raw PDU to store 178 * @return success or not 179 * 180 */ 181 182 public boolean 183 updateMessageOnIccEf(String callingPackage, int index, int status, byte[] pdu) { 184 if (DBG) log("updateMessageOnIccEf: index=" + index + 185 " status=" + status + " ==> " + 186 "("+ Arrays.toString(pdu) + ")"); 187 enforceReceiveAndSend("Updating message on Icc"); 188 if (mAppOps.noteOp(AppOpsManager.OP_WRITE_ICC_SMS, Binder.getCallingUid(), 189 callingPackage) != AppOpsManager.MODE_ALLOWED) { 190 return false; 191 } 192 synchronized(mLock) { 193 mSuccess = false; 194 Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); 195 196 if (status == STATUS_ON_ICC_FREE) { 197 // RIL_REQUEST_DELETE_SMS_ON_SIM vs RIL_REQUEST_CDMA_DELETE_SMS_ON_RUIM 198 // Special case FREE: call deleteSmsOnSim/Ruim instead of 199 // manipulating the record 200 // Will eventually fail if icc card is not present. 201 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) { 202 mPhone.mCi.deleteSmsOnSim(index, response); 203 } else { 204 mPhone.mCi.deleteSmsOnRuim(index, response); 205 } 206 } else { 207 //IccFilehandler can be null if ICC card is not present. 208 IccFileHandler fh = mPhone.getIccFileHandler(); 209 if (fh == null) { 210 response.recycle(); 211 return mSuccess; /* is false */ 212 } 213 byte[] record = makeSmsRecordData(status, pdu); 214 fh.updateEFLinearFixed( 215 IccConstants.EF_SMS, 216 index, record, null, response); 217 } 218 try { 219 mLock.wait(); 220 } catch (InterruptedException e) { 221 log("interrupted while trying to update by index"); 222 } 223 } 224 return mSuccess; 225 } 226 227 /** 228 * Copy a raw SMS PDU to the Icc. 229 * 230 * @param pdu the raw PDU to store 231 * @param status message status (STATUS_ON_ICC_READ, STATUS_ON_ICC_UNREAD, 232 * STATUS_ON_ICC_SENT, STATUS_ON_ICC_UNSENT) 233 * @return success or not 234 * 235 */ 236 public boolean copyMessageToIccEf(String callingPackage, int status, byte[] pdu, byte[] smsc) { 237 //NOTE smsc not used in RUIM 238 if (DBG) log("copyMessageToIccEf: status=" + status + " ==> " + 239 "pdu=("+ Arrays.toString(pdu) + 240 "), smsc=(" + Arrays.toString(smsc) +")"); 241 enforceReceiveAndSend("Copying message to Icc"); 242 if (mAppOps.noteOp(AppOpsManager.OP_WRITE_ICC_SMS, Binder.getCallingUid(), 243 callingPackage) != AppOpsManager.MODE_ALLOWED) { 244 return false; 245 } 246 synchronized(mLock) { 247 mSuccess = false; 248 Message response = mHandler.obtainMessage(EVENT_UPDATE_DONE); 249 250 //RIL_REQUEST_WRITE_SMS_TO_SIM vs RIL_REQUEST_CDMA_WRITE_SMS_TO_RUIM 251 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) { 252 mPhone.mCi.writeSmsToSim(status, IccUtils.bytesToHexString(smsc), 253 IccUtils.bytesToHexString(pdu), response); 254 } else { 255 mPhone.mCi.writeSmsToRuim(status, IccUtils.bytesToHexString(pdu), 256 response); 257 } 258 259 try { 260 mLock.wait(); 261 } catch (InterruptedException e) { 262 log("interrupted while trying to update by index"); 263 } 264 } 265 return mSuccess; 266 } 267 268 /** 269 * Retrieves all messages currently stored on Icc. 270 * 271 * @return list of SmsRawData of all sms on Icc 272 */ 273 274 public List<SmsRawData> getAllMessagesFromIccEf(String callingPackage) { 275 if (DBG) log("getAllMessagesFromEF"); 276 277 mContext.enforceCallingOrSelfPermission( 278 Manifest.permission.RECEIVE_SMS, 279 "Reading messages from Icc"); 280 if (mAppOps.noteOp(AppOpsManager.OP_READ_ICC_SMS, Binder.getCallingUid(), 281 callingPackage) != AppOpsManager.MODE_ALLOWED) { 282 return new ArrayList<SmsRawData>(); 283 } 284 synchronized(mLock) { 285 286 IccFileHandler fh = mPhone.getIccFileHandler(); 287 if (fh == null) { 288 Rlog.e(LOG_TAG, "Cannot load Sms records. No icc card?"); 289 if (mSms != null) { 290 mSms.clear(); 291 return mSms; 292 } 293 } 294 295 Message response = mHandler.obtainMessage(EVENT_LOAD_DONE); 296 fh.loadEFLinearFixedAll(IccConstants.EF_SMS, response); 297 298 try { 299 mLock.wait(); 300 } catch (InterruptedException e) { 301 log("interrupted while trying to load from the Icc"); 302 } 303 } 304 return mSms; 305 } 306 307 /** 308 * Send a data based SMS to a specific application port. 309 * 310 * @param destAddr the address to send the message to 311 * @param scAddr is the service center address or null to use 312 * the current default SMSC 313 * @param destPort the port to deliver the message to 314 * @param data the body of the message to send 315 * @param sentIntent if not NULL this <code>PendingIntent</code> is 316 * broadcast when the message is successfully sent, or failed. 317 * The result code will be <code>Activity.RESULT_OK<code> for success, 318 * or one of these errors:<br> 319 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 320 * <code>RESULT_ERROR_RADIO_OFF</code><br> 321 * <code>RESULT_ERROR_NULL_PDU</code><br> 322 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 323 * the extra "errorCode" containing a radio technology specific value, 324 * generally only useful for troubleshooting.<br> 325 * The per-application based SMS control checks sentIntent. If sentIntent 326 * is NULL the caller will be checked against all unknown applications, 327 * which cause smaller number of SMS to be sent in checking period. 328 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 329 * broadcast when the message is delivered to the recipient. The 330 * raw pdu of the status report is in the extended data ("pdu"). 331 */ 332 333 public void sendData(String callingPackage, String destAddr, String scAddr, int destPort, 334 byte[] data, PendingIntent sentIntent, PendingIntent deliveryIntent) { 335 mPhone.getContext().enforceCallingPermission( 336 Manifest.permission.SEND_SMS, 337 "Sending SMS message"); 338 if (Rlog.isLoggable("SMS", Log.VERBOSE)) { 339 log("sendData: destAddr=" + destAddr + " scAddr=" + scAddr + " destPort=" + 340 destPort + " data='"+ HexDump.toHexString(data) + "' sentIntent=" + 341 sentIntent + " deliveryIntent=" + deliveryIntent); 342 } 343 if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), 344 callingPackage) != AppOpsManager.MODE_ALLOWED) { 345 return; 346 } 347 mDispatcher.sendData(destAddr, scAddr, destPort, data, sentIntent, deliveryIntent); 348 } 349 350 /** 351 * Send a text based SMS. 352 * 353 * @param destAddr the address to send the message to 354 * @param scAddr is the service center address or null to use 355 * the current default SMSC 356 * @param text the body of the message to send 357 * @param sentIntent if not NULL this <code>PendingIntent</code> is 358 * broadcast when the message is successfully sent, or failed. 359 * The result code will be <code>Activity.RESULT_OK<code> for success, 360 * or one of these errors:<br> 361 * <code>RESULT_ERROR_GENERIC_FAILURE</code><br> 362 * <code>RESULT_ERROR_RADIO_OFF</code><br> 363 * <code>RESULT_ERROR_NULL_PDU</code><br> 364 * For <code>RESULT_ERROR_GENERIC_FAILURE</code> the sentIntent may include 365 * the extra "errorCode" containing a radio technology specific value, 366 * generally only useful for troubleshooting.<br> 367 * The per-application based SMS control checks sentIntent. If sentIntent 368 * is NULL the caller will be checked against all unknown applications, 369 * which cause smaller number of SMS to be sent in checking period. 370 * @param deliveryIntent if not NULL this <code>PendingIntent</code> is 371 * broadcast when the message is delivered to the recipient. The 372 * raw pdu of the status report is in the extended data ("pdu"). 373 */ 374 375 public void sendText(String callingPackage, String destAddr, String scAddr, 376 String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { 377 mPhone.getContext().enforceCallingPermission( 378 Manifest.permission.SEND_SMS, 379 "Sending SMS message"); 380 if (Rlog.isLoggable("SMS", Log.VERBOSE)) { 381 log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr + 382 " text='"+ text + "' sentIntent=" + 383 sentIntent + " deliveryIntent=" + deliveryIntent); 384 } 385 if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), 386 callingPackage) != AppOpsManager.MODE_ALLOWED) { 387 return; 388 } 389 mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent); 390 } 391 392 /** 393 * Send a multi-part text based SMS. 394 * 395 * @param destAddr the address to send the message to 396 * @param scAddr is the service center address or null to use 397 * the current default SMSC 398 * @param parts an <code>ArrayList</code> of strings that, in order, 399 * comprise the original message 400 * @param sentIntents if not null, an <code>ArrayList</code> of 401 * <code>PendingIntent</code>s (one for each message part) that is 402 * broadcast when the corresponding message part has been sent. 403 * The result code will be <code>Activity.RESULT_OK<code> for success, 404 * or one of these errors: 405 * <code>RESULT_ERROR_GENERIC_FAILURE</code> 406 * <code>RESULT_ERROR_RADIO_OFF</code> 407 * <code>RESULT_ERROR_NULL_PDU</code>. 408 * The per-application based SMS control checks sentIntent. If sentIntent 409 * is NULL the caller will be checked against all unknown applications, 410 * which cause smaller number of SMS to be sent in checking period. 411 * @param deliveryIntents if not null, an <code>ArrayList</code> of 412 * <code>PendingIntent</code>s (one for each message part) that is 413 * broadcast when the corresponding message part has been delivered 414 * to the recipient. The raw pdu of the status report is in the 415 * extended data ("pdu"). 416 */ 417 418 public void sendMultipartText(String callingPackage, String destAddr, String scAddr, 419 List<String> parts, List<PendingIntent> sentIntents, 420 List<PendingIntent> deliveryIntents) { 421 mPhone.getContext().enforceCallingPermission( 422 Manifest.permission.SEND_SMS, 423 "Sending SMS message"); 424 if (Rlog.isLoggable("SMS", Log.VERBOSE)) { 425 int i = 0; 426 for (String part : parts) { 427 log("sendMultipartText: destAddr=" + destAddr + ", srAddr=" + scAddr + 428 ", part[" + (i++) + "]=" + part); 429 } 430 } 431 if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), 432 callingPackage) != AppOpsManager.MODE_ALLOWED) { 433 return; 434 } 435 mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList<String>) parts, 436 (ArrayList<PendingIntent>) sentIntents, (ArrayList<PendingIntent>) deliveryIntents); 437 } 438 439 440 public int getPremiumSmsPermission(String packageName) { 441 return mDispatcher.getPremiumSmsPermission(packageName); 442 } 443 444 445 public void setPremiumSmsPermission(String packageName, int permission) { 446 mDispatcher.setPremiumSmsPermission(packageName, permission); 447 } 448 449 /** 450 * create SmsRawData lists from all sms record byte[] 451 * Use null to indicate "free" record 452 * 453 * @param messages List of message records from EF_SMS. 454 * @return SmsRawData list of all in-used records 455 */ 456 protected ArrayList<SmsRawData> buildValidRawData(ArrayList<byte[]> messages) { 457 int count = messages.size(); 458 ArrayList<SmsRawData> ret; 459 460 ret = new ArrayList<SmsRawData>(count); 461 462 for (int i = 0; i < count; i++) { 463 byte[] ba = messages.get(i); 464 if (ba[0] == STATUS_ON_ICC_FREE) { 465 ret.add(null); 466 } else { 467 ret.add(new SmsRawData(messages.get(i))); 468 } 469 } 470 471 return ret; 472 } 473 474 /** 475 * Generates an EF_SMS record from status and raw PDU. 476 * 477 * @param status Message status. See TS 51.011 10.5.3. 478 * @param pdu Raw message PDU. 479 * @return byte array for the record. 480 */ 481 protected byte[] makeSmsRecordData(int status, byte[] pdu) { 482 byte[] data; 483 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) { 484 data = new byte[IccConstants.SMS_RECORD_LENGTH]; 485 } else { 486 data = new byte[IccConstants.CDMA_SMS_RECORD_LENGTH]; 487 } 488 489 // Status bits for this record. See TS 51.011 10.5.3 490 data[0] = (byte)(status & 7); 491 492 System.arraycopy(pdu, 0, data, 1, pdu.length); 493 494 // Pad out with 0xFF's. 495 for (int j = pdu.length+1; j < data.length; j++) { 496 data[j] = -1; 497 } 498 499 return data; 500 } 501 502 public boolean enableCellBroadcast(int messageIdentifier) { 503 return enableCellBroadcastRange(messageIdentifier, messageIdentifier); 504 } 505 506 public boolean disableCellBroadcast(int messageIdentifier) { 507 return disableCellBroadcastRange(messageIdentifier, messageIdentifier); 508 } 509 510 public boolean enableCellBroadcastRange(int startMessageId, int endMessageId) { 511 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) { 512 return enableGsmBroadcastRange(startMessageId, endMessageId); 513 } else { 514 return enableCdmaBroadcastRange(startMessageId, endMessageId); 515 } 516 } 517 518 public boolean disableCellBroadcastRange(int startMessageId, int endMessageId) { 519 if (PhoneConstants.PHONE_TYPE_GSM == mPhone.getPhoneType()) { 520 return disableGsmBroadcastRange(startMessageId, endMessageId); 521 } else { 522 return disableCdmaBroadcastRange(startMessageId, endMessageId); 523 } 524 } 525 526 synchronized public boolean enableGsmBroadcastRange(int startMessageId, int endMessageId) { 527 if (DBG) log("enableGsmBroadcastRange"); 528 529 Context context = mPhone.getContext(); 530 531 context.enforceCallingPermission( 532 "android.permission.RECEIVE_SMS", 533 "Enabling cell broadcast SMS"); 534 535 String client = context.getPackageManager().getNameForUid( 536 Binder.getCallingUid()); 537 538 if (!mCellBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) { 539 log("Failed to add cell broadcast subscription for MID range " + startMessageId 540 + " to " + endMessageId + " from client " + client); 541 return false; 542 } 543 544 if (DBG) 545 log("Added cell broadcast subscription for MID range " + startMessageId 546 + " to " + endMessageId + " from client " + client); 547 548 setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty()); 549 550 return true; 551 } 552 553 synchronized public boolean disableGsmBroadcastRange(int startMessageId, int endMessageId) { 554 if (DBG) log("disableGsmBroadcastRange"); 555 556 Context context = mPhone.getContext(); 557 558 context.enforceCallingPermission( 559 "android.permission.RECEIVE_SMS", 560 "Disabling cell broadcast SMS"); 561 562 String client = context.getPackageManager().getNameForUid( 563 Binder.getCallingUid()); 564 565 if (!mCellBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) { 566 log("Failed to remove cell broadcast subscription for MID range " + startMessageId 567 + " to " + endMessageId + " from client " + client); 568 return false; 569 } 570 571 if (DBG) 572 log("Removed cell broadcast subscription for MID range " + startMessageId 573 + " to " + endMessageId + " from client " + client); 574 575 setCellBroadcastActivation(!mCellBroadcastRangeManager.isEmpty()); 576 577 return true; 578 } 579 580 synchronized public boolean enableCdmaBroadcastRange(int startMessageId, int endMessageId) { 581 if (DBG) log("enableCdmaBroadcastRange"); 582 583 Context context = mPhone.getContext(); 584 585 context.enforceCallingPermission( 586 "android.permission.RECEIVE_SMS", 587 "Enabling cdma broadcast SMS"); 588 589 String client = context.getPackageManager().getNameForUid( 590 Binder.getCallingUid()); 591 592 if (!mCdmaBroadcastRangeManager.enableRange(startMessageId, endMessageId, client)) { 593 log("Failed to add cdma broadcast subscription for MID range " + startMessageId 594 + " to " + endMessageId + " from client " + client); 595 return false; 596 } 597 598 if (DBG) 599 log("Added cdma broadcast subscription for MID range " + startMessageId 600 + " to " + endMessageId + " from client " + client); 601 602 setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty()); 603 604 return true; 605 } 606 607 synchronized public boolean disableCdmaBroadcastRange(int startMessageId, int endMessageId) { 608 if (DBG) log("disableCdmaBroadcastRange"); 609 610 Context context = mPhone.getContext(); 611 612 context.enforceCallingPermission( 613 "android.permission.RECEIVE_SMS", 614 "Disabling cell broadcast SMS"); 615 616 String client = context.getPackageManager().getNameForUid( 617 Binder.getCallingUid()); 618 619 if (!mCdmaBroadcastRangeManager.disableRange(startMessageId, endMessageId, client)) { 620 log("Failed to remove cdma broadcast subscription for MID range " + startMessageId 621 + " to " + endMessageId + " from client " + client); 622 return false; 623 } 624 625 if (DBG) 626 log("Removed cdma broadcast subscription for MID range " + startMessageId 627 + " to " + endMessageId + " from client " + client); 628 629 setCdmaBroadcastActivation(!mCdmaBroadcastRangeManager.isEmpty()); 630 631 return true; 632 } 633 634 class CellBroadcastRangeManager extends IntRangeManager { 635 private ArrayList<SmsBroadcastConfigInfo> mConfigList = 636 new ArrayList<SmsBroadcastConfigInfo>(); 637 638 /** 639 * Called when the list of enabled ranges has changed. This will be 640 * followed by zero or more calls to {@link #addRange} followed by 641 * a call to {@link #finishUpdate}. 642 */ 643 protected void startUpdate() { 644 mConfigList.clear(); 645 } 646 647 /** 648 * Called after {@link #startUpdate} to indicate a range of enabled 649 * values. 650 * @param startId the first id included in the range 651 * @param endId the last id included in the range 652 */ 653 protected void addRange(int startId, int endId, boolean selected) { 654 mConfigList.add(new SmsBroadcastConfigInfo(startId, endId, 655 SMS_CB_CODE_SCHEME_MIN, SMS_CB_CODE_SCHEME_MAX, selected)); 656 } 657 658 /** 659 * Called to indicate the end of a range update started by the 660 * previous call to {@link #startUpdate}. 661 * @return true if successful, false otherwise 662 */ 663 protected boolean finishUpdate() { 664 if (mConfigList.isEmpty()) { 665 return true; 666 } else { 667 SmsBroadcastConfigInfo[] configs = 668 mConfigList.toArray(new SmsBroadcastConfigInfo[mConfigList.size()]); 669 return setCellBroadcastConfig(configs); 670 } 671 } 672 } 673 674 class CdmaBroadcastRangeManager extends IntRangeManager { 675 private ArrayList<CdmaSmsBroadcastConfigInfo> mConfigList = 676 new ArrayList<CdmaSmsBroadcastConfigInfo>(); 677 678 /** 679 * Called when the list of enabled ranges has changed. This will be 680 * followed by zero or more calls to {@link #addRange} followed by a 681 * call to {@link #finishUpdate}. 682 */ 683 protected void startUpdate() { 684 mConfigList.clear(); 685 } 686 687 /** 688 * Called after {@link #startUpdate} to indicate a range of enabled 689 * values. 690 * @param startId the first id included in the range 691 * @param endId the last id included in the range 692 */ 693 protected void addRange(int startId, int endId, boolean selected) { 694 mConfigList.add(new CdmaSmsBroadcastConfigInfo(startId, endId, 695 1, selected)); 696 } 697 698 /** 699 * Called to indicate the end of a range update started by the previous 700 * call to {@link #startUpdate}. 701 * @return true if successful, false otherwise 702 */ 703 protected boolean finishUpdate() { 704 if (mConfigList.isEmpty()) { 705 return true; 706 } else { 707 CdmaSmsBroadcastConfigInfo[] configs = 708 mConfigList.toArray(new CdmaSmsBroadcastConfigInfo[mConfigList.size()]); 709 return setCdmaBroadcastConfig(configs); 710 } 711 } 712 } 713 714 private boolean setCellBroadcastConfig(SmsBroadcastConfigInfo[] configs) { 715 if (DBG) 716 log("Calling setGsmBroadcastConfig with " + configs.length + " configurations"); 717 718 synchronized (mLock) { 719 Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE); 720 721 mSuccess = false; 722 mPhone.mCi.setGsmBroadcastConfig(configs, response); 723 724 try { 725 mLock.wait(); 726 } catch (InterruptedException e) { 727 log("interrupted while trying to set cell broadcast config"); 728 } 729 } 730 731 return mSuccess; 732 } 733 734 private boolean setCellBroadcastActivation(boolean activate) { 735 if (DBG) 736 log("Calling setCellBroadcastActivation(" + activate + ')'); 737 738 synchronized (mLock) { 739 Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE); 740 741 mSuccess = false; 742 mPhone.mCi.setGsmBroadcastActivation(activate, response); 743 744 try { 745 mLock.wait(); 746 } catch (InterruptedException e) { 747 log("interrupted while trying to set cell broadcast activation"); 748 } 749 } 750 751 return mSuccess; 752 } 753 754 private boolean setCdmaBroadcastConfig(CdmaSmsBroadcastConfigInfo[] configs) { 755 if (DBG) 756 log("Calling setCdmaBroadcastConfig with " + configs.length + " configurations"); 757 758 synchronized (mLock) { 759 Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_CONFIG_DONE); 760 761 mSuccess = false; 762 mPhone.mCi.setCdmaBroadcastConfig(configs, response); 763 764 try { 765 mLock.wait(); 766 } catch (InterruptedException e) { 767 log("interrupted while trying to set cdma broadcast config"); 768 } 769 } 770 771 return mSuccess; 772 } 773 774 private boolean setCdmaBroadcastActivation(boolean activate) { 775 if (DBG) 776 log("Calling setCdmaBroadcastActivation(" + activate + ")"); 777 778 synchronized (mLock) { 779 Message response = mHandler.obtainMessage(EVENT_SET_BROADCAST_ACTIVATION_DONE); 780 781 mSuccess = false; 782 mPhone.mCi.setCdmaBroadcastActivation(activate, response); 783 784 try { 785 mLock.wait(); 786 } catch (InterruptedException e) { 787 log("interrupted while trying to set cdma broadcast activation"); 788 } 789 } 790 791 return mSuccess; 792 } 793 794 protected void log(String msg) { 795 Log.d(LOG_TAG, "[IccSmsInterfaceManager] " + msg); 796 } 797 798 public boolean isImsSmsSupported() { 799 return mDispatcher.isIms(); 800 } 801 802 public String getImsSmsFormat() { 803 return mDispatcher.getImsSmsFormat(); 804 } 805} 806