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 if (ar.exception != null) { 339 // just abort now. They didn't take our start so we don't have to revert 340 logd("onStartRadioCapabilityResponse got exception=" + ar.exception); 341 mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement(); 342 Intent intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_FAILED); 343 mContext.sendBroadcast(intent); 344 clearTransaction(); 345 return; 346 } 347 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 348 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 349 logd("onStartRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId 350 + " rc=" + rc); 351 return; 352 } 353 mRadioAccessFamilyStatusCounter--; 354 int id = rc.getPhoneId(); 355 if (((AsyncResult) msg.obj).exception != null) { 356 logd("onStartRadioCapabilityResponse: Error response session=" + rc.getSession()); 357 logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=FAIL"); 358 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; 359 mTransactionFailed = true; 360 } else { 361 logd("onStartRadioCapabilityResponse: phoneId=" + id + " status=STARTED"); 362 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_STARTED; 363 } 364 365 if (mRadioAccessFamilyStatusCounter == 0) { 366 HashSet<String> modemsInUse = new HashSet<String>(mNewLogicalModemIds.length); 367 for (String modemId : mNewLogicalModemIds) { 368 if (!modemsInUse.add(modemId)) { 369 mTransactionFailed = true; 370 Log.wtf(LOG_TAG, "ERROR: sending down the same id for different phones"); 371 } 372 } 373 logd("onStartRadioCapabilityResponse: success=" + !mTransactionFailed); 374 if (mTransactionFailed) { 375 // Sends a variable number of requests, so don't resetRadioAccessFamilyCounter 376 // here. 377 issueFinish(mRadioCapabilitySessionId); 378 } else { 379 // All logical modem accepted the new radio access family, issue the APPLY 380 resetRadioAccessFamilyStatusCounter(); 381 for (int i = 0; i < mPhones.length; i++) { 382 sendRadioCapabilityRequest( 383 i, 384 mRadioCapabilitySessionId, 385 RadioCapability.RC_PHASE_APPLY, 386 mNewRadioAccessFamily[i], 387 mNewLogicalModemIds[i], 388 RadioCapability.RC_STATUS_NONE, 389 EVENT_APPLY_RC_RESPONSE); 390 391 logd("onStartRadioCapabilityResponse: phoneId=" + i + " status=APPLYING"); 392 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_APPLYING; 393 } 394 } 395 } 396 } 397 } 398 399 /** 400 * Handle APPLY response 401 * @param msg obj field isa RadioCapability 402 */ onApplyRadioCapabilityResponse(Message msg)403 private void onApplyRadioCapabilityResponse(Message msg) { 404 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 405 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 406 logd("onApplyRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId 407 + " rc=" + rc); 408 return; 409 } 410 logd("onApplyRadioCapabilityResponse: rc=" + rc); 411 if (((AsyncResult) msg.obj).exception != null) { 412 synchronized (mSetRadioAccessFamilyStatus) { 413 logd("onApplyRadioCapabilityResponse: Error response session=" + rc.getSession()); 414 int id = rc.getPhoneId(); 415 logd("onApplyRadioCapabilityResponse: phoneId=" + id + " status=FAIL"); 416 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; 417 mTransactionFailed = true; 418 } 419 } else { 420 logd("onApplyRadioCapabilityResponse: Valid start expecting notification rc=" + rc); 421 } 422 } 423 424 /** 425 * Handle the notification unsolicited response associated with the APPLY 426 * @param msg obj field isa RadioCapability 427 */ onNotificationRadioCapabilityChanged(Message msg)428 private void onNotificationRadioCapabilityChanged(Message msg) { 429 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 430 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 431 logd("onNotificationRadioCapabilityChanged: Ignore session=" + mRadioCapabilitySessionId 432 + " rc=" + rc); 433 return; 434 } 435 synchronized (mSetRadioAccessFamilyStatus) { 436 logd("onNotificationRadioCapabilityChanged: rc=" + rc); 437 // skip the overdue response by checking sessionId 438 if (rc.getSession() != mRadioCapabilitySessionId) { 439 logd("onNotificationRadioCapabilityChanged: Ignore session=" 440 + mRadioCapabilitySessionId + " rc=" + rc); 441 return; 442 } 443 444 int id = rc.getPhoneId(); 445 if ((((AsyncResult) msg.obj).exception != null) || 446 (rc.getStatus() == RadioCapability.RC_STATUS_FAIL)) { 447 logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=FAIL"); 448 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_FAIL; 449 mTransactionFailed = true; 450 } else { 451 logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=SUCCESS"); 452 mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_SUCCESS; 453 // The modems may have been restarted and forgotten this 454 mPhoneSwitcher.resendDataAllowed(id); 455 mPhones[id].radioCapabilityUpdated(rc); 456 } 457 458 mRadioAccessFamilyStatusCounter--; 459 if (mRadioAccessFamilyStatusCounter == 0) { 460 logd("onNotificationRadioCapabilityChanged: APPLY URC success=" + 461 mTransactionFailed); 462 issueFinish(mRadioCapabilitySessionId); 463 } 464 } 465 } 466 467 /** 468 * Handle the FINISH Phase response 469 * @param msg obj field isa RadioCapability 470 */ onFinishRadioCapabilityResponse(Message msg)471 void onFinishRadioCapabilityResponse(Message msg) { 472 RadioCapability rc = (RadioCapability) ((AsyncResult) msg.obj).result; 473 if ((rc == null) || (rc.getSession() != mRadioCapabilitySessionId)) { 474 logd("onFinishRadioCapabilityResponse: Ignore session=" + mRadioCapabilitySessionId 475 + " rc=" + rc); 476 return; 477 } 478 synchronized (mSetRadioAccessFamilyStatus) { 479 logd(" onFinishRadioCapabilityResponse mRadioAccessFamilyStatusCounter=" 480 + mRadioAccessFamilyStatusCounter); 481 mRadioAccessFamilyStatusCounter--; 482 if (mRadioAccessFamilyStatusCounter == 0) { 483 completeRadioCapabilityTransaction(); 484 } 485 } 486 } 487 onTimeoutRadioCapability(Message msg)488 private void onTimeoutRadioCapability(Message msg) { 489 if (msg.arg1 != mRadioCapabilitySessionId) { 490 logd("RadioCapability timeout: Ignore msg.arg1=" + msg.arg1 + 491 "!= mRadioCapabilitySessionId=" + mRadioCapabilitySessionId); 492 return; 493 } 494 495 synchronized(mSetRadioAccessFamilyStatus) { 496 // timed-out. Clean up as best we can 497 for (int i = 0; i < mPhones.length; i++) { 498 logd("RadioCapability timeout: mSetRadioAccessFamilyStatus[" + i + "]=" + 499 mSetRadioAccessFamilyStatus[i]); 500 } 501 502 // Increment the sessionId as we are completing the transaction below 503 // so we don't want it completed when the FINISH phase is done. 504 int uniqueDifferentId = mUniqueIdGenerator.getAndIncrement(); 505 // send FINISH request with fail status and then uniqueDifferentId 506 mTransactionFailed = true; 507 issueFinish(uniqueDifferentId); 508 } 509 } 510 issueFinish(int sessionId)511 private void issueFinish(int sessionId) { 512 // Issue FINISH 513 synchronized(mSetRadioAccessFamilyStatus) { 514 for (int i = 0; i < mPhones.length; i++) { 515 logd("issueFinish: phoneId=" + i + " sessionId=" + sessionId 516 + " mTransactionFailed=" + mTransactionFailed); 517 mRadioAccessFamilyStatusCounter++; 518 sendRadioCapabilityRequest( 519 i, 520 sessionId, 521 RadioCapability.RC_PHASE_FINISH, 522 mOldRadioAccessFamily[i], 523 mCurrentLogicalModemIds[i], 524 (mTransactionFailed ? RadioCapability.RC_STATUS_FAIL : 525 RadioCapability.RC_STATUS_SUCCESS), 526 EVENT_FINISH_RC_RESPONSE); 527 if (mTransactionFailed) { 528 logd("issueFinish: phoneId: " + i + " status: FAIL"); 529 // At least one failed, mark them all failed. 530 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_FAIL; 531 } 532 } 533 } 534 } 535 completeRadioCapabilityTransaction()536 private void completeRadioCapabilityTransaction() { 537 // Create the intent to broadcast 538 Intent intent; 539 logd("onFinishRadioCapabilityResponse: success=" + !mTransactionFailed); 540 if (!mTransactionFailed) { 541 ArrayList<RadioAccessFamily> phoneRAFList = new ArrayList<RadioAccessFamily>(); 542 for (int i = 0; i < mPhones.length; i++) { 543 int raf = mPhones[i].getRadioAccessFamily(); 544 logd("radioAccessFamily[" + i + "]=" + raf); 545 RadioAccessFamily phoneRC = new RadioAccessFamily(i, raf); 546 phoneRAFList.add(phoneRC); 547 } 548 intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_DONE); 549 intent.putParcelableArrayListExtra(TelephonyIntents.EXTRA_RADIO_ACCESS_FAMILY, 550 phoneRAFList); 551 552 // make messages about the old transaction obsolete (specifically the timeout) 553 mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement(); 554 555 // Reinitialize 556 clearTransaction(); 557 } else { 558 intent = new Intent(TelephonyIntents.ACTION_SET_RADIO_CAPABILITY_FAILED); 559 560 // now revert. 561 mTransactionFailed = false; 562 RadioAccessFamily[] rafs = new RadioAccessFamily[mPhones.length]; 563 for (int phoneId = 0; phoneId < mPhones.length; phoneId++) { 564 rafs[phoneId] = new RadioAccessFamily(phoneId, mOldRadioAccessFamily[phoneId]); 565 } 566 doSetRadioCapabilities(rafs); 567 } 568 569 // Broadcast that we're done 570 mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE); 571 } 572 573 // Clear this transaction clearTransaction()574 private void clearTransaction() { 575 logd("clearTransaction"); 576 synchronized(mSetRadioAccessFamilyStatus) { 577 for (int i = 0; i < mPhones.length; i++) { 578 logd("clearTransaction: phoneId=" + i + " status=IDLE"); 579 mSetRadioAccessFamilyStatus[i] = SET_RC_STATUS_IDLE; 580 mOldRadioAccessFamily[i] = 0; 581 mNewRadioAccessFamily[i] = 0; 582 mTransactionFailed = false; 583 } 584 585 if (mWakeLock.isHeld()) { 586 mWakeLock.release(); 587 } 588 } 589 } 590 resetRadioAccessFamilyStatusCounter()591 private void resetRadioAccessFamilyStatusCounter() { 592 mRadioAccessFamilyStatusCounter = mPhones.length; 593 } 594 sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase, int radioFamily, String logicalModemId, int status, int eventId)595 private void sendRadioCapabilityRequest(int phoneId, int sessionId, int rcPhase, 596 int radioFamily, String logicalModemId, int status, int eventId) { 597 RadioCapability requestRC = new RadioCapability( 598 phoneId, sessionId, rcPhase, radioFamily, logicalModemId, status); 599 mPhones[phoneId].setRadioCapability( 600 requestRC, mHandler.obtainMessage(eventId)); 601 } 602 603 // This method will return max number of raf bits supported from the raf 604 // values currently stored in all phone objects getMaxRafSupported()605 public int getMaxRafSupported() { 606 int[] numRafSupported = new int[mPhones.length]; 607 int maxNumRafBit = 0; 608 int maxRaf = RadioAccessFamily.RAF_UNKNOWN; 609 610 for (int len = 0; len < mPhones.length; len++) { 611 numRafSupported[len] = Integer.bitCount(mPhones[len].getRadioAccessFamily()); 612 if (maxNumRafBit < numRafSupported[len]) { 613 maxNumRafBit = numRafSupported[len]; 614 maxRaf = mPhones[len].getRadioAccessFamily(); 615 } 616 } 617 618 return maxRaf; 619 } 620 621 // This method will return minimum number of raf bits supported from the raf 622 // values currently stored in all phone objects getMinRafSupported()623 public int getMinRafSupported() { 624 int[] numRafSupported = new int[mPhones.length]; 625 int minNumRafBit = 0; 626 int minRaf = RadioAccessFamily.RAF_UNKNOWN; 627 628 for (int len = 0; len < mPhones.length; len++) { 629 numRafSupported[len] = Integer.bitCount(mPhones[len].getRadioAccessFamily()); 630 if ((minNumRafBit == 0) || (minNumRafBit > numRafSupported[len])) { 631 minNumRafBit = numRafSupported[len]; 632 minRaf = mPhones[len].getRadioAccessFamily(); 633 } 634 } 635 return minRaf; 636 } 637 638 // This method checks current raf values stored in all phones and 639 // whicheve phone raf matches with input raf, returns modemId from that phone getLogicalModemIdFromRaf(int raf)640 private String getLogicalModemIdFromRaf(int raf) { 641 String modemUuid = null; 642 643 for (int phoneId = 0; phoneId < mPhones.length; phoneId++) { 644 if (mPhones[phoneId].getRadioAccessFamily() == raf) { 645 modemUuid = mPhones[phoneId].getModemUuId(); 646 break; 647 } 648 } 649 return modemUuid; 650 } 651 logd(String string)652 private void logd(String string) { 653 Rlog.d(LOG_TAG, string); 654 } 655 loge(String string)656 private void loge(String string) { 657 Rlog.e(LOG_TAG, string); 658 } 659 } 660