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