Script changes to support Google Fi lab tests

TelLabProjectFiTest.py -- Modified the TelLiveProjectFiTest.py
from Tel/Live and created a new script in the Tel/Lab to support
the Lab callbox testing.

md8475a.py / anrtisu_utils.py - Has changes to support Google Fi
SIM profiles for TMO / SPR & USCC.

TelLabCmasTest.py / TelLabEtwsTest.py  -- Added methods to
change the SIM profiles between TMO / SPR & USCC.

Bug: 127582302
Test: Locally tested the scripts with the callbox. Ran the scripts to
switch the  profile to TMO > ran CMAS / ETWS tests > switched to
SPR / USCC > ran the CMAS / ETWS tests again.

Change-Id: If4b21e204c4203833d519e456180352e0d89a9fd
diff --git a/acts/tests/google/tel/lab/TelLabCmasTest.py b/acts/tests/google/tel/lab/TelLabCmasTest.py
index dc1d666..8a48c64 100644
--- a/acts/tests/google/tel/lab/TelLabCmasTest.py
+++ b/acts/tests/google/tel/lab/TelLabCmasTest.py
@@ -197,6 +197,24 @@
             return False
         return True
 
+    def test_carrier_tmobile(self):
+        """ Sets the Carrier to TMO.
+        Returns: None
+        """
+        setattr(self.ad, "sim_card", "FiTMO")
+
+    def test_carrier_sprint(self):
+        """ Sets the Carrier to SPR.
+        Returns: None
+        """
+        setattr(self.ad, "sim_card", "FiSPR")
+
+    def test_carrier_uscc(self):
+        """ Sets the Carrier to USCC.
+        Returns: None
+        """
+        setattr(self.ad, "sim_card", "FiUSCC")
+
     """ Tests Begin """
 
     @test_tracker_info(uuid="e5ddf562-e94b-4b58-bc7d-6635c01f290e")
diff --git a/acts/tests/google/tel/lab/TelLabEtwsTest.py b/acts/tests/google/tel/lab/TelLabEtwsTest.py
index 59e12a0..5eff288 100644
--- a/acts/tests/google/tel/lab/TelLabEtwsTest.py
+++ b/acts/tests/google/tel/lab/TelLabEtwsTest.py
@@ -153,6 +153,24 @@
             return False
         return True
 
+    def test_carrier_tmobile(self):
+        """ Sets the Carrier to TMO.
+        Returns: None
+        """
+        setattr(self.ad, "sim_card", "FiTMO")
+
+    def test_carrier_sprint(self):
+        """ Sets the Carrier to SPR.
+        Returns: None
+        """
+        setattr(self.ad, "sim_card", "FiSPR")
+
+    def test_carrier_uscc(self):
+        """ Sets the Carrier to USCC.
+        Returns: None
+        """
+        setattr(self.ad, "sim_card", "FiUSCC")
+
     """ Tests Begin """
 
     @test_tracker_info(uuid="af4a00d0-9a91-45d5-9f65-9541e64a57f2")
