1#!/usr/bin/env python3.4 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 Basic script for managing a JSON "database" file of SIM cards. 18 It will look at the list of attached devices, and add their SIMs to a 19 database. 20 We expect to add much more functionality in the future. 21""" 22 23import argparse 24import json 25import acts.controllers.android_device as android_device 26import acts_contrib.test_utils.tel.tel_defines as tel_defines 27import acts_contrib.test_utils.tel.tel_lookup_tables as tel_lookup_tables 28import acts_contrib.test_utils.tel.tel_test_utils as tel_test_utils 29 30 31def get_active_sim_list(verbose_warnings=False): 32 """ Get a dictionary of active sims across phones 33 34 Args: verbose_warnings - print warnings as issues are encountered if True 35 36 Returns: 37 A dictionary with keys equivalent to the ICCIDs of each SIM containing 38 information about that SIM 39 """ 40 active_list = {} 41 droid_list = android_device.get_all_instances() 42 for droid_device in droid_list: 43 droid = droid_device.get_droid(False) 44 45 sub_info_list = droid.subscriptionGetActiveSubInfoList() 46 if not sub_info_list: 47 if verbose_warnings: 48 print('No Valid Sim in {} {}! SimState = {}'.format( 49 droid_device.model, droid_device.serial, droid.telephonyGetSimState())) 50 continue 51 52 for sub_info in sub_info_list: 53 print(sub_info) 54 iccid = sub_info['iccId'] 55 if not sub_info['iccId']: 56 continue 57 58 active_list[iccid] = {} 59 current = active_list[iccid] 60 current['droid_serial'] = droid_device.serial 61 62 sub_id = sub_info['subscriptionId'] 63 64 try: 65 plmn_id = droid.telephonyGetSimOperatorForSubscription(sub_id) 66 current[ 67 'operator'] = tel_lookup_tables.operator_name_from_plmn_id( 68 plmn_id) 69 except KeyError: 70 if verbose_warnings: 71 print('Unknown Operator {}'.format( 72 droid.telephonyGetSimOperatorForSubscription(sub_id))) 73 current['operator'] = '' 74 75 # TODO: add actual capability determination to replace the defaults 76 current['capability'] = ['voice', 'ims', 'volte', 'vt', 'sms', 77 'tethering', 'data'] 78 79 phone_num = droid.telephonyGetLine1NumberForSubscription(sub_id) 80 if not phone_num: 81 if verbose_warnings: 82 print('Please manually add a phone number for {}\n'.format( 83 iccid)) 84 current['phone_num'] = '' 85 else: 86 # No need to set phone number formatter for South Korea carriers 87 if (current['operator'] == tel_defines.CARRIER_SKT or 88 current['operator'] == tel_defines.CARRIER_KT or 89 current['operator'] == tel_defines.CARRIER_LG_UPLUS): 90 current['phone_num'] = \ 91 tel_test_utils.phone_number_formatter(phone_num) 92 else: 93 current['phone_num'] = \ 94 tel_test_utils.phone_number_formatter( 95 phone_num, 96 tel_defines.PHONE_NUMBER_STRING_FORMAT_11_DIGIT) 97 return active_list 98 99 100def add_sims(sim_card_file=None): 101 if not sim_card_file: 102 print('Error: file name is None.') 103 return False 104 try: 105 f = open(sim_card_file, 'r') 106 simconf = json.load(f) 107 f.close() 108 except FileNotFoundError: 109 simconf = {} 110 111 active_sims = get_active_sim_list(True) 112 113 if not active_sims: 114 print('No active SIMs, exiting') 115 return False 116 117 file_write_required = False 118 119 for iccid in active_sims.keys(): 120 # Add new entry if not exist 121 if iccid in simconf: 122 print('Declining to add a duplicate entry: {}'.format(iccid)) 123 #TODO: Add support for "refreshing" an entry 124 continue 125 126 simconf[iccid] = {} 127 current = simconf[iccid] 128 file_write_required = True 129 130 current['operator'] = active_sims[iccid]['operator'] 131 current['capability'] = active_sims[iccid]['capability'] 132 current['phone_num'] = active_sims[iccid]['phone_num'] 133 134 if file_write_required: 135 f = open(sim_card_file, 'w') 136 json.dump(simconf, f, indent=4, sort_keys=True) 137 f.close() 138 return True 139 140 141def prune_sims(sim_card_file=None): 142 try: 143 f = open(sim_card_file, 'r') 144 simconf = json.load(f) 145 f.close() 146 except FileNotFoundError: 147 print('File {} not found.'.format(sim_card_file if sim_card_file else 148 '<UNSPECIFIED>')) 149 return False 150 151 simconf_list = list(simconf.keys()) 152 active_list = get_active_sim_list().keys() 153 delete_list = list(set(simconf_list).difference(set(active_list))) 154 155 print('active phones: {}'.format(active_list)) 156 157 file_write_required = False 158 159 if len(delete_list) > 0: 160 for sim in delete_list: 161 # prune 162 print('Deleting the SIM entry: ', sim) 163 del simconf[sim] 164 file_write_required = True 165 else: 166 print('No entries to prune') 167 168 if file_write_required: 169 f = open(sim_card_file, 'w') 170 json.dump(simconf, f, indent=4, sort_keys=True) 171 f.close() 172 return True 173 174 175def dump_sims(): 176 active_list = get_active_sim_list() 177 output_format = '{:32.32}{:20.20}{:12.12}{:10.10}' 178 if not active_list: 179 print('No active devices with sims!') 180 return False 181 182 print(output_format.format('ICCID', 'Android SN', 'Phone #', 'Carrier')) 183 for iccid in active_list.keys(): 184 print( 185 output_format.format( 186 str(iccid), str(active_list[iccid]['droid_serial']), str( 187 active_list[iccid]['phone_num']), str(active_list[iccid][ 188 'operator']))) 189 190 191if __name__ == '__main__': 192 193 parser = argparse.ArgumentParser(description=( 194 'Script to generate, augment and prune' 195 ' SIM list')) 196 parser.add_argument( 197 '-f', 198 '--file', 199 default='./simcard_list.json', 200 help='json file path', 201 type=str) 202 group = parser.add_mutually_exclusive_group() 203 group.add_argument( 204 '-a', 205 '--append', 206 help='(default) Append to the list of SIM entries', 207 action='store_true') 208 group.add_argument( 209 '-p', 210 '--prune', 211 help='Prune the list of SIM entries', 212 action='store_true') 213 group.add_argument( 214 '-d', 215 '--dump', 216 help='Dump a list of SIMs from devices', 217 action='store_true') 218 219 args = parser.parse_args() 220 221 if args.prune: 222 prune_sims(args.file) 223 elif args.dump: 224 dump_sims() 225 # implies either no arguments or a && !p 226 elif not args.prune and not args.dump: 227 add_sims(args.file) 228""" 229Usage Examples 230 231---------------------------------------------------------------- 232p3 manage_sim.py -h 233usage: manage_sim.py [-h] [-f F] [-a | -p] 234 235Script to generate, augment and prune SIM list 236 237optional arguments: 238 -h, --help show this help message and exit 239 -f F, --file F name for json file 240 -a append to the list of SIM entries 241 -d dump a list of SIMs from all devices 242 -p prune the list of SIM entries 243 244---------------------------------------------------------------- 245p3 manage_sim.py -f ./simcard_list.json -p 246 OR 247p3 manage_sim.py -p 248 249Namespace(a=False, f='./simcard_list.json', p=True) 250add_sims: 8901260222780922759 251Please manually add a phone number for 8901260222780922759 252 253active phones: 1 254 ['8901260222780922759'] 255Deleting the SIM entry: 89148000001280331488 256: 257: 258Deleting the SIM entry: 89014103277559059196 259 260---------------------------------------------------------------- 261p3 manage_sim.py -f ./simcard_list.json -a 262 OR 263p3 manage_sim.py -a 264 265Namespace(a=True, f='./simcard_list.json', p=False) 266add_sims: 8901260222780922759 267Please manually add a phone number for 8901260222780922759 268 269---------------------------------------------------------------- 270""" 271