1#!/usr/bin/env python3 2# 3# Copyright 2016 - Google 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17# This is test util for subscription setup. 18# It will be deleted once we have better solution for subscription ids. 19import re 20import time 21 22from acts_contrib.test_utils.tel.tel_defines import CHIPSET_MODELS_LIST 23from acts_contrib.test_utils.tel.tel_defines import INVALID_PORT_INDEX 24from acts_contrib.test_utils.tel.tel_defines import INVALID_SIM_SLOT_INDEX 25from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID 26from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID 27from future import standard_library 28 29standard_library.install_aliases() 30 31 32def initial_set_up_for_subid_information(log, ad): 33 """Initial subid setup for voice, message and data according to ad's 34 attribute. 35 36 Setup sub id properties for android device. Including the followings: 37 incoming_voice_sub_id 38 incoming_message_sub_id 39 outgoing_voice_sub_id 40 outgoing_message_sub_id 41 default_data_sub_id 42 43 Args: 44 log: log object 45 ad: android device object 46 47 Returns: 48 None 49 """ 50 # outgoing_voice_sub_id 51 # If default_voice_sim_slot_index is set in config file, then use sub_id 52 # of this SIM as default_outgoing_sub_id. If default_voice_sim_slot_index 53 # is not set, then use default voice sub_id as default_outgoing_sub_id. 54 # Outgoing voice call will be made on default_outgoing_sub_id by default. 55 if hasattr(ad, "default_voice_sim_slot_index"): 56 outgoing_voice_sub_id = get_subid_from_slot_index( 57 log, ad, ad.default_voice_sim_slot_index) 58 set_subid_for_outgoing_call(ad, outgoing_voice_sub_id) 59 else: 60 outgoing_voice_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId() 61 setattr(ad, "outgoing_voice_sub_id", outgoing_voice_sub_id) 62 63 # outgoing_message_sub_id 64 # If default_message_sim_slot_index is set in config file, then use sub_id 65 # of this SIM as outgoing_message_sub_id. If default_message_sim_slot_index 66 # is not set, then use default Sms sub_id as outgoing_message_sub_id. 67 # Outgoing SMS will be sent on outgoing_message_sub_id by default. 68 if hasattr(ad, "default_message_sim_slot_index"): 69 outgoing_message_sub_id = get_subid_from_slot_index( 70 log, ad, ad.default_message_sim_slot_index) 71 set_subid_for_message(ad, outgoing_message_sub_id) 72 else: 73 outgoing_message_sub_id = ad.droid.subscriptionGetDefaultSmsSubId() 74 setattr(ad, "outgoing_message_sub_id", outgoing_message_sub_id) 75 76 # default_data_sub_id 77 # If default_data_sim_slot_index is set in config file, then use sub_id 78 # of this SIM as default_data_sub_id. If default_data_sim_slot_index 79 # is not set, then use default Data sub_id as default_data_sub_id. 80 # Data connection will be established on default_data_sub_id by default. 81 if hasattr(ad, "default_data_sim_slot_index"): 82 default_data_sub_id = get_subid_from_slot_index( 83 log, ad, ad.default_data_sim_slot_index) 84 set_subid_for_data(ad, default_data_sub_id, 0) 85 else: 86 default_data_sub_id = ad.droid.subscriptionGetDefaultDataSubId() 87 setattr(ad, "default_data_sub_id", default_data_sub_id) 88 89 # This is for Incoming Voice Sub ID 90 # If "incoming_voice_sim_slot_index" is set in config file, then 91 # incoming voice call will call to the phone number of the SIM in 92 # "incoming_voice_sim_slot_index". 93 # If "incoming_voice_sim_slot_index" is NOT set in config file, 94 # then incoming voice call will call to the phone number of default 95 # subId. 96 if hasattr(ad, "incoming_voice_sim_slot_index"): 97 incoming_voice_sub_id = get_subid_from_slot_index( 98 log, ad, ad.incoming_voice_sim_slot_index) 99 else: 100 incoming_voice_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId() 101 setattr(ad, "incoming_voice_sub_id", incoming_voice_sub_id) 102 103 # This is for Incoming SMS Sub ID 104 # If "incoming_message_sim_slot_index" is set in config file, then 105 # incoming SMS be sent to the phone number of the SIM in 106 # "incoming_message_sim_slot_index". 107 # If "incoming_message_sim_slot_index" is NOT set in config file, 108 # then incoming SMS be sent to the phone number of default 109 # subId. 110 if hasattr(ad, "incoming_message_sim_slot_index"): 111 incoming_message_sub_id = get_subid_from_slot_index( 112 log, ad, ad.incoming_message_sim_slot_index) 113 else: 114 incoming_message_sub_id = ad.droid.subscriptionGetDefaultSmsSubId() 115 setattr(ad, "incoming_message_sub_id", incoming_message_sub_id) 116 117 118def get_default_data_sub_id(ad): 119 """ Get default data subscription id 120 """ 121 if hasattr(ad, "default_data_sub_id"): 122 return ad.default_data_sub_id 123 else: 124 return ad.droid.subscriptionGetDefaultDataSubId() 125 126 127def get_outgoing_message_sub_id(ad): 128 """ Get outgoing message subscription id 129 """ 130 if hasattr(ad, "outgoing_message_sub_id"): 131 return ad.outgoing_message_sub_id 132 else: 133 return ad.droid.subscriptionGetDefaultSmsSubId() 134 135 136def get_outgoing_voice_sub_id(ad): 137 """ Get outgoing voice subscription id 138 """ 139 if hasattr(ad, "outgoing_voice_sub_id"): 140 return ad.outgoing_voice_sub_id 141 else: 142 return ad.droid.subscriptionGetDefaultVoiceSubId() 143 144 145def get_incoming_voice_sub_id(ad): 146 """ Get incoming voice subscription id 147 """ 148 if hasattr(ad, "incoming_voice_sub_id"): 149 return ad.incoming_voice_sub_id 150 else: 151 return ad.droid.subscriptionGetDefaultVoiceSubId() 152 153 154def get_incoming_message_sub_id(ad): 155 """ Get incoming message subscription id 156 """ 157 if hasattr(ad, "incoming_message_sub_id"): 158 return ad.incoming_message_sub_id 159 else: 160 return ad.droid.subscriptionGetDefaultSmsSubId() 161 162 163def get_subid_by_adb(ad, sim_slot_index): 164 """Get the subscription ID for a SIM at a particular slot via adb command. 165 166 Args: 167 ad: android device object. 168 sim_slot_index: slot 0 or slot 1. 169 170 Returns: 171 Subscription ID. 172 """ 173 try: 174 output = ad.adb.shell("dumpsys isub | grep subIds") 175 pattern = re.compile(r"sSlotIndexToSubId\[%d\]:\s*subIds=%d=\[(\d)\]" % 176 (sim_slot_index, sim_slot_index)) 177 sub_id = pattern.findall(output) 178 except Exception as e: 179 error_msg = "%s due to %s" % ("Failed to get the subid", e) 180 ad.log.error(error_msg) 181 return INVALID_SUB_ID 182 return int(sub_id[0]) if sub_id else INVALID_SUB_ID 183 184 185def get_subid_from_slot_index(log, ad, sim_slot_index): 186 """ Get the subscription ID for a SIM at a particular slot. 187 188 Args: 189 ad: android_device object. 190 sim_slot_index: 0 for pSIM, 191 1 for eSIM port 0, 192 2 for eSIM port 1. 193 194 Returns: 195 result: Subscription ID 196 """ 197 siminfo = ad.adb.shell( 198 "content query --uri content://telephony/siminfo") 199 if "port_index" in siminfo and getattr(ad, "mep", False): 200 pattern_port = re.compile(r"port_index=(\d)") 201 pattern_sub = re.compile(r" _id=(\d+)") 202 pattern_embedded = re.compile(r"is_embedded=(\d+)") 203 siminfo_list = siminfo.splitlines() 204 for row in siminfo_list: 205 sub_id = pattern_sub.findall(row) 206 sub_id = int(sub_id[-1]) if sub_id else INVALID_SUB_ID 207 port_id = pattern_port.findall(row) 208 port_id = int(port_id[-1]) if port_id else INVALID_PORT_INDEX 209 is_embedded = int(pattern_embedded.findall(row)[-1]) 210 if port_id == INVALID_PORT_INDEX: 211 continue 212 elif sim_slot_index == 0 and is_embedded == 0: 213 return sub_id 214 elif sim_slot_index-1 == port_id and is_embedded == 1: 215 return sub_id 216 else: 217 sim_slot_index = 1 if sim_slot_index else 0 218 subInfo = ad.droid.subscriptionGetAllSubInfoList() 219 for info in subInfo: 220 if info['simSlotIndex'] == sim_slot_index: 221 return info['subscriptionId'] 222 return INVALID_SUB_ID 223 224 225def get_subid_from_logical_slot(ad, logical_slot): 226 """ Get the subscription ID for a SIM at a particular logical slot. 227 228 Args: 229 ad: android_device object. 230 logical_slot: The logical slot(0 or 1). 231 232 Returns: 233 result: Subscription ID 234 """ 235 logical_slot = 1 if logical_slot else 0 236 subInfo = ad.droid.subscriptionGetAllSubInfoList() 237 for info in subInfo: 238 if info['simSlotIndex'] == logical_slot: 239 return info['subscriptionId'] 240 return INVALID_SUB_ID 241 242 243def get_operatorname_from_slot_index(ad, sim_slot_index): 244 """ Get the operator name for a SIM at a particular slot 245 246 Args: 247 ad: android_device object. 248 249 Returns: 250 result: Operator Name 251 """ 252 subInfo = ad.droid.subscriptionGetAllSubInfoList() 253 for info in subInfo: 254 if info['simSlotIndex'] == sim_slot_index: 255 return info['displayName'] 256 return None 257 258 259def get_carrierid_from_slot_index(ad, sim_slot_index): 260 """ Get the carrierId for a SIM at a particular slot 261 262 Args: 263 ad: android_device object. 264 sim_slot_index: slot 0 or slot 1 265 266 Returns: 267 result: CarrierId 268 """ 269 subInfo = ad.droid.subscriptionGetAllSubInfoList() 270 for info in subInfo: 271 if info['simSlotIndex'] == sim_slot_index: 272 return info['carrierId'] 273 return None 274 275 276def get_isopportunistic_from_slot_index(ad, sim_slot_index): 277 """ Get the isOppotunistic field for a particular slot 278 279 Args: 280 ad: android_device object. 281 sim_slot_index: slot 0 or slot 1 282 283 Returns: 284 result: True or False based on Value set 285 """ 286 subInfo = ad.droid.subscriptionGetAllSubInfoList() 287 for info in subInfo: 288 if info['simSlotIndex'] == sim_slot_index: 289 return info['isOpportunistic'] 290 return None 291 292 293def set_subid_for_data(ad, sub_id, time_to_sleep=WAIT_TIME_CHANGE_DATA_SUB_ID): 294 """Set subId for data 295 296 Args: 297 ad: android device object. 298 sub_id: subscription id (integer) 299 300 Returns: 301 None 302 """ 303 # TODO: Need to check onSubscriptionChanged event. b/27843365 304 if ad.droid.subscriptionGetDefaultDataSubId() != sub_id: 305 ad.droid.subscriptionSetDefaultDataSubId(sub_id) 306 time.sleep(time_to_sleep) 307 setattr(ad, "default_data_sub_id", sub_id) 308 309 310def set_subid_for_message(ad, sub_id): 311 """Set subId for outgoing message 312 313 Args: 314 ad: android device object. 315 sub_id: subscription id (integer) 316 317 Returns: 318 None 319 """ 320 ad.droid.subscriptionSetDefaultSmsSubId(sub_id) 321 if hasattr(ad, "outgoing_message_sub_id"): 322 ad.outgoing_message_sub_id = sub_id 323 324 325def set_message_subid(ad, sub_id): 326 """Set subId for both outgoing and incoming messages 327 328 Args: 329 ad: android device object. 330 sub_id: subscription id (integer) 331 332 Returns: 333 None 334 """ 335 ad.droid.subscriptionSetDefaultSmsSubId(sub_id) 336 if hasattr(ad, "outgoing_message_sub_id"): 337 ad.outgoing_message_sub_id = sub_id 338 if hasattr(ad, "incoming_message_sub_id"): 339 ad.incoming_message_sub_id = sub_id 340 341 342def set_subid_for_outgoing_call(ad, sub_id): 343 """Set subId for outgoing voice call 344 345 Args: 346 ad: android device object. 347 sub_id: subscription id (integer) 348 349 Returns: 350 None 351 """ 352 ad.droid.telecomSetUserSelectedOutgoingPhoneAccountBySubId(sub_id) 353 if hasattr(ad, "outgoing_voice_sub_id"): 354 ad.outgoing_voice_sub_id = sub_id 355 356 357def set_incoming_voice_sub_id(ad, sub_id): 358 """Set default subId for voice calls 359 360 Args: 361 ad: android device object. 362 sub_id: subscription id (integer) 363 364 Returns: 365 None 366 """ 367 ad.droid.subscriptionSetDefaultVoiceSubId(sub_id) 368 if hasattr(ad, "incoming_voice_sub_id"): 369 ad.incoming_voice_sub_id = sub_id 370 371 372def set_voice_sub_id(ad, sub_id): 373 """Set default subId for both incoming and outgoing voice calls 374 375 Args: 376 ad: android device object. 377 sub_id: subscription id (integer) 378 379 Returns: 380 None 381 """ 382 ad.droid.subscriptionSetDefaultVoiceSubId(sub_id) 383 if hasattr(ad, "incoming_voice_sub_id"): 384 ad.incoming_voice_sub_id = sub_id 385 if hasattr(ad, "outgoing_voice_sub_id"): 386 ad.outgoing_voice_sub_id = sub_id 387 388 389def set_default_sub_for_all_services(ad, slot_id=0): 390 """Set subId for all services 391 392 Args: 393 ad: android device object. 394 slot_id: 0 or 1 (integer) 395 396 Returns: 397 None 398 """ 399 sub_id = get_subid_from_slot_index(ad.log, ad, slot_id) 400 ad.log.info("Default Subid for all service is %s", sub_id) 401 set_subid_for_outgoing_call(ad, sub_id) 402 set_incoming_voice_sub_id(ad, sub_id) 403 set_subid_for_data(ad, sub_id) 404 set_subid_for_message(ad, sub_id) 405 ad.droid.telephonyToggleDataConnection(True) 406 407 408def perform_dds_switch(ad): 409 slot_dict = {0: {}, 1: {}} 410 for slot in (0,1): 411 slot_dict[slot]['sub_id'] = get_subid_from_slot_index(ad.log, ad, slot) 412 slot_dict[slot]['operator'] = get_operatorname_from_slot_index(ad, slot) 413 ad.log.debug("%s", slot_dict) 414 415 current_data = get_default_data_sub_id(ad) 416 if slot_dict[0]['sub_id'] == current_data: 417 ad.log.info("DDS Switch from %s to %s", slot_dict[0]['operator'], 418 slot_dict[1]['operator']) 419 new_data = slot_dict[1]['sub_id'] 420 new_oper = slot_dict[1]['operator'] 421 else: 422 ad.log.info("DDS Switch from %s to %s", slot_dict[1]['operator'], 423 slot_dict[0]['operator']) 424 new_data = slot_dict[0]['sub_id'] 425 new_oper = slot_dict[0]['operator'] 426 set_subid_for_data(ad, new_data) 427 ad.droid.telephonyToggleDataConnection(True) 428 if get_default_data_sub_id(ad) == new_data: 429 return new_oper 430 else: 431 ad.log.error("DDS Switch Failed") 432 return False 433 434 435def set_dds_on_slot_0(ad): 436 sub_id = get_subid_from_slot_index(ad.log, ad, 0) 437 if sub_id == INVALID_SUB_ID: 438 ad.log.warning("Invalid sub ID at slot 0") 439 return False 440 operator = get_operatorname_from_slot_index(ad, 0) 441 if ad.droid.subscriptionGetDefaultDataSubId() == sub_id: 442 ad.log.info("Current DDS is already on Sub %s(%s)", sub_id, operator) 443 return True 444 ad.log.info("Setting DDS on Sub %s(%s)", sub_id, operator) 445 set_subid_for_data(ad, sub_id) 446 ad.droid.telephonyToggleDataConnection(True) 447 if get_default_data_sub_id(ad) == sub_id: 448 return True 449 else: 450 return False 451 452 453def set_dds_on_slot_1(ad): 454 sub_id = get_subid_from_slot_index(ad.log, ad, 1) 455 if sub_id == INVALID_SUB_ID: 456 ad.log.warning("Invalid sub ID at slot 1") 457 return False 458 operator = get_operatorname_from_slot_index(ad, 1) 459 if ad.droid.subscriptionGetDefaultDataSubId() == sub_id: 460 ad.log.info("Current DDS is already on Sub %s(%s)", sub_id, operator) 461 return True 462 ad.log.info("Setting DDS on Sub %s(%s)", sub_id, operator) 463 set_subid_for_data(ad, sub_id) 464 ad.droid.telephonyToggleDataConnection(True) 465 if get_default_data_sub_id(ad) == sub_id: 466 return True 467 else: 468 return False 469 470 471def set_dds_on_slot(ad, dds_slot): 472 """Switch DDS to given slot. 473 474 Args: 475 ad: android device object. 476 dds_slot: the slot which be set to DDS. 477 0 for pSIM, 478 1 for eSIM port 0, 479 2 for eSIM port 1. 480 481 Returns: 482 True if success, False if fail. 483 """ 484 sub_id = get_subid_from_slot_index(ad.log, ad, dds_slot) 485 if sub_id == INVALID_SUB_ID: 486 ad.log.warning("Invalid sub ID at slot %d", dds_slot) 487 return False 488 operator = get_operatorname_from_slot_index(ad, dds_slot) 489 if ad.droid.subscriptionGetDefaultDataSubId() == sub_id: 490 ad.log.info("Current DDS is already on Sub %s(%s)", sub_id, operator) 491 return True 492 ad.log.info("Setting DDS on Sub %s(%s)", sub_id, operator) 493 set_subid_for_data(ad, sub_id) 494 ad.droid.telephonyToggleDataConnection(True) 495 if get_default_data_sub_id(ad) == sub_id: 496 return True 497 else: 498 return False 499 500 501def set_always_allow_mms_data(ad, sub_id, state=True): 502 """Set always allow mms data on sub_id 503 504 Args: 505 ad: android device object. 506 sub_id: subscription id (integer) 507 state: True or False 508 509 Returns: 510 None 511 """ 512 if any(model in ad.model for model in CHIPSET_MODELS_LIST): 513 ad.log.debug("SKIP telephonySetAlwaysAllowMmsData") 514 else: 515 ad.log.debug("telephonySetAlwaysAllowMmsData %s sub_id %s", state, sub_id) 516 ad.droid.telephonySetAlwaysAllowMmsData(sub_id, state) 517 return True 518 519 520def get_cbrs_and_default_sub_id(ad): 521 """Gets CBRS and Default SubId 522 523 Args: 524 ad: android device object. 525 526 Returns: 527 cbrs_subId 528 default_subId 529 """ 530 cbrs_subid, default_subid = None, None 531 slot_dict = {0: {}, 1: {}} 532 for slot in (0, 1): 533 slot_dict[slot]['sub_id'] = get_subid_from_slot_index( 534 ad.log, ad, slot) 535 slot_dict[slot]['carrier_id'] = get_carrierid_from_slot_index( 536 ad, slot) 537 slot_dict[slot]['operator'] = get_operatorname_from_slot_index( 538 ad, slot) 539 if slot_dict[slot]['carrier_id'] == 2340: 540 cbrs_subid = slot_dict[slot]['sub_id'] 541 else: 542 default_subid = slot_dict[slot]['sub_id'] 543 ad.log.info("Slot %d - Sub %s - Carrier %d - %s", slot, 544 slot_dict[slot]['sub_id'], 545 slot_dict[slot]['carrier_id'], 546 slot_dict[slot]['operator']) 547 if not cbrs_subid: 548 ad.log.error("CBRS sub_id is not ACTIVE") 549 return cbrs_subid, default_subid 550 551 552def get_subid_on_same_network_of_host_ad(ads, host_sub_id=None, type="voice"): 553 ad_host = ads[0] 554 ad_p1 = ads[1] 555 556 try: 557 ad_p2 = ads[2] 558 except: 559 ad_p2 = None 560 561 if not host_sub_id: 562 if type == "sms": 563 host_sub_id = get_outgoing_message_sub_id(ad_host) 564 else: 565 host_sub_id = get_incoming_voice_sub_id(ad_host) 566 host_mcc = ad_host.telephony["subscription"][host_sub_id]["mcc"] 567 host_mnc = ad_host.telephony["subscription"][host_sub_id]["mnc"] 568 p1_sub_id = INVALID_SUB_ID 569 p2_sub_id = INVALID_SUB_ID 570 p1_mcc = None 571 p1_mnc = None 572 p2_mcc = None 573 p2_mnc = None 574 575 for ad in [ad_p1, ad_p2]: 576 if ad: 577 for sub_id in ad.telephony["subscription"]: 578 mcc = ad.telephony["subscription"][sub_id]["mcc"] 579 mnc = ad.telephony["subscription"][sub_id]["mnc"] 580 581 if ad == ad_p1: 582 if p1_sub_id == INVALID_SUB_ID: 583 p1_sub_id = sub_id 584 if not p1_mcc: 585 p1_mcc = mcc 586 if not p1_mnc: 587 p1_mnc = mnc 588 elif ad == ad_p2: 589 if p2_sub_id == INVALID_SUB_ID: 590 p2_sub_id = sub_id 591 if not p2_mcc: 592 p2_mcc = mcc 593 if not p2_mnc: 594 p2_mnc = mnc 595 596 if mcc == host_mcc and mnc == host_mnc: 597 if ad == ad_p1: 598 p1_sub_id = sub_id 599 p1_mcc = mcc 600 p1_mnc = mnc 601 602 elif ad == ad_p2: 603 p2_sub_id = sub_id 604 p2_mcc = mcc 605 p2_mnc = mnc 606 607 return host_sub_id, p1_sub_id, p2_sub_id 608 609 610def get_slot_index_from_subid(ad, sub_id): 611 try: 612 info = ad.droid.subscriptionGetSubInfoForSubscriber(sub_id) 613 return info['simSlotIndex'] 614 except KeyError: 615 return INVALID_SIM_SLOT_INDEX 616 617 618def get_slot_index_from_data_sub_id(ad): 619 """Get slot index from given sub ID for data 620 621 Args: 622 ad: Android object 623 624 Returns: 625 0 for pSIM or 1 for eSIM. Otherwise -1 will be returned. 626 """ 627 data_sub_id = get_default_data_sub_id(ad) 628 sub_info = ad.droid.subscriptionGetAllSubInfoList() 629 for info in sub_info: 630 if info['subscriptionId'] == data_sub_id: 631 return info['simSlotIndex'] 632 return INVALID_SUB_ID 633 634 635def get_slot_index_from_voice_sub_id(ad): 636 """Get slot index from the current voice sub ID. 637 638 Args: 639 ad: android object 640 641 Returns: 642 0: pSIM 643 1: eSIM 644 INVALID_SUB_ID (-1): if no sub ID is equal to current voice sub ID. 645 """ 646 voice_sub_id = get_incoming_voice_sub_id(ad) 647 sub_info = ad.droid.subscriptionGetAllSubInfoList() 648 for info in sub_info: 649 if info['subscriptionId'] == voice_sub_id: 650 return info['simSlotIndex'] 651 return INVALID_SUB_ID 652 653 654def get_all_sub_id(ad): 655 """Return all valid subscription IDs. 656 657 Args: 658 ad: Android object 659 660 Returns: 661 List containing all valid subscription IDs. 662 """ 663 sub_id_list = [] 664 sub_info = ad.droid.subscriptionGetAllSubInfoList() 665 for info in sub_info: 666 if info['simSlotIndex'] != INVALID_SUB_ID: 667 sub_id_list.append(info['subscriptionId']) 668 669 return sub_id_list