diff --git a/acts/tests/google/tel/lab/TelLabProjectFiTest.py b/acts/tests/google/tel/lab/TelLabProjectFiTest.py
new file mode 100644
index 0000000..6a3a979
--- /dev/null
+++ b/acts/tests/google/tel/lab/TelLabProjectFiTest.py
@@ -0,0 +1,704 @@
+#!/usr/bin/env python3
+#
+#   Copyright 2016 - The Android Open Source Project
+#
+#   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.
+"""
+Fi Switching Methods 
+"""
+import time
+from acts.controllers.anritsu_lib._anritsu_utils import AnritsuError
+from acts.controllers.anritsu_lib.md8475a import CBCHSetup
+from acts.controllers.anritsu_lib.md8475a import CTCHSetup
+from acts.controllers.anritsu_lib.md8475a import MD8475A
+from acts.test_utils.tel.anritsu_utils import cb_serial_number
+from acts.test_utils.tel.anritsu_utils import set_system_model_lte
+from acts.test_utils.tel.anritsu_utils import set_usim_parameters
+from acts.test_utils.tel.anritsu_utils import set_post_sim_params
+from acts.test_utils.tel.tel_test_utils import \
+    ensure_preferred_network_type_for_subscription
+from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
+from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts.test_utils.tel.tel_test_utils import start_qxdm_loggers
+from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
+from acts.test_utils.tel.tel_defines import RAT_FAMILY_LTE
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.tel.tel_defines import RAT_LTE
+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 reboot_device
+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 toggle_airplane_mode_by_adb
+from acts.test_utils.tel.tel_test_utils import wait_for_state
+from acts.test_utils.tel.tel_test_utils import add_google_account
+from acts.test_utils.tel.tel_test_utils import remove_google_account
+
+WAIT_TIME_BETWEEN_REG_AND_MSG = 15  # default 15 sec
+CARRIER = None
+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 = 120
+_TYCHO_VERBOSE_LOGGING_CMDS = [
+    "setprop log.tag.Tycho VERBOSE",
+    "CLASSPATH=/system/framework/am.jar su root app_process "
+    "/system/bin com.android.commands.am.Am broadcast -a "
+    "com.google.gservices.intent.action.GSERVICES_OVERRIDE "
+    "-e tycho.enable_request_logging true",
+    "CLASSPATH=/system/framework/am.jar su root app_process "
+    "/system/bin com.android.commands.am.Am broadcast -a "
+    "com.google.gservices.intent.action.GSERVICES_OVERRIDE "
+    "-e tycho.enable_sensitive_logging true",
+    "CLASSPATH=/system/framework/am.jar su root app_process "
+    "/system/bin com.android.commands.am.Am broadcast -a "
+    "com.google.gservices.intent.action.GSERVICES_OVERRIDE "
+    "-e tycho.enable_ample_logging true"
+]
+
+_TYCHO_SERVER_LAB_OVERRIDE_CMD = (
+    "am broadcast -a com.google.gservices.intent.action.GSERVICES_OVERRIDE -e "
+    "url:tycho_server_endpoint https://android.googleapis.com/nova/nfe/ rewrite"
+    " https://android.googleapis.com/lab/nova/nfe/")
+
+
+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 TelLabProjectFiTest(TelephonyBaseTest):
+    SERIAL_NO = cb_serial_number()
+
+    def __init__(self, controllers):
+        TelephonyBaseTest.__init__(self, controllers)
+        self.ad = self.android_devices[0]
+        self.ad.sim_card = getattr(self.ad, "sim_card", None)
+        self.md8475a_ip_address = self.user_params[
+            "anritsu_md8475a_ip_address"]
+        self.wlan_option = self.user_params.get("anritsu_wlan_option", False)
+        self.md8475_version = self.user_params.get("md8475", "A")
+        self.ad.adb.shell("settings put secure cmas_additional_broadcast_pkg "
+                          "com.googlecode.android_scripting")
+        self.wait_time_between_reg_and_msg = self.user_params.get(
+            "wait_time_between_reg_and_msg", WAIT_TIME_BETWEEN_REG_AND_MSG)
+
+    def setup_class(self):
+        try:
+            self.anritsu = MD8475A(self.md8475a_ip_address, self.log,
+                                   self.wlan_option, self.md8475_version)
+        except AnritsuError:
+            self.log.error("Error in connecting to Anritsu Simulator")
+            return False
+        self.activation_attemps = self.user_params.get("activation_attemps", 3)
+        return True
+
+    def setup_test(self):
+        if getattr(self, "qxdm_log", True):
+            start_qxdm_loggers(self.log, self.android_devices)
+        ensure_phones_idle(self.log, self.android_devices)
+        toggle_airplane_mode(self.log, self.ad, True)
+        return True
+
+    def teardown_test(self):
+        self.log.info("Stopping Simulation")
+        self.anritsu.stop_simulation()
+        toggle_airplane_mode(self.log, self.ad, True)
+
+    def teardown_class(self):
+        self.anritsu.disconnect()
+        return True
+
+    def _bring_up_callbox(
+            self,
+            set_simulation_func,
+            rat):
+        try:
+            [self.bts1] = set_simulation_func(self.anritsu, self.user_params,
+                                              self.ad.sim_card)
+            set_usim_parameters(self.anritsu, self.ad.sim_card)
+            if rat == RAT_LTE:
+                set_post_sim_params(self.anritsu, self.user_params,
+                                    self.ad.sim_card)
+            self.anritsu.start_simulation()
+
+            if rat == RAT_LTE:
+                preferred_network_setting = NETWORK_MODE_LTE_GSM_WCDMA
+                rat_family = RAT_FAMILY_LTE
+            else:
+                self.log.error("No valid RAT provided to bring up callbox.")
+                return False
+
+            if not ensure_preferred_network_type_for_subscription(
+                    self.ad,
+                    preferred_network_setting):
+                self.log.error(
+                    "Failed to set rat family {}, preferred network:{}".format(
+                        rat_family, preferred_network_setting))
+                return False
+
+            if self.ad.droid.connectivityCheckAirplaneMode():
+                toggle_airplane_mode(self.log, self.ad, False)
+        except AnritsuError as e:
+            self.log.error("Error in connection with Anritsu Simulator: " +
+                           str(e))
+            return False
+        return True
+
+    def pre_switching_callbox_setup(self):
+        """ Setup environment to enable carrier switching
+        Returns:
+            True if pass; False if fail
+        """
+        return self._bring_up_callbox(set_system_model_lte, RAT_LTE)
+
+    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=300, ignore_status=True)
+        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):
+        toggle_airplane_mode_by_adb(self.log, ad, new_state=False)
+        for cmd in _TYCHO_VERBOSE_LOGGING_CMDS:
+            ad.adb.shell(cmd)
+        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 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")
+            if not ad.is_apk_installed(_TYCHO_PKG):
+                ad.log.info("%s is not installed", _TYCHO_PKG)
+                return False
+            ad.adb.shell('pm enable %s' % _TYCHO_PKG)
+            # ad.adb.shell(_TYCHO_SERVER_LAB_OVERRIDE_CMD)
+            for i in range(1, self.activation_attemps + 1):
+                if i == self.activation_attemps:
+                    ad.log.info("Reboot and try Fi activation again")
+                    reboot_device(ad)
+                self.activate_fi_account(ad)
+                if not self.check_project_fi_activated(ad):
+                    ad.log.error("Fail to activate Fi account on attempt-%s",
+                                 i)
+                    if i == self.activation_attemps:
+                        return False
+                else:
+                    ad.log.info("Fi account is activated successfully")
+                    break
+        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.
+        """
+        ad.force_stop_apk(_TYCHO_PKG)
+        ad.send_keycode("HOME")
+        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 ad.adb.shell(
+                    "settings get global device_provisioning_mobile_data"
+            ) != "1":
+                ad.adb.shell(
+                    "settings put global device_provisioning_mobile_data 1")
+            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, retries=20):
+        for _ in range(retries):
+            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.
+
+        if self.pre_switching_callbox_setup():
+            self.log.info("Turned ON Anritsu for Switching")
+            pass
+        else:
+            self.log.error("Failed to Camp to Anritsu")
+            return False
+
+        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:
+            active_carrier = self.get_active_carrier(ad)
+            if active_carrier == carrier:
+                ad.log.info("Switched to %s successfully", carrier)
+                return True
+            ad.log.error("Carrier is %s. Fail to switch to %s", active_carrier,
+                         carrier)
+            return False
+
+    def operator_network_switch(self, ad, carrier):
+        if ad.droid.telephonyGetSimOperatorName() == "Google Fi":
+            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]
+        try:
+            if not multithread_func(self.log, tasks):
+                abort_all_tests(self.log, "Unable to activate Fi account!")
+        except Exception as e:
+            self.log.error(e)
+            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.
+        """
+        setattr(self.ad, "sim_card", "FiTMO")
+        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 sprint network.
+
+        Returns:
+            True if success.
+            False if failed.
+        """
+        setattr(self.ad, "sim_card", "FiSPR")
+        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 uscc network.
+
+        Returns:
+            True if success.
+            False if failed.
+        """
+        setattr(self.ad, "sim_card", "FiUSCC")
+        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:
+            remove_google_account(ad)
+
+
+""" Tests End """
diff --git a/acts/tests/google/tel/live/TelLiveProjectFiTest.py b/acts/tests/google/tel/live/TelLiveProjectFiTest.py
index b5a60f4..a86939c 100644
--- a/acts/tests/google/tel/live/TelLiveProjectFiTest.py
+++ b/acts/tests/google/tel/live/TelLiveProjectFiTest.py
@@ -36,6 +36,8 @@
 from acts.test_utils.tel.tel_test_utils import send_dialer_secret_code
 from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
 from acts.test_utils.tel.tel_test_utils import wait_for_state
