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