#!/usr/bin/env python3.4 # # Copyright 2017 - Google # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """ Test Script for Project Fi Setting """ import time from acts.test_decorators import test_tracker_info from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest from acts.test_utils.tel.tel_defines import CARRIER_SPT from acts.test_utils.tel.tel_defines import CARRIER_TMO from acts.test_utils.tel.tel_defines import CARRIER_USCC from acts.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id from acts.test_utils.tel.tel_test_utils import abort_all_tests from acts.test_utils.tel.tel_test_utils import ensure_phone_subscription from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected from acts.test_utils.tel.tel_test_utils import is_sim_ready from acts.test_utils.tel.tel_test_utils import log_screen_shot from acts.test_utils.tel.tel_test_utils import multithread_func from acts.test_utils.tel.tel_test_utils import refresh_droid_config from acts.test_utils.tel.tel_test_utils import send_dialer_secret_code from acts.test_utils.tel.tel_test_utils import wait_for_state CARRIER_AUTO = "auto" _CARRIER_DIALER_CODE_LOOKUP = { CARRIER_AUTO: '342886', CARRIER_SPT: '34777', CARRIER_TMO: '34866', CARRIER_USCC: '34872' } _SWITCHING_PREF_FILE = ( '/data/data/com.google.android.apps.tycho/shared_prefs/switching.xml') _INTENT_FLAGS = int(0x00008000 | 0x10000000 | 0x00080000 | 0x00020000) _TYCHO_PKG = 'com.google.android.apps.tycho' _MAX_WAIT_TIME = 600 class TychoClassId(object): """Tycho Activity/Service Classnames.""" # Activities CARRIER_SETUP = 'CarrierSetupEntryPointTrampoline' INIT_ACTIVITY = 'InitActivity' # Services SYNC_SERVICE = 'services.SyncService' ACTIVATE_SUPER_NETWORK_SERVICE = 'services.SuperNetworkConfigurationService' class ActionTypeId(object): """Andorid Action Type to trigger events.""" MAIN = 'android.intent.action.MAIN' MASTER_CLEAR_NOTIFICATION = 'android.intent.action.MASTER_CLEAR_NOTIFICATION' TYCHO_ACTIVATE_SUPER_NETWORK = ( 'com.google.android.apps.tycho.ActionType.ACTIVATE_SUPER_NETWORK') class TelLiveProjectFiTest(TelephonyBaseTest): def setup_class(self): self.wifi_network_ssid = self.user_params.get( "wifi_network_ssid") or self.user_params.get( "wifi_network_ssid_2g") or self.user_params.get( "wifi_network_ssid_5g") self.wifi_network_pass = self.user_params.get( "wifi_network_pass") or self.user_params.get( "wifi_network_pass_2g") or self.user_params.get( "wifi_network_ssid_5g") def _add_google_account(self, ad, retries=3): for _ in range(3): ad.ensure_screen_on() output = ad.adb.shell( 'am instrument -w -e account "%s@gmail.com" -e password ' '"%s" -e sync true -e wait-for-checkin false ' 'com.google.android.tradefed.account/.AddAccount' % (ad.user_account, ad.user_password)) if "result=SUCCESS" in output: ad.log.info("google account is added successfully") return True ad.log.error("Fail to add google account due to %s", output) return False def _remove_google_account(self, ad, retries=3): if not ad.is_apk_installed("com.google.android.tradefed.account" ) and self.user_params.get("account_util"): account_util = self.user_params["account_util"] if isinstance(account_util, list): account_util = account_util[0] ad.log.info("Install account_util %s", account_util) ad.ensure_screen_on() ad.adb.install("-r %s" % account_util, timeout=180) if not ad.is_apk_installed("com.google.android.tradefed.account"): ad.log.error( "com.google.android.tradefed.account is not installed") return False for _ in range(3): ad.ensure_screen_on() output = ad.adb.shell( 'am instrument -w ' 'com.google.android.tradefed.account/.RemoveAccounts') if "result=SUCCESS" in output: ad.log.info("google account is removed successfully") return True ad.log.error("Fail to remove google account due to %s", output) return False def _install_account_util(self, ad): account_util = self.user_params["account_util"] if isinstance(account_util, list): account_util = account_util[0] ad.log.info("Install account_util %s", account_util) ad.ensure_screen_on() ad.adb.install("-r %s" % account_util, timeout=180) time.sleep(3) if not ad.is_apk_installed("com.google.android.tradefed.account"): ad.log.info("com.google.android.tradefed.account is not installed") return False return True def _account_registration(self, ad): if hasattr(ad, "user_account"): ad.exit_setup_wizard() if not ad.is_apk_installed("com.google.android.tradefed.account" ) and self.user_params.get( "account_util"): for _ in range(2): if self._install_account_util(ad): break else: ad.log.error( "Fail to install com.google.android.tradefed.account") return False ad.force_stop_apk(_TYCHO_PKG) if not ensure_wifi_connected(self.log, ad, self.wifi_network_ssid, self.wifi_network_pass): ad.log.error("Failed to connect to wifi") return False ad.log.info("Add google account") if not self._add_google_account(ad): ad.log.error("Failed to add google account") return False ad.adb.shell( 'am instrument -w -e account "%s@gmail.com" -e password ' '"%s" -e sync true -e wait-for-checkin false ' 'com.google.android.tradefed.account/.AddAccount' % (ad.user_account, ad.user_password)) ad.log.info("Enable and activate tycho apk") ad.adb.shell('pm enable %s' % _TYCHO_PKG) self.activate_fi_account(ad) if not self.check_project_fi_activated(ad): ad.log.error("Fail to activate Fi account") return False elif "Fi Network" in ad.adb.getprop("gsm.sim.operator.alpha"): ad.log.error("Google account is not provided for Fi Network") return False if not ensure_phone_subscription(self.log, ad): ad.log.error("Unable to find a valid subscription!") return False refresh_droid_config(self.log, ad) return True def start_service(self, ad, package, service_id, extras, action_type): """Starts the specified service. Args: ad: (android_device.AndroidDevice) device to start activity on package: (str) the package to start the service from service_id: (str) service to start extras: (dict) extras needed to specify with the activity id action_type: The action type id to create the intent """ ad.log.info('Starting service %s/.%s.', package, service_id) intent = ad.droid.makeIntent(action_type, None, None, extras, [ 'android.intent.category.DEFAULT' ], package, package + '.' + service_id, _INTENT_FLAGS) ad.droid.startServiceIntent(intent) def start_activity(self, ad, package, activity_id, extras=None): """Starts the specified activity. Args: ad: (android_device.AndroidDevice) device to start activity on package: (str) the package to start activity_id: (str) activity to start extras: (dict) extras needed to specify with the activity id """ ad.log.info('Starting activity %s/.%s.', package, activity_id) intent = ad.droid.makeIntent(ActionTypeId.MAIN, None, None, extras, [ 'android.intent.category.LAUNCHER' ], package, package + '.' + activity_id, _INTENT_FLAGS) ad.droid.startActivityIntent(intent, False) def activate_fi_account(self, ad): """Start Tycho InitActivity. For in-app Tycho activition (post-SUW tests), Tycho does not automatically trigger OMADM process. This method is used to start Tycho InitActivity before launching super network activation. The device will finally stay on Sprint network if everything goes well. Args: ad: Android device need to start Tycho InitActivity. """ extra = {'in_setup_wizard': False, 'force_show_account_chooser': False} self.start_activity(ad, _TYCHO_PKG, TychoClassId.INIT_ACTIVITY, extra) for _ in range(30): ad.send_keycode("WAKEUP") time.sleep(1) current_window = ad.get_my_current_focus_window() log_screen_shot(ad, self.test_name) if 'SwitchConfirmDialogActivity' in current_window: ad.log.info("In Switch Confirmation Dialog") if ad.adb.getprop("ro.build.version.release")[0] not in ("8", "O"): ad.send_keycode("TAB") ad.send_keycode("TAB") ad.send_keycode("ENTER") time.sleep(10) elif 'tycho.InitActivity' in current_window: ad.log.info("In Tycho InitActivity") ad.send_keycode("TAB") ad.send_keycode("TAB") ad.send_keycode("ENTER") time.sleep(10) elif 'tycho.AccountChooserActivity' in current_window: ad.send_keycode("ENTER") else: ad.log.info("Finished activation process") return def check_project_fi_activated(self, ad): for _ in range(20): if is_sim_ready(self.log, ad) and ( ad.droid.telephonyGetSimOperatorName() == "Fi Network"): ad.log.info("SIM state is READY, SIM operator is Fi") return True time.sleep(5) def start_tycho_activation(self, ad): """Start the Tycho client and register to cellular network. Starts Tycho within SUW: - Tycho is expected to follow the in-SUW work flow: - Tycho will perform TychoInit, handshake to server, account configuration, etc - If successful, Tycho will trigger a switch to Sprint Network - If successful, Tycho will start OMA-DM activation sessions The device will finally stay on Sprint network if everything goes well. Args: ad: Android device need to start Tycho activation. """ extra = {'device_setup': True, 'has_account': True} self.start_activity(ad, _TYCHO_PKG, TychoClassId.CARRIER_SETUP, extra) def start_super_network_activation(self, ad): """Start the Super-Network activation. For in-app Tycho activition (post-SUW tests), this method starts super-network activation after Tycho is initialized. The device will finally stay on Sprint network if everything goes well. Args: ad: Android device need to start Tycho super network activation. """ extra = {'in_setup_wizard': False, 'is_interactive': True} self.start_service(ad, _TYCHO_PKG, TychoClassId.ACTIVATE_SUPER_NETWORK_SERVICE, extra, ActionTypeId.TYCHO_ACTIVATE_SUPER_NETWORK) def get_active_carrier(self, ad): """Gets the active carrier profile value from the device. Args: ad: An AndroidDevice Object. Returns: (string) A key from the CARRIER_TO_MCC_MNC map representing the active carrier. Raises: KeyError: when an mcc_mnc code reported by the device is not a recognized Fi partner carrier. """ mcc_mnc = ad.droid.telephonyGetSimOperator() if not mcc_mnc: return "UNKNOWN" try: return operator_name_from_plmn_id(mcc_mnc) except KeyError: ad.log.error('Unknown Mobile Country Code/Mobile Network Code %s', mcc_mnc) raise def switch_sim(self, ad): """Requests switch between physical sim and esim. Args: ad: An AndroidDevice Object. timeout: (optional -- integer) the number of seconds in which a switch should be completed. Raises: Error: whenever a device is not set to the desired carrier within the timeout window. """ old_sim_operator = ad.droid.telephonyGetSimOperatorName() ad.log.info("Before SIM switch, SIM operator = %s", old_sim_operator) send_dialer_secret_code(ad, "794824746") time.sleep(10) new_sim_operator = ad.droid.telephonyGetSimOperatorName() ad.log.info("After SIM switch, SIM operator = %s", new_sim_operator) refresh_droid_config(self.log, ad) return old_sim_operator != new_sim_operator def set_active_carrier(self, ad, carrier, timeout=_MAX_WAIT_TIME, check_interval=10): """Requests an active carrier to be set on the device sim. If switching to a different carrier, after the switch is completed auto-switching will be disabled. To re-enable, call enable_auto_switching. Args: ad: An AndroidDevice Object. carrier: (carrier_constants.Carrier) Which carrier to switch to. timeout: (optional -- integer) the number of seconds in which a switch should be completed. Raises: Error: whenever a device is not set to the desired carrier within the timeout window. """ # If there's no need to switch, then don't. max_time = timeout while max_time >= 0: if self.is_ready_to_make_carrier_switch(ad): break time.sleep(check_interval) max_time -= check_interval else: ad.log.error("Device stays in carrier switch lock state") return False if carrier == CARRIER_AUTO: send_dialer_secret_code(ad, _CARRIER_DIALER_CODE_LOOKUP[carrier]) return True old_carrier = self.get_active_carrier(ad) if carrier == old_carrier: ad.log.info('Already on %s, so no need to switch', carrier) return True # Start switch on device, using events to verify that the switch starts. ad.log.info('Initiating unsolicited switch from %s to %s.', old_carrier, carrier) send_dialer_secret_code(ad, _CARRIER_DIALER_CODE_LOOKUP[carrier]) return self.wait_for_carrier_switch_completed( ad, carrier, timeout=timeout, check_interval=check_interval) def is_switching_silent(self, ad): """Checks if Tycho switching controller is in silent mode. Note that silent mode is a sign of airplane mode, not of a switching lock. Args: ad: An AndroidDevice Object. Returns: A Boolean True if the preferences file reports True, False otherwise. """ return "isInSilentMode\" value=\"true" in ad.adb.shell( "cat %s | grep isInSilentMode" % _SWITCHING_PREF_FILE, ignore_status=True) def is_switching_locked(self, ad): """Checks if Tycho switching controller is locked. Args: ad: An AndroidDevice Object. Returns: A Boolean True if the switching controller is locked for any reason, False otherwise. """ return "switchingInProgress\" value=\"true" in ad.adb.shell( "cat %s | grep switchingInProgress" % _SWITCHING_PREF_FILE) def is_ready_to_make_carrier_switch(self, ad): """Checks if device is ready to make carrier switch. Args: ad: An AndroidDevice Object. Returns: A Boolean True if it is ready to make switch, False otherwise. """ # Check Tycho switching controller states. if self.is_switching_silent(ad): ad.log.info( "Cannot make carrier switch: SwitchingController is in silent " "mode!") return False if self.is_switching_locked(ad): ad.log.info( "Cannot make carrier switch: SwitchingController is locked!") return False if self.is_carrier_switch_in_progress(ad): ad.log.info("Cannot make carrier switch: Switch in progress!") return False return True def is_carrier_switch_in_progress(self, ad): """Checks if Tycho says that a switch is currently in progress. Args: ad: An AndroidDevice Object. Returns: A Boolean True if the preferences file reports True, False otherwise. """ switching_preferences = ad.adb.shell("cat %s" % _SWITCHING_PREF_FILE) return 'InProgress\" value=\"true' in switching_preferences def check_network_carrier(self, ad, carrier): current_carrier = self.get_active_carrier(ad) ad.log.info("Current network carrier is %s", current_carrier) is_in_switch = self.is_carrier_switch_in_progress(ad) ad.log.info("Device in carrier switch progress mode") return current_carrier == carrier and is_in_switch def wait_for_carrier_switch_completed(self, ad, carrier, timeout=_MAX_WAIT_TIME, check_interval=10): """Wait for carrier switch to complete. This function waits for a carrier switch to complete by monitoring the Tycho switching controller preference file. Args: ad: An Android device object. carrier: The target carrier network to switch to. timeout: (integer) Time wait for switch to complete. Return: True or False for successful/unsuccessful switch. """ check_args = [ad, carrier] if wait_for_state(self.check_network_carrier, True, check_interval, timeout, *check_args): ad.log.info("Switched to %s successfully", carrier) ad.send_keycode("ENTER") return True else: ad.log.error("Carrier is %s. Fail to switch to %s", self.get_active_carrier(ad), carrier) return False def operator_network_switch(self, ad, carrier): if ad.droid.telephonyGetSimOperatorName() == "Fi Network": for i in range(3): if self.set_active_carrier(ad, carrier): break elif i == 2: ad.log.error("Failed to switch to %s", carrier) return False if not ensure_phone_subscription(self.log, ad): ad.log.error("Unable to find a valid subscription!") return False refresh_droid_config(self.log, ad) return True def network_switch_test(self, carrier): tasks = [(self.operator_network_switch, [ad, carrier]) for ad in self.android_devices] if not multithread_func(self.log, tasks): abort_all_tests(self.log, "Unable to switch to network %s" % carrier) return True """ Tests Begin """ @test_tracker_info(uuid="4d92318e-4980-471a-882b-3136c5dda384") @TelephonyBaseTest.tel_test_wrap def test_project_fi_account_activation(self): """Test activate Fi account. Returns: True if success. False if failed. """ tasks = [(self._account_registration, [ad]) for ad in self.android_devices] if not multithread_func(self.log, tasks): abort_all_tests(self.log, "Unable to activate Fi account!") return True @test_tracker_info(uuid="6bfbcc1d-e318-4964-bf36-5b82f086860d") @TelephonyBaseTest.tel_test_wrap def test_switch_to_tmobile_network(self): """Test switch to tmobile network. Returns: True if success. False if failed. """ return self.network_switch_test(CARRIER_TMO) @test_tracker_info(uuid="4f27944d-f3c5-423d-b0c5-5c66dbb98376") @TelephonyBaseTest.tel_test_wrap def test_switch_to_sprint_network(self): """Test switch to tmobile network. Returns: True if success. False if failed. """ return self.network_switch_test(CARRIER_SPT) @test_tracker_info(uuid="5f30c9bd-b79e-4805-aa46-7855ed9023f0") @TelephonyBaseTest.tel_test_wrap def test_switch_to_uscc_network(self): """Test switch to tmobile network. Returns: True if success. False if failed. """ return self.network_switch_test(CARRIER_USCC) @test_tracker_info(uuid="0b062751-d59d-420e-941e-3ffa02aea0d5") @TelephonyBaseTest.tel_test_wrap def test_switch_to_auto_network(self): """Test switch to auto network selection. Returns: True if success. False if failed. """ return self.network_switch_test(CARRIER_AUTO) @test_tracker_info(uuid="13c5f080-69bf-42fd-86ed-c67b1984c347") @TelephonyBaseTest.tel_test_wrap def test_switch_between_sim(self): """Test switch between physical sim and esim. Returns: True if success. False if failed. """ for ad in self.android_devices: self.switch_sim(ad) @test_tracker_info(uuid="") @TelephonyBaseTest.tel_test_wrap def test_remove_google_account(self): for ad in self.android_devices: self._remove_google_account(ad) """ Tests End """