1 /* 2 * Copyright (C) 2013 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 17 package com.android.internal.telephony; 18 19 import android.content.Context; 20 import android.content.Intent; 21 import android.os.AsyncResult; 22 import android.os.Handler; 23 import android.os.Message; 24 import android.os.PowerManager; 25 import android.os.PowerManager.WakeLock; 26 import android.telephony.RadioAccessFamily; 27 import android.telephony.Rlog; 28 import android.telephony.TelephonyManager; 29 import android.util.Log; 30 31 import com.android.internal.telephony.uicc.UiccController; 32 33 import java.util.ArrayList; 34 import java.util.HashSet; 35 import java.util.Random; 36 import java.util.concurrent.atomic.AtomicInteger; 37 38 public class ProxyController { 39 static final String LOG_TAG = "ProxyController"; 40 41 private static final int EVENT_NOTIFICATION_RC_CHANGED = 1; 42 private static final int EVENT_START_RC_RESPONSE = 2; 43 private static final int EVENT_APPLY_RC_RESPONSE = 3; 44 private static final int EVENT_FINISH_RC_RESPONSE = 4; 45 private static final int EVENT_TIMEOUT = 5; 46 47 private static final int SET_RC_STATUS_IDLE = 0; 48 private static final int SET_RC_STATUS_STARTING = 1; 49 private static final int SET_RC_STATUS_STARTED = 2; 50 private static final int SET_RC_STATUS_APPLYING = 3; 51 private static final int SET_RC_STATUS_SUCCESS = 4; 52 private static final int SET_RC_STATUS_FAIL = 5; 53 54 // The entire transaction must complete within this amount of time 55 // or a FINISH will be issued to each Logical Modem with the old 56 // Radio Access Family. 57 private static final int SET_RC_TIMEOUT_WAITING_MSEC = (45 * 1000); 58 59 //***** Class Variables 60 private static ProxyController sProxyController; 61 62 private Phone[] mPhones; 63 64 private UiccController mUiccController; 65 66 private CommandsInterface[] mCi; 67 68 private Context mContext; 69 70 private PhoneSwitcher mPhoneSwitcher; 71 72 //UiccPhoneBookController to use proper IccPhoneBookInterfaceManagerProxy object 73 private UiccPhoneBookController mUiccPhoneBookController; 74 75 //PhoneSubInfoController to use proper PhoneSubInfoProxy object 76 private PhoneSubInfoController mPhoneSubInfoController; 77 78 //UiccSmsController to use proper IccSmsInterfaceManager object 79 private UiccSmsController mUiccSmsController; 80 81 WakeLock mWakeLock; 82 83 // record each phone's set radio capability status 84 private int[] mSetRadioAccessFamilyStatus; 85 private int mRadioAccessFamilyStatusCounter; 86 private boolean mTransactionFailed = false; 87 88 private String[] mCurrentLogicalModemIds; 89 private String[] mNewLogicalModemIds; 90 91 // Allows the generation of unique Id's for radio capability request session id 92 private AtomicInteger mUniqueIdGenerator = new AtomicInteger(new Random().nextInt()); 93 94 // on-going radio capability request session id 95 private int mRadioCapabilitySessionId; 96 97 // Record new and old Radio Access Family (raf) configuration. 98 // The old raf configuration is used to restore each logical modem raf when FINISH is 99 // issued if any requests fail. 100 private int[] mNewRadioAccessFamily; 101 private int[] mOldRadioAccessFamily; 102 103 104 //***** Class Methods getInstance(Context context, Phone[] phone, UiccController uiccController, CommandsInterface[] ci, PhoneSwitcher ps)105 public static ProxyController getInstance(Context context, Phone[] phone, 106 UiccController uiccController, CommandsInterface[] ci, PhoneSwitcher ps) { 107 if (sProxyController == null) { 108 sProxyController = new ProxyController(context, phone, uiccController, ci, ps); 109 } 110 return sProxyController; 111 } 112 getInstance()113 public static ProxyController getInstance() { 114 return sProxyController; 115 } 116 ProxyController(Context context, Phone[] phone, UiccController uiccController, CommandsInterface[] ci, PhoneSwitcher phoneSwitcher)117 private ProxyController(Context context, Phone[] phone, UiccController uiccController, 118 CommandsInterface[] ci, PhoneSwitcher phoneSwitcher) { 119 logd("Constructor - Enter"); 120 121 mContext = context; 122 mPhones = phone; 123 mUiccController = uiccController; 124 mCi = ci; 125 mPhoneSwitcher = phoneSwitcher; 126 127 mUiccPhoneBookController = new UiccPhoneBookController(mPhones); 128 mPhoneSubInfoController = new PhoneSubInfoController(mContext, mPhones); 129 mUiccSmsController = new UiccSmsController(); 130 mSetRadioAccessFamilyStatus = new int[mPhones.length]; 131 mNewRadioAccessFamily = new int[mPhones.length]; 132 mOldRadioAccessFamily = new int[mPhones.length]; 133 mCurrentLogicalModemIds = new String[mPhones.length]; 134 mNewLogicalModemIds = new String[mPhones.length]; 135 136 // wake lock for set radio capability 137 PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 138 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG); 139 mWakeLock.setReferenceCounted(false); 140 141 // Clear to be sure we're in the initial state 142 clearTransaction(); 143 for (int i = 0; i < mPhones.length; i++) { 144 mPhones[i].registerForRadioCapabilityChanged( 145 mHandler, EVENT_NOTIFICATION_RC_CHANGED, null); 146 } 147 logd("Constructor - Exit"); 148 } 149 updateDataConnectionTracker(int sub)150 public void updateDataConnectionTracker(int sub) { 151 mPhones[sub].updateDataConnectionTracker(); 152 } 153 enableDataConnectivity(int sub)154 public void enableDataConnectivity(int sub) { 155 mPhones[sub].setInternalDataEnabled(true, null); 156 } 157 disableDataConnectivity(int sub, Message dataCleanedUpMsg)158 public void disableDataConnectivity(int sub, 159 Message dataCleanedUpMsg) { 160 mPhones[sub].setInternalDataEnabled(false, dataCleanedUpMsg); 161 } 162 updateCurrentCarrierInProvider(int sub)163 public void updateCurrentCarrierInProvider(int sub) { 164 mPhones[sub].updateCurrentCarrierInProvider(); 165 } 166 registerForAllDataDisconnected(int subId, Handler h, int what, Object obj)167 public void registerForAllDataDisconnected(int subId, Handler h, int what, Object obj) { 168 int phoneId = SubscriptionController.getInstance().getPhoneId(subId); 169 170 if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) { 171 mPhones[phoneId].registerForAllDataDisconnected(h, what, obj); 172 } 173 } 174 unregisterForAllDataDisconnected(int subId, Handler h)175 public void unregisterForAllDataDisconnected(int subId, Handler h) { 176 int phoneId = SubscriptionController.getInstance().getPhoneId(subId); 177 178 if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) { 179 mPhones[phoneId].unregisterForAllDataDisconnected(h); 180 } 181 } 182 isDataDisconnected(int subId)183 public boolean isDataDisconnected(int subId) { 184 int phoneId = SubscriptionController.getInstance().getPhoneId(subId); 185 186 if (phoneId >= 0 && phoneId < TelephonyManager.getDefault().getPhoneCount()) { 187 return mPhones[phoneId].mDcTracker.isDisconnected(); 188 } else { 189 // if we can't find a phone for the given subId, it is disconnected. 190 return true; 191 } 192 } 193 194 /** 195 * Get phone radio type and access technology. 196 * 197 * @param phoneId which phone you want to get 198 * @return phone radio type and access technology for input phone ID 199 */ getRadioAccessFamily(int phoneId)200 public int getRadioAccessFamily(int phoneId) { 201 if (phoneId >= mPhones.length) { 202 return RadioAccessFamily.RAF_UNKNOWN; 203 } else { 204 return mPhones[phoneId].getRadioAccessFamily(); 205 } 206 } 207 208 /** 209 * Set phone radio type and access technology for each phone. 210 * 211 * @param rafs an RadioAccessFamily array to indicate all phone's 212 * new radio access family. The length of RadioAccessFamily 213 * must equal to phone count. 214 * @return false if another session is already active and the request is rejected. 215 */ setRadioCapability(RadioAccessFamily[] rafs)216 public boolean setRadioCapability(RadioAccessFamily[] rafs) { 217 if (rafs.length != mPhones.length) { 218 throw new RuntimeException("Length of input rafs must equal to total phone count"); 219 } 220 // Check if there is any ongoing transaction and throw an exception if there 221 // is one as this is a programming error. 222 synchronized (mSetRadioAccessFamilyStatus) { 223 for (int i = 0; i < mPhones.length; i++) { 224 if (mSetRadioAccessFamilyStatus[i] != SET_RC_STATUS_IDLE) { 225 // TODO: The right behaviour is to cancel previous request and send this. 226 loge("setRadioCapability: Phone[" + i + "] is not idle. Rejecting request."); 227 return false; 228 } 229 } 230 } 231 232 // Check we actually need to do anything 233 boolean same = true; 234 for (int i = 0; i < mPhones.length; i++) { 235 if (mPhones[i].getRadioAccessFamily() != rafs[i].getRadioAccessFamily()) { 236 same = false; 237 } 238 } 239 if (same) { 240 // All phones are already set to the requested raf 241 logd("setRadioCapability: Already in requested configuration, nothing to do."); 242 // It isn't really an error, so return true - everything is OK. 243 return true; 244 } 245 246 // Clear to be sure we're in the initial state 247 clearTransaction(); 248 249 // Keep a wake lock until we finish radio capability changed 250 mWakeLock.acquire(); 251 252 return doSetRadioCapabilities(rafs); 253 } 254 doSetRadioCapabilities(RadioAccessFamily[] rafs)255 private boolean doSetRadioCapabilities(RadioAccessFamily[] rafs) { 256 // A new sessionId for this transaction 257 mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement(); 258 259 // Start timer to make sure all phones respond within a specific time interval. 260 // Will send FINISH if a timeout occurs. 261 Message msg = mHandler.obtainMessage(EVENT_TIMEOUT, mRadioCapabilitySessionId, 0); 262 mHandler.sendMessageDelayed(msg, SET_RC_TIMEOUT_WAITING_MSEC); 263 264 synchronized (mSetRadioAccessFamilyStatus) { 265 logd("setRadioCapability: new request session id=" + mRadioCapabilitySessionId); 266 resetRadioAccessFamilyStatusCounter(); 267 for (int i = 0; i < rafs.length; i++) { 268 int phoneId = rafs[i].getPhoneId(); 269 logd("setRadioCapability: phoneId=" + phoneId + " status=STARTING"); 270 mSetRadioAccessFamilyStatus[phoneId] = SET_RC_STATUS_STARTING; 271 mOldRadioAccessFamily[phoneId] = mPhones[phoneId].getRadioAccessFamily(); 272 int requestedRaf = rafs[i].getRadioAccessFamily(); 273 // TODO Set the new radio access family to the maximum of the requested & supported 274 // int supportedRaf = mPhones[i].getRadioAccessFamily(); 275 // mNewRadioAccessFamily[phoneId] = requestedRaf & supportedRaf; 276 mNewRadioAccessFamily[phoneId] = requestedRaf; 277 278 mCurrentLogicalModemIds[phoneId] = mPhones[phoneId].getModemUuId(); 279 // get the logical mode corresponds to new raf requested and pass the 280 // same as part of SET_RADIO_CAP APPLY phase 281 mNewLogicalModemIds[phoneId] = getLogicalModemIdFromRaf(requestedRaf); 282 logd("setRadioCapability: mOldRadioAccessFamily[" + phoneId + "]=" 283 + mOldRadioAccessFamily[phoneId]); 284 logd("setRadioCapability: mNewRadioAccessFamily[" + phoneId + "]=" 285 + mNewRadioAccessFamily[phoneId]); 286 sendRadioCapabilityRequest( 287 phoneId, 288 mRadioCapabilitySessionId, 289 RadioCapability.RC_PHASE_START, 290 mOldRadioAccessFamily[phoneId], 291 mCurrentLogicalModemIds[phoneId], 292 RadioCapability.RC_STATUS_NONE, 293 EVENT_START_RC_RESPONSE); 294 } 295 } 296 297 return true; 298 } 299 300 private Handler mHandler = new Handler() { 301 @Override 302 public void handleMessage(Message msg) { 303 logd("handleMessage msg.what=" + msg.what); 304 switch (msg.what) { 305 case EVENT_START_RC_RESPONSE: 306 onStartRadioCapabilityResponse(msg); 307 break; 308 309 case EVENT_APPLY_RC_RESPONSE: 310 onApplyRadioCapabilityResponse(msg); 311 break; 312 313 case EVENT_NOTIFICATION_RC_CHANGED: 314 onNotificationRadioCapabilityChanged(msg); 315 break; 316 317 case EVENT_FINISH_RC_RESPONSE: 318 onFinishRadioCapabilityResponse(msg); 319 break; 320 321 case EVENT_TIMEOUT: 322 onTimeoutRadioCapability(msg); 323 break; 324 325 default: 326 break; 327 } 328 } 329 }; 330 331 /** 332 * Handle START response 333 * @param msg obj field isa RadioCapability 334 */ onStartRadioCapabilityResponse(Message msg)335 private void onStartRadioCapabilityResponse(Message msg) { 336 synchronized (mSetRadioAccessFamilyStatus) { 337 AsyncResult ar = (AsyncResult)msg.obj; 338 // Abort here only in Single SIM case, in Multi SIM cases 339 // send FINISH with failure so that below layers can re-bind 340 // old logical modems. 341 if ((TelephonyManager.getDefault().getPhoneCount() == 1) && (ar.exception != null)) { 342 // just abort now. They didn't take our start so we don't have to revert 343 logd("onStartRadioCapabilityResponse got exception=" + ar.exception); 344 mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement(); 345 Intent intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_FAILED); 346 mContext.sendBroadcast(intent); 347 clearTransaction(); 348 return; 349 } 350 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 351 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 352 logd("onStartRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId 353 + " rc=" + rc); 354 return; 355 } 356 mRadioAccessFamilyStatusCounter--; 357 int id = rc.getPhoneId(); 358 if (((AsyncResult) msg.obj).exception != null) { 359 logd("onStartRadioCapabilityResponse: Error response session=" + rc.getSession()); 360 logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=FAIL"); 361 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; 362 mTransactionFailed = true; 363 } else { 364 logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=STARTED"); 365 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_STARTED; 366 } 367 368 if (mRadioAccessFamilyStatusCounter == 0) { 369 HashSet<String> modemsInUse = new HashSet<String>(mNewLogicalModemIds.length); 370 for (String modemId : mNewLogicalModemIds) { 371 if (!modemsInUse.add(modemId)) { 372 mTransactionFailed = true; 373 Log.wtf(LOG_TAG, "ERROR: sending down the same id for different phones"); 374 } 375 } 376 logd("onStartRadioCapabilityResponse: success=" + !mTransactionFailed); 377 if (mTransactionFailed) { 378 // Sends a variable number of requests, so don't resetRadioAccessFamilyCounter 379 // here. 380 issueFinish(mRadioCapabilitySessionId); 381 } else { 382 // All logical modem accepted the new radio access family, issue the APPLY 383 resetRadioAccessFamilyStatusCounter(); 384 for (int i = 0; i < mPhones.length; i++) { 385 sendRadioCapabilityRequest( 386 i, 387 mRadioCapabilitySessionId, 388 RadioCapability.RC_PHASE_APPLY, 389 mNewRadioAccessFamily[i], 390 mNewLogicalModemIds[i], 391 RadioCapability.RC_STATUS_NONE, 392 EVENT_APPLY_RC_RESPONSE); 393 394 logd("onStartRadioCapabilityResponse: phoneId=" + i + " status=APPLYING"); 395 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_APPLYING; 396 } 397 } 398 } 399 } 400 } 401 402 /** 403 * Handle APPLY response 404 * @param msg obj field isa RadioCapability 405 */ onApplyRadioCapabilityResponse(Message msg)406 private void onApplyRadioCapabilityResponse(Message msg) { 407 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 408 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 409 logd("onApplyRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId 410 + " rc=" + rc); 411 return; 412 } 413 logd("onApplyRadioCapabilityResponse: rc=" + rc); 414 if (((AsyncResult) msg.obj).exception != null) { 415 synchronized (mSetRadioAccessFamilyStatus) { 416 logd("onApplyRadioCapabilityResponse: Error response session=" + rc.getSession()); 417 int id = rc.getPhoneId(); 418 logd("onApplyRadioCapabilityResponse: phoneId=" + id + " status=FAIL"); 419 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; 420 mTransactionFailed = true; 421 } 422 } else { 423 logd("onApplyRadioCapabilityResponse: Valid start expecting notification rc=" + rc); 424 } 425 } 426 427 /** 428 * Handle the notification unsolicited response associated with the APPLY 429 * @param msg obj field isa RadioCapability 430 */ onNotificationRadioCapabilityChanged(Message msg)431 private void onNotificationRadioCapabilityChanged(Message msg) { 432 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 433 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 434 logd("onNotificationRadioCapabilityChanged: Ignore session=" + mRadioCapabilitySessionId 435 + " rc=" + rc); 436 return; 437 } 438 synchronized (mSetRadioAccessFamilyStatus) { 439 logd("onNotificationRadioCapabilityChanged: rc=" + rc); 440 // skip the overdue response by checking sessionId 441 if (rc.getSession() != mRadioCapabilitySessionId) { 442 logd("onNotificationRadioCapabilityChanged: Ignore session=" 443 + mRadioCapabilitySessionId + " rc=" + rc); 444 return; 445 } 446 447 int id = rc.getPhoneId(); 448 if ((((AsyncResult) msg.obj).exception != null) || 449 (rc.getStatus() == RadioCapability.RC_STATUS_FAIL)) { 450 logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=FAIL"); 451 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; 452 mTransactionFailed = true; 453 } else { 454 logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=SUCCESS"); 455 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_SUCCESS; 456 // The modems may have been restarted and forgotten this 457 mPhoneSwitcher.resendDataAllowed(id); 458 mPhones[id].radioCapabilityUpdated(rc); 459 } 460 461 mRadioAccessFamilyStatusCounter--; 462 if (mRadioAccessFamilyStatusCounter == 0) { 463 logd("onNotificationRadioCapabilityChanged: APPLY URC success=" + 464 mTransactionFailed); 465 issueFinish(mRadioCapabilitySessionId); 466 } 467 } 468 } 469 470 /** 471 * Handle the FINISH Phase response 472 * @param msg obj field isa RadioCapability 473 */ onFinishRadioCapabilityResponse(Message msg)474 void onFinishRadioCapabilityResponse(Message msg) { 475 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 476 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 477 logd("onFinishRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId 478 + " rc=" + rc); 479 return; 480 } 481 synchronized (mSetRadioAccessFamilyStatus) { 482 logd(" onFinishRadioCapabilityResponse mRadioAccessFamilyStatusCounter=" 483 + mRadioAccessFamilyStatusCounter); 484 mRadioAccessFamilyStatusCounter--; 485 if (mRadioAccessFamilyStatusCounter == 0) { 486 completeRadioCapabilityTransaction(); 487 } 488 } 489 } 490 onTimeoutRadioCapability(Message msg)491 private void onTimeoutRadioCapability(Message msg) { 492 if (msg.arg1 != mRadioCapabilitySessionId) { 493 logd("RadioCapability timeout: Ignore msg.arg1=" + msg.arg1 + 494 "!= mRadioCapabilitySessionId=" + mRadioCapabilitySessionId); 495 return; 496 } 497 498 synchronized(mSetRadioAccessFamilyStatus) { 499 // timed-out. Clean up as best we can 500 for (int i = 0; i < mPhones.length; i++) { 501 logd("RadioCapability timeout: mSetRadioAccessFamilyStatus[" + i + "]=" + 502 mSetRadioAccessFamilyStatus[i]); 503 } 504 505 // Increment the sessionId as we are completing the transaction below 506 // so we don't want it completed when the FINISH phase is done. 507 mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement(); 508 509 // Reset the status counter as existing session failed 510 mRadioAccessFamilyStatusCounter = 0; 511 512 // send FINISH request with fail status and then uniqueDifferentId 513 mTransactionFailed = true; 514 issueFinish(mRadioCapabilitySessionId); 515 } 516 } 517 issueFinish(int sessionId)518 private void issueFinish(int sessionId) { 519 // Issue FINISH 520 synchronized(mSetRadioAccessFamilyStatus) { 521 for (int i = 0; i < mPhones.length; i++) { 522 logd("issueFinish: phoneId=" + i + " sessionId=" + sessionId 523 + " mTransactionFailed=" + mTransactionFailed); 524 mRadioAccessFamilyStatusCounter++; 525 sendRadioCapabilityRequest( 526 i, 527 sessionId, 528 RadioCapability.RC_PHASE_FINISH, 529 (mTransactionFailed ? mOldRadioAccessFamily[i] : 530 mNewRadioAccessFamily[i]), 531 (mTransactionFailed ? mCurrentLogicalModemIds[i] : 532 mNewLogicalModemIds[i]), 533 (mTransactionFailed ? RadioCapability.RC_STATUS_FAIL : 534 RadioCapability.RC_STATUS_SUCCESS), 535 EVENT_FINISH_RC_RESPONSE); 536 if (mTransactionFailed) { 537 logd("issueFinish: phoneId: " + i + " status: FAIL"); 538 // At least one failed, mark them all failed. 539 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_FAIL; 540 } 541 } 542 } 543 } 544 completeRadioCapabilityTransaction()545 private void completeRadioCapabilityTransaction() { 546 // Create the intent to broadcast 547 Intent intent; 548 logd("onFinishRadioCapabilityResponse: success=" + !mTransactionFailed); 549 if (!mTransactionFailed) { 550 ArrayList<RadioAccessFamily> phoneRAFList = new ArrayList<RadioAccessFamily>(); 551 for (int i = 0; i < mPhones.length; i++) { 552 int raf = mPhones[i].getRadioAccessFamily(); 553 logd("radioAccessFamily[" + i + "]=" + raf); 554 RadioAccessFamily phoneRC = new RadioAccessFamily(i, raf); 555 phoneRAFList.add(phoneRC); 556 } 557 intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_DONE); 558 intent.putParcelableArrayListExtra(TelephonyIntents.EXTRA_RADIO_ACCESS_FAMILY, 559 phoneRAFList); 560 561 // make messages about the old transaction obsolete (specifically the timeout) 562 mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement(); 563 564 // Reinitialize 565 clearTransaction(); 566 } else { 567 intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_FAILED); 568 569 // now revert. 570 mTransactionFailed = false; 571 RadioAccessFamily[] rafs = new RadioAccessFamily[mPhones.length]; 572 for (int phoneId = 0; phoneId < mPhones.length; phoneId++) { 573 rafs[phoneId] = new RadioAccessFamily(phoneId, mOldRadioAccessFamily[phoneId]); 574 } 575 doSetRadioCapabilities(rafs); 576 } 577 578 // Broadcast that we're done 579 mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE); 580 } 581 582 // Clear this transaction clearTransaction()583 private void clearTransaction() { 584 logd("clearTransaction"); 585 synchronized(mSetRadioAccessFamilyStatus) { 586 for (int i = 0; i < mPhones.length; i++) { 587 logd("clearTransaction: phoneId=" + i + " status=IDLE"); 588 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_IDLE; 589 mOldRadioAccessFamily[i] = 0; 590 mNewRadioAccessFamily[i] = 0; 591 mTransactionFailed = false; 592 } 593 594 if (mWakeLock.isHeld()) { 595 mWakeLock.release(); 596 } 597 } 598 } 599 resetRadioAccessFamilyStatusCounter()600 private void resetRadioAccessFamilyStatusCounter() { 601 mRadioAccessFamilyStatusCounter = mPhones.length; 602 } 603 sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase, int radioFamily, String logicalModemId, int status, int eventId)604 private void sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase, 605 int radioFamily, String logicalModemId, int status, int eventId) { 606 RadioCapability requestRC = new RadioCapability( 607 phoneId, sessionId, rcPhase, radioFamily, logicalModemId, status); 608 mPhones[phoneId].setRadioCapability( 609 requestRC, mHandler.obtainMessage(eventId)); 610 } 611 612 // This method will return max number of raf bits supported from the raf 613 // values currently stored in all phone objects getMaxRafSupported()614 public int getMaxRafSupported() { 615 int[] numRafSupported = new int[mPhones.length]; 616 int maxNumRafBit = 0; 617 int maxRaf = RadioAccessFamily.RAF_UNKNOWN; 618 619 for (int len = 0; len < mPhones.length; len++) { 620 numRafSupported[len] = Integer.bitCount(mPhones[len].getRadioAccessFamily()); 621 if (maxNumRafBit < numRafSupported[len]) { 622 maxNumRafBit = numRafSupported[len]; 623 maxRaf = mPhones[len].getRadioAccessFamily(); 624 } 625 } 626 627 return maxRaf; 628 } 629 630 // This method will return minimum number of raf bits supported from the raf 631 // values currently stored in all phone objects getMinRafSupported()632 public int getMinRafSupported() { 633 int[] numRafSupported = new int[mPhones.length]; 634 int minNumRafBit = 0; 635 int minRaf = RadioAccessFamily.RAF_UNKNOWN; 636 637 for (int len = 0; len < mPhones.length; len++) { 638 numRafSupported[len] = Integer.bitCount(mPhones[len].getRadioAccessFamily()); 639 if ((minNumRafBit == 0) || (minNumRafBit > numRafSupported[len])) { 640 minNumRafBit = numRafSupported[len]; 641 minRaf = mPhones[len].getRadioAccessFamily(); 642 } 643 } 644 return minRaf; 645 } 646 647 // This method checks current raf values stored in all phones and 648 // whicheve phone raf matches with input raf, returns modemId from that phone getLogicalModemIdFromRaf(int raf)649 private String getLogicalModemIdFromRaf(int raf) { 650 String modemUuid = null; 651 652 for (int phoneId = 0; phoneId < mPhones.length; phoneId++) { 653 if (mPhones[phoneId].getRadioAccessFamily() == raf) { 654 modemUuid = mPhones[phoneId].getModemUuId(); 655 break; 656 } 657 } 658 return modemUuid; 659 } 660 logd(String string)661 private void logd(String string) { 662 Rlog.d(LOG_TAG, string); 663 } 664 loge(String string)665 private void loge(String string) { 666 Rlog.e(LOG_TAG, string); 667 } 668 } 669