1 /* 2 * Copyright (C) 2018 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 static android.telephony.PhoneCapability.DEVICE_NR_CAPABILITY_NSA; 20 import static android.telephony.PhoneCapability.DEVICE_NR_CAPABILITY_SA; 21 22 import static com.android.internal.telephony.RILConstants.RADIO_NOT_AVAILABLE; 23 import static com.android.internal.telephony.RILConstants.REQUEST_NOT_SUPPORTED; 24 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES; 25 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_PHONE_CAPABILITY; 26 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_GET_SLOT_STATUS; 27 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING; 28 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SET_PREFERRED_DATA_MODEM; 29 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG; 30 31 import android.content.Context; 32 import android.hardware.radio.V1_0.RadioResponseInfo; 33 import android.hardware.radio.V1_0.RadioResponseType; 34 import android.hardware.radio.config.V1_0.IRadioConfig; 35 import android.hardware.radio.config.V1_1.ModemsConfig; 36 import android.os.AsyncResult; 37 import android.os.Handler; 38 import android.os.HwBinder; 39 import android.os.Message; 40 import android.os.Registrant; 41 import android.os.RemoteException; 42 import android.os.WorkSource; 43 import android.telephony.TelephonyManager; 44 import android.util.SparseArray; 45 46 import com.android.internal.telephony.uicc.IccSlotStatus; 47 import com.android.telephony.Rlog; 48 49 import java.util.ArrayList; 50 import java.util.Arrays; 51 import java.util.List; 52 import java.util.NoSuchElementException; 53 import java.util.concurrent.atomic.AtomicLong; 54 55 /** 56 * This class provides wrapper APIs for IRadioConfig interface. 57 */ 58 public class RadioConfig extends Handler { 59 private static final String TAG = "RadioConfig"; 60 private static final boolean DBG = true; 61 private static final boolean VDBG = false; //STOPSHIP if true 62 63 private static final int EVENT_SERVICE_DEAD = 1; 64 65 private static final HalVersion RADIO_CONFIG_HAL_VERSION_UNKNOWN = new HalVersion(-1, -1); 66 67 private static final HalVersion RADIO_CONFIG_HAL_VERSION_1_0 = new HalVersion(1, 0); 68 69 private static final HalVersion RADIO_CONFIG_HAL_VERSION_1_1 = new HalVersion(1, 1); 70 71 private static final HalVersion RADIO_CONFIG_HAL_VERSION_1_3 = new HalVersion(1, 3); 72 73 private final boolean mIsMobileNetworkSupported; 74 private volatile IRadioConfig mRadioConfigProxy = null; 75 // IRadioConfig version 76 private HalVersion mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_UNKNOWN; 77 private final ServiceDeathRecipient mServiceDeathRecipient; 78 private final AtomicLong mRadioConfigProxyCookie = new AtomicLong(0); 79 private final RadioConfigResponse mRadioConfigResponse; 80 private final RadioConfigIndication mRadioConfigIndication; 81 private final SparseArray<RILRequest> mRequestList = new SparseArray<RILRequest>(); 82 /* default work source which will blame phone process */ 83 private final WorkSource mDefaultWorkSource; 84 private final int[] mDeviceNrCapabilities; 85 private static RadioConfig sRadioConfig; 86 private static final Object sLock = new Object(); 87 88 protected Registrant mSimSlotStatusRegistrant; 89 90 final class ServiceDeathRecipient implements HwBinder.DeathRecipient { 91 @Override serviceDied(long cookie)92 public void serviceDied(long cookie) { 93 // Deal with service going away 94 logd("serviceDied"); 95 sendMessage(obtainMessage(EVENT_SERVICE_DEAD, cookie)); 96 } 97 } 98 isMobileDataCapable(Context context)99 private boolean isMobileDataCapable(Context context) { 100 final TelephonyManager tm = context.getSystemService(TelephonyManager.class); 101 if (tm == null) { 102 return false; 103 } 104 return tm.isDataCapable(); 105 } 106 RadioConfig(Context context, HalVersion radioHalVersion)107 private RadioConfig(Context context, HalVersion radioHalVersion) { 108 mIsMobileNetworkSupported = isMobileDataCapable(context); 109 110 mRadioConfigResponse = new RadioConfigResponse(this, radioHalVersion); 111 mRadioConfigIndication = new RadioConfigIndication(this); 112 mServiceDeathRecipient = new ServiceDeathRecipient(); 113 114 mDefaultWorkSource = new WorkSource(context.getApplicationInfo().uid, 115 context.getPackageName()); 116 117 boolean is5gStandalone = context.getResources().getBoolean( 118 com.android.internal.R.bool.config_telephony5gStandalone); 119 boolean is5gNonStandalone = context.getResources().getBoolean( 120 com.android.internal.R.bool.config_telephony5gNonStandalone); 121 122 if (!is5gStandalone && !is5gNonStandalone) { 123 mDeviceNrCapabilities = new int[0]; 124 } else { 125 List<Integer> list = new ArrayList<>(); 126 if (is5gNonStandalone) { 127 list.add(DEVICE_NR_CAPABILITY_NSA); 128 } 129 if (is5gStandalone) { 130 list.add(DEVICE_NR_CAPABILITY_SA); 131 } 132 mDeviceNrCapabilities = list.stream().mapToInt(Integer::valueOf).toArray(); 133 } 134 } 135 136 /** 137 * Returns the singleton static instance of RadioConfig 138 */ getInstance()139 public static RadioConfig getInstance() { 140 synchronized (sLock) { 141 if (sRadioConfig == null) { 142 throw new RuntimeException( 143 "RadioConfig.getInstance can't be called before make()"); 144 } 145 return sRadioConfig; 146 } 147 } 148 149 /** 150 * Makes the radio config based on the context and the radio hal version passed in 151 */ make(Context c, HalVersion radioHalVersion)152 public static RadioConfig make(Context c, HalVersion radioHalVersion) { 153 synchronized (sLock) { 154 if (sRadioConfig != null) { 155 throw new RuntimeException("RadioConfig.make() should only be called once"); 156 } 157 sRadioConfig = new RadioConfig(c, radioHalVersion); 158 return sRadioConfig; 159 } 160 } 161 162 @Override handleMessage(Message message)163 public void handleMessage(Message message) { 164 switch (message.what) { 165 case EVENT_SERVICE_DEAD: 166 logd("handleMessage: EVENT_SERVICE_DEAD cookie = " + message.obj 167 + " mRadioConfigProxyCookie = " + mRadioConfigProxyCookie.get()); 168 if ((long) message.obj == mRadioConfigProxyCookie.get()) { 169 resetProxyAndRequestList("EVENT_SERVICE_DEAD", null); 170 } 171 break; 172 } 173 } 174 175 /** 176 * Release each request in mRequestList then clear the list 177 * @param error is the RIL_Errno sent back 178 * @param loggable true means to print all requests in mRequestList 179 */ clearRequestList(int error, boolean loggable)180 private void clearRequestList(int error, boolean loggable) { 181 RILRequest rr; 182 synchronized (mRequestList) { 183 int count = mRequestList.size(); 184 if (DBG && loggable) { 185 logd("clearRequestList: mRequestList=" + count); 186 } 187 188 for (int i = 0; i < count; i++) { 189 rr = mRequestList.valueAt(i); 190 if (DBG && loggable) { 191 logd(i + ": [" + rr.mSerial + "] " + requestToString(rr.mRequest)); 192 } 193 rr.onError(error, null); 194 rr.release(); 195 } 196 mRequestList.clear(); 197 } 198 } 199 resetProxyAndRequestList(String caller, Exception e)200 private void resetProxyAndRequestList(String caller, Exception e) { 201 loge(caller + ": " + e); 202 mRadioConfigProxy = null; 203 204 // increment the cookie so that death notification can be ignored 205 mRadioConfigProxyCookie.incrementAndGet(); 206 207 RILRequest.resetSerial(); 208 // Clear request list on close 209 clearRequestList(RADIO_NOT_AVAILABLE, false); 210 211 getRadioConfigProxy(null); 212 } 213 214 /** Returns a {@link IRadioConfig} instance or null if the service is not available. */ getRadioConfigProxy(Message result)215 public IRadioConfig getRadioConfigProxy(Message result) { 216 if (!mIsMobileNetworkSupported) { 217 if (VDBG) logd("getRadioConfigProxy: Not calling getService(): wifi-only"); 218 if (result != null) { 219 AsyncResult.forMessage(result, null, 220 CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); 221 result.sendToTarget(); 222 } 223 return null; 224 } 225 226 if (mRadioConfigProxy != null) { 227 return mRadioConfigProxy; 228 } 229 230 updateRadioConfigProxy(); 231 232 if (mRadioConfigProxy == null) { 233 if (result != null) { 234 AsyncResult.forMessage(result, null, 235 CommandException.fromRilErrno(RADIO_NOT_AVAILABLE)); 236 result.sendToTarget(); 237 } 238 } 239 240 return mRadioConfigProxy; 241 } 242 updateRadioConfigProxy()243 private void updateRadioConfigProxy() { 244 try { 245 246 // Try to get service from different versions. 247 try { 248 mRadioConfigProxy = android.hardware.radio.config.V1_3.IRadioConfig.getService( 249 true); 250 mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_3; 251 } catch (NoSuchElementException e) { 252 } 253 254 255 if (mRadioConfigProxy == null) { 256 // Try to get service from different versions. 257 try { 258 mRadioConfigProxy = android.hardware.radio.config.V1_1.IRadioConfig.getService( 259 true); 260 mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_1; 261 } catch (NoSuchElementException e) { 262 } 263 } 264 265 if (mRadioConfigProxy == null) { 266 try { 267 mRadioConfigProxy = android.hardware.radio.config.V1_0 268 .IRadioConfig.getService(true); 269 mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_0; 270 } catch (NoSuchElementException e) { 271 } 272 } 273 274 if (mRadioConfigProxy == null) { 275 loge("getRadioConfigProxy: mRadioConfigProxy == null"); 276 return; 277 } 278 279 // Link to death recipient and set response. If fails, set proxy to null and return. 280 mRadioConfigProxy.linkToDeath(mServiceDeathRecipient, 281 mRadioConfigProxyCookie.incrementAndGet()); 282 mRadioConfigProxy.setResponseFunctions(mRadioConfigResponse, 283 mRadioConfigIndication); 284 } catch (RemoteException | RuntimeException e) { 285 mRadioConfigProxy = null; 286 loge("getRadioConfigProxy: RadioConfigProxy setResponseFunctions: " + e); 287 return; 288 } 289 } 290 obtainRequest(int request, Message result, WorkSource workSource)291 private RILRequest obtainRequest(int request, Message result, WorkSource workSource) { 292 RILRequest rr = RILRequest.obtain(request, result, workSource); 293 synchronized (mRequestList) { 294 mRequestList.append(rr.mSerial, rr); 295 } 296 return rr; 297 } 298 findAndRemoveRequestFromList(int serial)299 private RILRequest findAndRemoveRequestFromList(int serial) { 300 RILRequest rr; 301 synchronized (mRequestList) { 302 rr = mRequestList.get(serial); 303 if (rr != null) { 304 mRequestList.remove(serial); 305 } 306 } 307 308 return rr; 309 } 310 311 /** 312 * This is a helper function to be called when a RadioConfigResponse callback is called. 313 * It finds and returns RILRequest corresponding to the response if one is found. 314 * @param responseInfo RadioResponseInfo received in response callback 315 * @return RILRequest corresponding to the response 316 */ processResponse(RadioResponseInfo responseInfo)317 public RILRequest processResponse(RadioResponseInfo responseInfo) { 318 int serial = responseInfo.serial; 319 int error = responseInfo.error; 320 int type = responseInfo.type; 321 322 if (type != RadioResponseType.SOLICITED) { 323 loge("processResponse: Unexpected response type " + type); 324 } 325 326 RILRequest rr = findAndRemoveRequestFromList(serial); 327 if (rr == null) { 328 loge("processResponse: Unexpected response! serial: " + serial + " error: " + error); 329 return null; 330 } 331 332 return rr; 333 } 334 335 /** 336 * This is a helper function to be called when a RadioConfigResponse callback is called. 337 * It finds and returns RILRequest corresponding to the response if one is found. 338 * @param responseInfo RadioResponseInfo received in response callback 339 * @return RILRequest corresponding to the response 340 */ processResponse_1_6( android.hardware.radio.V1_6.RadioResponseInfo responseInfo)341 public RILRequest processResponse_1_6( 342 android.hardware.radio.V1_6.RadioResponseInfo responseInfo) { 343 int serial = responseInfo.serial; 344 int error = responseInfo.error; 345 int type = responseInfo.type; 346 347 if (type != RadioResponseType.SOLICITED) { 348 loge("processResponse: Unexpected response type " + type); 349 } 350 351 RILRequest rr = findAndRemoveRequestFromList(serial); 352 if (rr == null) { 353 loge("processResponse: Unexpected response! serial: " + serial + " error: " + error); 354 return null; 355 } 356 357 return rr; 358 } 359 360 /** 361 * Wrapper function for IRadioConfig.getSimSlotsStatus(). 362 */ getSimSlotsStatus(Message result)363 public void getSimSlotsStatus(Message result) { 364 IRadioConfig radioConfigProxy = getRadioConfigProxy(result); 365 if (radioConfigProxy != null) { 366 RILRequest rr = obtainRequest(RIL_REQUEST_GET_SLOT_STATUS, result, mDefaultWorkSource); 367 368 if (DBG) { 369 logd(rr.serialString() + "> " + requestToString(rr.mRequest)); 370 } 371 372 try { 373 radioConfigProxy.getSimSlotsStatus(rr.mSerial); 374 } catch (RemoteException | RuntimeException e) { 375 resetProxyAndRequestList("getSimSlotsStatus", e); 376 } 377 } 378 } 379 380 /** 381 * Wrapper function for IRadioConfig.setPreferredDataModem(int modemId). 382 */ setPreferredDataModem(int modemId, Message result)383 public void setPreferredDataModem(int modemId, Message result) { 384 if (!isSetPreferredDataCommandSupported()) { 385 if (result != null) { 386 AsyncResult.forMessage(result, null, 387 CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); 388 result.sendToTarget(); 389 } 390 return; 391 } 392 393 RILRequest rr = obtainRequest(RIL_REQUEST_SET_PREFERRED_DATA_MODEM, 394 result, mDefaultWorkSource); 395 396 if (DBG) { 397 logd(rr.serialString() + "> " + requestToString(rr.mRequest)); 398 } 399 400 try { 401 ((android.hardware.radio.config.V1_1.IRadioConfig) mRadioConfigProxy) 402 .setPreferredDataModem(rr.mSerial, (byte) modemId); 403 } catch (RemoteException | RuntimeException e) { 404 resetProxyAndRequestList("setPreferredDataModem", e); 405 } 406 } 407 408 /** 409 * Wrapper function for IRadioConfig.getPhoneCapability(). 410 */ getPhoneCapability(Message result)411 public void getPhoneCapability(Message result) { 412 IRadioConfig radioConfigProxy = getRadioConfigProxy(null); 413 if (radioConfigProxy == null || mRadioConfigVersion.less(RADIO_CONFIG_HAL_VERSION_1_1)) { 414 if (result != null) { 415 AsyncResult.forMessage(result, null, 416 CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); 417 result.sendToTarget(); 418 } 419 return; 420 } 421 422 RILRequest rr = obtainRequest(RIL_REQUEST_GET_PHONE_CAPABILITY, result, mDefaultWorkSource); 423 424 if (DBG) { 425 logd(rr.serialString() + "> " + requestToString(rr.mRequest)); 426 } 427 428 try { 429 ((android.hardware.radio.config.V1_1.IRadioConfig) mRadioConfigProxy) 430 .getPhoneCapability(rr.mSerial); 431 } catch (RemoteException | RuntimeException e) { 432 resetProxyAndRequestList("getPhoneCapability", e); 433 } 434 } 435 436 /** 437 * @return whether current radio config version supports SET_PREFERRED_DATA_MODEM command. 438 * If yes, we'll use RIL_REQUEST_SET_PREFERRED_DATA_MODEM to indicate which modem is preferred. 439 * If not, we shall use RIL_REQUEST_ALLOW_DATA for on-demand PS attach / detach. 440 * See PhoneSwitcher for more details. 441 */ isSetPreferredDataCommandSupported()442 public boolean isSetPreferredDataCommandSupported() { 443 IRadioConfig radioConfigProxy = getRadioConfigProxy(null); 444 return radioConfigProxy != null && mRadioConfigVersion 445 .greaterOrEqual(RADIO_CONFIG_HAL_VERSION_1_1); 446 } 447 448 /** 449 * Wrapper function for IRadioConfig.setSimSlotsMapping(int32_t serial, vec<uint32_t> slotMap). 450 */ setSimSlotsMapping(int[] physicalSlots, Message result)451 public void setSimSlotsMapping(int[] physicalSlots, Message result) { 452 IRadioConfig radioConfigProxy = getRadioConfigProxy(result); 453 if (radioConfigProxy != null) { 454 RILRequest rr = obtainRequest(RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING, result, 455 mDefaultWorkSource); 456 457 if (DBG) { 458 logd(rr.serialString() + "> " + requestToString(rr.mRequest) 459 + " " + Arrays.toString(physicalSlots)); 460 } 461 462 try { 463 radioConfigProxy.setSimSlotsMapping(rr.mSerial, 464 primitiveArrayToArrayList(physicalSlots)); 465 } catch (RemoteException | RuntimeException e) { 466 resetProxyAndRequestList("setSimSlotsMapping", e); 467 } 468 } 469 } 470 primitiveArrayToArrayList(int[] arr)471 private static ArrayList<Integer> primitiveArrayToArrayList(int[] arr) { 472 ArrayList<Integer> arrayList = new ArrayList<>(arr.length); 473 for (int i : arr) { 474 arrayList.add(i); 475 } 476 return arrayList; 477 } 478 requestToString(int request)479 static String requestToString(int request) { 480 switch (request) { 481 case RIL_REQUEST_GET_PHONE_CAPABILITY: 482 return "GET_PHONE_CAPABILITY"; 483 case RIL_REQUEST_GET_SLOT_STATUS: 484 return "GET_SLOT_STATUS"; 485 case RIL_REQUEST_SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING: 486 return "SET_LOGICAL_TO_PHYSICAL_SLOT_MAPPING"; 487 case RIL_REQUEST_SET_PREFERRED_DATA_MODEM: 488 return "SET_PREFERRED_DATA_MODEM"; 489 case RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG: 490 return "SWITCH_DUAL_SIM_CONFIG"; 491 case RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES: 492 return "GET_HAL_DEVICE_CAPABILITIES"; 493 default: 494 return "<unknown request " + request + ">"; 495 } 496 } 497 498 /** 499 * Wrapper function for using IRadioConfig.setModemsConfig(int32_t serial, 500 * ModemsConfig modemsConfig) to switch between single-sim and multi-sim. 501 */ setModemsConfig(int numOfLiveModems, Message result)502 public void setModemsConfig(int numOfLiveModems, Message result) { 503 IRadioConfig radioConfigProxy = getRadioConfigProxy(result); 504 if (radioConfigProxy != null 505 && mRadioConfigVersion.greaterOrEqual(RADIO_CONFIG_HAL_VERSION_1_1)) { 506 android.hardware.radio.config.V1_1.IRadioConfig radioConfigProxy11 = 507 (android.hardware.radio.config.V1_1.IRadioConfig) radioConfigProxy; 508 RILRequest rr = obtainRequest(RIL_REQUEST_SWITCH_DUAL_SIM_CONFIG, 509 result, mDefaultWorkSource); 510 511 if (DBG) { 512 logd(rr.serialString() + "> " + requestToString(rr.mRequest) 513 + ", numOfLiveModems = " + numOfLiveModems); 514 } 515 516 try { 517 ModemsConfig modemsConfig = new ModemsConfig(); 518 modemsConfig.numOfLiveModems = (byte) numOfLiveModems; 519 radioConfigProxy11.setModemsConfig(rr.mSerial, modemsConfig); 520 } catch (RemoteException | RuntimeException e) { 521 resetProxyAndRequestList("setModemsConfig", e); 522 } 523 } 524 } 525 526 // TODO: not needed for now, but if we don't want to use System Properties any more, 527 // we need to implement a wrapper function for getModemsConfig as well 528 529 /** 530 * Register a handler to get SIM slot status changed notifications. 531 */ registerForSimSlotStatusChanged(Handler h, int what, Object obj)532 public void registerForSimSlotStatusChanged(Handler h, int what, Object obj) { 533 mSimSlotStatusRegistrant = new Registrant(h, what, obj); 534 } 535 536 /** 537 * Unregister corresponding to registerForSimSlotStatusChanged(). 538 */ unregisterForSimSlotStatusChanged(Handler h)539 public void unregisterForSimSlotStatusChanged(Handler h) { 540 if (mSimSlotStatusRegistrant != null && mSimSlotStatusRegistrant.getHandler() == h) { 541 mSimSlotStatusRegistrant.clear(); 542 mSimSlotStatusRegistrant = null; 543 } 544 } 545 546 /** 547 * Gets the hal capabilities from the device. 548 */ getHalDeviceCapabilities(Message result)549 public void getHalDeviceCapabilities(Message result) { 550 IRadioConfig radioConfigProxy = getRadioConfigProxy(Message.obtain(result)); 551 if (radioConfigProxy != null 552 && mRadioConfigVersion.greaterOrEqual(RADIO_CONFIG_HAL_VERSION_1_3)) { 553 android.hardware.radio.config.V1_3.IRadioConfig radioConfigProxy13 = 554 (android.hardware.radio.config.V1_3.IRadioConfig) radioConfigProxy; 555 RILRequest rr = obtainRequest(RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES, 556 result, mDefaultWorkSource); 557 558 if (DBG) { 559 logd(rr.serialString() + "> " + requestToString(rr.mRequest)); 560 } 561 562 try { 563 mRadioConfigVersion = RADIO_CONFIG_HAL_VERSION_1_3; 564 radioConfigProxy13.getHalDeviceCapabilities(rr.mSerial); 565 566 } catch (RemoteException | RuntimeException e) { 567 resetProxyAndRequestList("getHalDeviceCapabilities", e); 568 } 569 } else { 570 if (result != null) { 571 if (DBG) { 572 logd("RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES > REQUEST_NOT_SUPPORTED"); 573 } 574 AsyncResult.forMessage(result, 575 /* Send response such that all capabilities are supported (depending on 576 the hal version of course.) */ 577 mRadioConfigResponse.getFullCapabilitySet(), 578 CommandException.fromRilErrno(REQUEST_NOT_SUPPORTED)); 579 result.sendToTarget(); 580 } else { 581 if (DBG) { 582 logd("RIL_REQUEST_GET_HAL_DEVICE_CAPABILITIES > REQUEST_NOT_SUPPORTED " 583 + "on complete message not set."); 584 } 585 } 586 } 587 } 588 589 /** 590 * Returns the device's nr capability. 591 */ getDeviceNrCapabilities()592 public int[] getDeviceNrCapabilities() { 593 return mDeviceNrCapabilities; 594 } 595 convertHalSlotStatus( ArrayList<android.hardware.radio.config.V1_0.SimSlotStatus> halSlotStatusList)596 static ArrayList<IccSlotStatus> convertHalSlotStatus( 597 ArrayList<android.hardware.radio.config.V1_0.SimSlotStatus> halSlotStatusList) { 598 ArrayList<IccSlotStatus> response = new ArrayList<IccSlotStatus>(halSlotStatusList.size()); 599 for (android.hardware.radio.config.V1_0.SimSlotStatus slotStatus : halSlotStatusList) { 600 IccSlotStatus iccSlotStatus = new IccSlotStatus(); 601 iccSlotStatus.setCardState(slotStatus.cardState); 602 iccSlotStatus.setSlotState(slotStatus.slotState); 603 iccSlotStatus.logicalSlotIndex = slotStatus.logicalSlotId; 604 iccSlotStatus.atr = slotStatus.atr; 605 iccSlotStatus.iccid = slotStatus.iccid; 606 response.add(iccSlotStatus); 607 } 608 return response; 609 } 610 convertHalSlotStatus_1_2( ArrayList<android.hardware.radio.config.V1_2.SimSlotStatus> halSlotStatusList)611 static ArrayList<IccSlotStatus> convertHalSlotStatus_1_2( 612 ArrayList<android.hardware.radio.config.V1_2.SimSlotStatus> halSlotStatusList) { 613 ArrayList<IccSlotStatus> response = new ArrayList<IccSlotStatus>(halSlotStatusList.size()); 614 for (android.hardware.radio.config.V1_2.SimSlotStatus slotStatus : halSlotStatusList) { 615 IccSlotStatus iccSlotStatus = new IccSlotStatus(); 616 iccSlotStatus.setCardState(slotStatus.base.cardState); 617 iccSlotStatus.setSlotState(slotStatus.base.slotState); 618 iccSlotStatus.logicalSlotIndex = slotStatus.base.logicalSlotId; 619 iccSlotStatus.atr = slotStatus.base.atr; 620 iccSlotStatus.iccid = slotStatus.base.iccid; 621 iccSlotStatus.eid = slotStatus.eid; 622 response.add(iccSlotStatus); 623 } 624 return response; 625 } 626 logd(String log)627 private static void logd(String log) { 628 Rlog.d(TAG, log); 629 } 630 loge(String log)631 private static void loge(String log) { 632 Rlog.e(TAG, log); 633 } 634 } 635