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 vebose_warnings: 71 print('Unknown Operator {}'.format( 72 droid.telephonyGetSimOperator())) 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 current['phone_num'] = tel_test_utils.phone_number_formatter( 87 phone_num, tel_defines.PHONE_NUMBER_STRING_FORMAT_11_DIGIT) 88 return active_list 89 90 91def add_sims(sim_card_file=None): 92 if not sim_card_file: 93 print('Error: file name is None.') 94 return False 95 try: 96 f = open(sim_card_file, 'r') 97 simconf = json.load(f) 98 f.close() 99 except FileNotFoundError: 100 simconf = {} 101 102 active_sims = get_active_sim_list(True) 103 104 if not active_sims: 105 print('No active SIMs, exiting') 106 return False 107 108 file_write_required = False 109 110 for iccid in active_sims.keys(): 111 # Add new entry if not exist 112 if iccid in simconf: 113 print('Declining to add a duplicate entry: {}'.format(iccid)) 114 #TODO: Add support for "refreshing" an entry 115 continue 116 117 simconf[iccid] = {} 118 current = simconf[iccid] 119 file_write_required = True 120 121 current['operator'] = active_sims[iccid]['operator'] 122 current['capability'] = active_sims[iccid]['capability'] 123 current['phone_num'] = active_sims[iccid]['phone_num'] 124 125 if file_write_required: 126 f = open(sim_card_file, 'w') 127 json.dump(simconf, f, indent=4, sort_keys=True) 128 f.close() 129 return True 130 131 132def prune_sims(sim_card_file=None): 133 try: 134 f = open(sim_card_file, 'r') 135 simconf = json.load(f) 136 f.close() 137 except FileNotFoundError: 138 print('File {} not found.'.format(sim_card_file if sim_card_file else 139 '<UNSPECIFIED>')) 140 return False 141 142 simconf_list = list(simconf.keys()) 143 active_list = get_active_sim_list().keys() 144 delete_list = list(set(simconf_list).difference(set(active_list))) 145 146 print('active phones: {}'.format(active_list)) 147 148 file_write_required = False 149 150 if len(delete_list) > 0: 151 for sim in delete_list: 152 # prune 153 print('Deleting the SIM entry: ', sim) 154 del simconf[sim] 155 file_write_required = True 156 else: 157 print('No entries to prune') 158 159 if file_write_required: 160 f = open(sim_card_file, 'w') 161 json.dump(simconf, f, indent=4, sort_keys=True) 162 f.close() 163 return True 164 165 166def dump_sims(): 167 active_list = get_active_sim_list() 168 output_format = '{:32.32}{:20.20}{:12.12}{:10.10}' 169 if not active_list: 170 print('No active devices with sims!') 171 return False 172 173 print(output_format.format('ICCID', 'Android SN', 'Phone #', 'Carrier')) 174 for iccid in active_list.keys(): 175 print( 176 output_format.format( 177 str(iccid), str(active_list[iccid]['droid_serial']), str( 178 active_list[iccid]['phone_num']), str(active_list[iccid][ 179 'operator']))) 180 181 182if __name__ == '__main__': 183 184 parser = argparse.ArgumentParser(description=( 185 'Script to generate, augment and prune' 186 ' SIM list')) 187 parser.add_argument( 188 '-f', 189 '--file', 190 default='./simcard_list.json', 191 help='json file path', 192 type=str) 193 group = parser.add_mutually_exclusive_group() 194 group.add_argument( 195 '-a', 196 '--append', 197 help='(default) Append to the list of SIM entries', 198 action='store_true') 199 group.add_argument( 200 '-p', 201 '--prune', 202 help='Prune the list of SIM entries', 203 action='store_true') 204 group.add_argument( 205 '-d', 206 '--dump', 207 help='Dump a list of SIMs from devices', 208 action='store_true') 209 210 args = parser.parse_args() 211 212 if args.prune: 213 prune_sims(args.file) 214 elif args.dump: 215 dump_sims() 216 # implies either no arguments or a && !p 217 elif not args.prune and not args.dump: 218 add_sims(args.file) 219""" 220Usage Examples 221 222---------------------------------------------------------------- 223p3 manage_sim.py -h 224usage: manage_sim.py [-h] [-f F] [-a | -p] 225 226Script to generate, augment and prune SIM list 227 228optional arguments: 229 -h, --help show this help message and exit 230 -f F, --file F name for json file 231 -a append to the list of SIM entries 232 -d dump a list of SIMs from all devices 233 -p prune the list of SIM entries 234 235---------------------------------------------------------------- 236p3 manage_sim.py -f ./simcard_list.json -p 237 OR 238p3 manage_sim.py -p 239 240Namespace(a=False, f='./simcard_list.json', p=True) 241add_sims: 8901260222780922759 242Please manually add a phone number for 8901260222780922759 243 244active phones: 1 245 ['8901260222780922759'] 246Deleting the SIM entry: 89148000001280331488 247: 248: 249Deleting the SIM entry: 89014103277559059196 250 251---------------------------------------------------------------- 252p3 manage_sim.py -f ./simcard_list.json -a 253 OR 254p3 manage_sim.py -a 255 256Namespace(a=True, f='./simcard_list.json', p=False) 257add_sims: 8901260222780922759 258Please manually add a phone number for 8901260222780922759 259 260---------------------------------------------------------------- 261""" 262