+from acts.test_utils.tel.tel_test_utils import add_google_account
+from acts.test_utils.tel.tel_test_utils import remove_google_account
 
 CARRIER_AUTO = "auto"
 
@@ -96,44 +98,6 @@
     def setup_class(self):
         self.activation_attemps = self.user_params.get("activation_attemps", 3)
 
-    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(retries):
-            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):
@@ -169,7 +133,7 @@
                 ad.log.error("Failed to connect to wifi")
                 return False
             ad.log.info("Add google account")
-            if not self._add_google_account(ad):
+            if not add_google_account(ad):
                 ad.log.error("Failed to add google account")
                 return False
             ad.adb.shell(
@@ -182,7 +146,7 @@
                 ad.log.info("%s is not installed", _TYCHO_PKG)
                 return False
             ad.adb.shell('pm enable %s' % _TYCHO_PKG)
-            #ad.adb.shell(_TYCHO_SERVER_LAB_OVERRIDE_CMD)
+            # ad.adb.shell(_TYCHO_SERVER_LAB_OVERRIDE_CMD)
             for i in range(1, self.activation_attemps + 1):
                 if i == self.activation_attemps:
                     ad.log.info("Reboot and try Fi activation again")
@@ -622,7 +586,7 @@
     @TelephonyBaseTest.tel_test_wrap
     def test_remove_google_account(self):
         for ad in self.android_devices:
-            self._remove_google_account(ad)
+            remove_google_account(ad)
 
 
 """ Tests End """