Merge "Fix for test_info decorator __name__"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 838f4b9..8429cf6 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -13,6 +13,7 @@
 acts_host_utils_test = ./acts/framework/tests/acts_host_utils_test.py
 acts_import_test_utils_test = ./acts/framework/tests/acts_import_test_utils_test.py
 acts_import_unit_test = ./acts/framework/tests/acts_import_unit_test.py
+acts_relay_controller_test = ./acts/framework/tests/acts_relay_controller_test.py
 yapf_hook = ./tools/yapf_checker.py
 
 [Builtin Hooks]
diff --git a/acts/__init__.py b/acts/__init__.py
new file mode 100644
index 0000000..9eb92df
--- /dev/null
+++ b/acts/__init__.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+#
+#   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.
diff --git a/acts/framework/__init__.py b/acts/framework/__init__.py
new file mode 100644
index 0000000..9eb92df
--- /dev/null
+++ b/acts/framework/__init__.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+#
+#   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.
diff --git a/acts/framework/acts/controllers/relay_device_controller.py b/acts/framework/acts/controllers/relay_device_controller.py
new file mode 100644
index 0000000..36715a3
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_device_controller.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#
+#   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.
+
+import json
+
+from acts.controllers.relay_lib.relay_rig import RelayRig
+
+ACTS_CONTROLLER_CONFIG_NAME = "RelayDevice"
+ACTS_CONTROLLER_REFERENCE_NAME = "relay_devices"
+
+
+def create(config):
+    """Creates RelayDevice controller objects.
+
+        Args:
+            config: A dict of:
+                config_path: The path to the RelayDevice config file.
+                devices: A list of configs or names associated with the devices.
+
+        Returns:
+                A list of RelayDevice objects.
+    """
+    devices = list()
+    with open(config) as json_file:
+        relay_rig = RelayRig(json.load(json_file))
+
+    for device in relay_rig.devices.values():
+        devices.append(device)
+
+    return devices
+
+
+def destroy(relay_devices):
+    """Cleans up RelayDevice objects.
+
+        Args:
+            relay_devices: A list of AndroidDevice objects.
+    """
+    for device in relay_devices:
+        device.clean_up()
+    pass
+
+
+def get_info(relay_devices):
+    """Get information on a list of RelayDevice objects.
+
+    Args:
+        relay_devices: A list of RelayDevice objects.
+
+    Returns:
+        A list of dict, each representing info for an RelayDevice objects.
+    """
+    device_info = []
+    for device in relay_devices:
+        relay_ids = list()
+        for relay in device.relays:
+            relay_ids.append(relay)
+        info = {"name": device.name, "relays": relay_ids}
+        device_info.append(info)
+    return device_info
diff --git a/acts/framework/acts/controllers/relay_lib/__init__.py b/acts/framework/acts/controllers/relay_lib/__init__.py
new file mode 100644
index 0000000..9eb92df
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/__init__.py
@@ -0,0 +1,15 @@
+#!/usr/bin/env python
+#
+#   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.
diff --git a/acts/framework/acts/controllers/relay_lib/errors.py b/acts/framework/acts/controllers/relay_lib/errors.py
new file mode 100644
index 0000000..2a7ef7a
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/errors.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+#
+#   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.
+from acts import signals
+
+
+class RelayConfigError(signals.ControllerError):
+    """An error found within the RelayRig config file."""
+    pass
+
+
+class RelayDeviceConnectionError(signals.ControllerError):
+    """An error for being unable to connect to the device."""
+    pass
diff --git a/acts/framework/acts/controllers/relay_lib/generic_relay_device.py b/acts/framework/acts/controllers/relay_lib/generic_relay_device.py
new file mode 100644
index 0000000..b028d96
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/generic_relay_device.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+#   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.
+
+from acts.controllers.relay_lib.relay_device import RelayDevice
+from acts.controllers.relay_lib.relay import SynchronizeRelays
+
+
+class GenericRelayDevice(RelayDevice):
+    """A default, all-encompassing implementation of RelayDevice.
+
+    This class allows for quick access to getting relay switches through the
+    subscript ([]) operator. Note that it does not allow for re-assignment or
+    additions to the relays dictionary.
+    """
+
+    def __init__(self, config, relay_rig):
+        RelayDevice.__init__(self, config, relay_rig)
+
+    def setup(self):
+        """Sets all relays to their default state (off)."""
+        with SynchronizeRelays():
+            for relay in self.relays.values():
+                relay.set_no()
+
+    def clean_up(self):
+        """Sets all relays to their default state (off)."""
+        with SynchronizeRelays():
+            for relay in self.relays.values():
+                relay.set_no()
diff --git a/acts/framework/acts/controllers/relay_lib/helpers.py b/acts/framework/acts/controllers/relay_lib/helpers.py
new file mode 100644
index 0000000..3803248
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/helpers.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python
+#
+#   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.
+from acts.controllers.relay_lib.errors import RelayConfigError
+from six import string_types
+
+MISSING_KEY_ERR_MSG = 'key "%s" missing from %s. Offending object:\n %s'
+TYPE_MISMATCH_ERR_MSG = 'Key "%s" is of type %s. Expecting %s.' \
+                        ' Offending object:\n %s'
+
+
+def validate_key(key, dictionary, expected_type, source):
+    """Validates if a key exists and its value is the correct type.
+    Args:
+        key: The key in dictionary.
+        dictionary: The dictionary that should contain key.
+        expected_type: the type that key's value should have.
+        source: The name of the object being checked. Used for error messages.
+
+    Returns:
+        The value of dictionary[key] if no error was raised.
+
+    Raises:
+        RelayConfigError if the key does not exist, or is not of expected_type.
+    """
+    if key not in dictionary:
+        raise RelayConfigError(MISSING_KEY_ERR_MSG % (key, source, dictionary))
+    if expected_type == str:
+        if not isinstance(dictionary[key], string_types):
+            raise RelayConfigError(TYPE_MISMATCH_ERR_MSG %
+                                   (key, dictionary[key], expected_type,
+                                    dictionary))
+    elif not isinstance(dictionary[key], expected_type):
+        raise RelayConfigError(TYPE_MISMATCH_ERR_MSG %
+                               (key, dictionary[key], expected_type,
+                                dictionary))
+    return dictionary[key]
diff --git a/acts/framework/acts/controllers/relay_lib/relay.py b/acts/framework/acts/controllers/relay_lib/relay.py
new file mode 100644
index 0000000..e6f0a51
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/relay.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python
+#
+#   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.
+
+from enum import Enum
+from time import sleep
+
+
+class RelayState(Enum):
+    """Enum for possible Relay States."""
+    # Pretend this means 'OFF'
+    NO = 'NORMALLY_OPEN'
+    # Pretend this means 'ON'
+    NC = 'NORMALLY_CLOSED'
+
+
+class SynchronizeRelays:
+    """A class that allows for relays to change state nearly simultaneously.
+
+    Can be used with the 'with' statement in Python:
+
+    with SynchronizeRelays():
+        relay1.set_no()
+        relay2.set_nc()
+
+    Note that the thread will still wait for RELAY_TRANSITION_WAIT_TIME
+    after execution leaves the 'with' statement.
+    """
+    _sync_sleep_flag = False
+
+    def __enter__(self):
+        self.prev_toggle_time = Relay.transition_wait_time
+        self.prev_sync_flag = SynchronizeRelays._sync_sleep_flag
+        Relay.transition_wait_time = 0
+        SynchronizeRelays._sync_sleep_flag = False
+
+    def __exit__(self, type, value, traceback):
+        if SynchronizeRelays._sync_sleep_flag:
+            sleep(Relay.transition_wait_time)
+
+        Relay.transition_wait_time = self.prev_toggle_time
+        SynchronizeRelays._sync_sleep_flag = self.prev_sync_flag
+
+
+class Relay(object):
+    """A class representing a single relay switch on a RelayBoard.
+
+    References to these relays are stored in both the RelayBoard and the
+    RelayDevice classes under the variable "relays". GenericRelayDevice can also
+    access these relays through the subscript ([]) operator.
+
+    At the moment, relays only have a valid state of 'ON' or 'OFF'. This may be
+    extended in a subclass if needed. Keep in mind that if this is done, changes
+    will also need to be made in the RelayRigParser class to initialize the
+    relays.
+
+    """
+    """How long to wait for relays to transition state."""
+    transition_wait_time = .2
+
+    def __init__(self, relay_board, position):
+        self.relay_board = relay_board
+        self.position = position
+        self._original_state = relay_board.get_relay_status(self.position)
+        self.relay_id = "{}/{}".format(self.relay_board.name, self.position)
+
+    def set_no(self):
+        """Sets the relay to the 'NO' state. Shorthand for set(RelayState.NO).
+
+        Blocks the thread for Relay.transition_wait_time.
+        """
+        self.set(RelayState.NO)
+
+    def set_nc(self):
+        """Sets the relay to the 'NC' state. Shorthand for set(RelayState.NC).
+
+        Blocks the thread for Relay.transition_wait_time.
+
+        """
+        self.set(RelayState.NC)
+
+    def toggle(self):
+        """Swaps the state from 'NO' to 'NC' or 'NC' to 'NO'.
+        Blocks the thread for Relay.transition_wait_time.
+        """
+        if self.get_status() == RelayState.NO:
+            self.set(RelayState.NC)
+        else:
+            self.set(RelayState.NO)
+
+    def set(self, state):
+        """Sets the relay to the 'NO' or 'NC' state.
+
+        Blocks the thread for Relay.transition_wait_time.
+
+        Args:
+            state: either 'NO' or 'NC'.
+
+        Raises:
+            ValueError if state is not 'NO' or 'NC'.
+
+        """
+        if state is not RelayState.NO and state is not RelayState.NC:
+            raise ValueError(
+                'Invalid state. Received "%s". Expected any of %s.' %
+                (state, [state for state in RelayState]))
+        if self.get_status() != state:
+            self.relay_board.set(self.position, state)
+            SynchronizeRelays._sync_sleep_flag = True
+            sleep(Relay.transition_wait_time)
+
+    def set_no_for(self, seconds=.25):
+        """Sets the relay to 'NORMALLY_OPEN' for seconds. Blocks the thread.
+
+        Args:
+            seconds: The number of seconds to sleep for.
+        """
+        self.set_no()
+        sleep(seconds)
+        self.set_nc()
+
+    def set_nc_for(self, seconds=.25):
+        """Sets the relay to 'NORMALLY_CLOSED' for seconds. Blocks the thread.
+
+        Respects Relay.transition_wait_time for toggling state.
+
+        Args:
+            seconds: The number of seconds to sleep for.
+        """
+        self.set_nc()
+        sleep(seconds)
+        self.set_no()
+
+    def get_status(self):
+        return self.relay_board.get_relay_status(self.position)
+
+    def clean_up(self):
+        """Does any clean up needed to allow the next series of tests to run.
+
+        For now, all this does is switches to its previous state. Inheriting
+        from this class and overriding this method would be the best course of
+        action to allow a more complex clean up to occur. If you do this, be
+        sure to make the necessary modifications in RelayRig.initialize_relay
+        and RelayRigParser.parse_json_relays.
+        """
+
+        self.set(self._original_state)
diff --git a/acts/framework/acts/controllers/relay_lib/relay_board.py b/acts/framework/acts/controllers/relay_lib/relay_board.py
new file mode 100644
index 0000000..c59e20d
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/relay_board.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+#
+#   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.
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from acts.controllers.relay_lib.errors import RelayConfigError
+from acts.controllers.relay_lib.helpers import validate_key
+from acts.controllers.relay_lib.relay import Relay
+from acts.controllers.relay_lib.relay import RelayState
+
+
+class RelayBoard(object):
+    """Handles interfacing with the Relays and RelayDevices.
+
+    This is the base class for all RelayBoards.
+    """
+
+    def __init__(self, config):
+        """Creates a RelayBoard instance. Handles naming and relay creation.
+
+        Args:
+            config: A configuration dictionary, usually pulled from an element
+            under in "boards" list in the relay rig config file.
+        """
+        self.name = validate_key('name', config, str, 'config')
+        if '/' in self.name:
+            raise RelayConfigError('RelayBoard name cannot contain a "/".')
+        self.relays = dict()
+        for pos in self.get_relay_position_list():
+            self.relays[pos] = Relay(self, pos)
+
+    def set(self, relay_position, state):
+        """Sets the relay to the given state.
+
+        Args:
+            relay_position: the relay having its state modified.
+            state: the state to set the relay to. Currently only states NO and
+                   NC are supported.
+        """
+        raise NotImplementedError()
+
+    def get_relay_position_list(self):
+        """Returns a list of all possible relay positions."""
+        raise NotImplementedError()
+
+    def get_relay_status(self, relay):
+        """Returns the state of the given relay."""
+        raise NotImplementedError()
diff --git a/acts/framework/acts/controllers/relay_lib/relay_device.py b/acts/framework/acts/controllers/relay_lib/relay_device.py
new file mode 100644
index 0000000..31ff862
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/relay_device.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#
+#   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.
+
+from acts.controllers.relay_lib.errors import RelayConfigError
+from acts.controllers.relay_lib.helpers import validate_key
+
+
+class RelayDevice(object):
+    """The base class for all relay devices.
+
+    RelayDevice has access to both its relays as well as the relay rig it is
+    a part of. Note that you can receive references to the relay_boards
+    through relays[0...n].board. The relays are not guaranteed to be on
+    the same relay board.
+    """
+
+    def __init__(self, config, relay_rig):
+        """Creates a RelayDevice.
+
+        Args:
+            config: The dictionary found in the config file for this device.
+            You can add your own params to the config file if needed, and they
+            will be found in this dictionary.
+            relay_rig: The RelayRig the device is attached to. This won't be
+            useful for classes that inherit from RelayDevice, so just pass it
+            down to this __init__.
+        """
+        self.rig = relay_rig
+        self.relays = dict()
+
+        validate_key('name', config, str, '"devices" element')
+        self.name = config['name']
+
+        validate_key('relays', config, list, '"devices list element')
+        if len(config['relays']) < 1:
+            raise RelayConfigError(
+                'Key "relays" must have at least 1 element.')
+
+        for relay_config in config['relays']:
+            if isinstance(relay_config, dict):
+                name = validate_key('name', relay_config, str,
+                                    '"relays" element in "devices"')
+                if 'pos' in relay_config:
+                    self.relays[name] = relay_rig.relays[relay_config['pos']]
+                else:
+                    validate_key('pos', relay_config, int,
+                                 '"relays" element in "devices"')
+            else:
+                raise TypeError('Key "relay" is of type {}. Expecting {}. '
+                                'Offending object:\n {}'.format(
+                                    type(relay_config['relay']), dict,
+                                    relay_config))
+
+    def setup(self):
+        """Sets up the relay device to be ready for commands."""
+        pass
+
+    def clean_up(self):
+        """Sets the relay device back to its inert state."""
+        pass
diff --git a/acts/framework/acts/controllers/relay_lib/relay_rig.py b/acts/framework/acts/controllers/relay_lib/relay_rig.py
new file mode 100644
index 0000000..c959a50
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/relay_rig.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+#
+#   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.
+from acts.controllers.relay_lib.errors import RelayConfigError
+from acts.controllers.relay_lib.helpers import validate_key
+from acts.controllers.relay_lib.sain_smart_board import SainSmartBoard
+from acts.controllers.relay_lib.generic_relay_device import GenericRelayDevice
+
+
+class RelayRig:
+    """A group of relay boards and their connected devices.
+
+    This class is also responsible for handling the creation of the relay switch
+    boards, as well as the devices and relays associated with them.
+
+    The boards dict can contain different types of relay boards. They share a
+    common interface through inheriting from RelayBoard. This layer can be
+    ignored by the user.
+
+    The relay devices are stored in a dict of (device_name: device). These
+    device references should be used by the user when they want to directly
+    interface with the relay switches. See RelayDevice or GeneralRelayDevice for
+    implementation.
+
+    """
+    DUPLICATE_ID_ERR_MSG = 'The {} "{}" is not unique. Duplicated in:\n {}'
+
+    # A dict of lambdas that instantiate relay board upon invocation.
+    # The key is the class type name, the value is the lambda.
+    _board_constructors = {
+        'SainSmartBoard': lambda x: SainSmartBoard(x),
+    }
+
+    # Similar to the dict above, except for devices.
+    _device_constructors = {
+        'GenericRelayDevice': lambda x, rig: GenericRelayDevice(x, rig),
+    }
+
+    def __init__(self, config):
+        self.relays = dict()
+        self.boards = dict()
+        self.devices = dict()
+
+        validate_key('boards', config, list, 'relay config file')
+
+        for elem in config['boards']:
+            board = self.create_relay_board(elem)
+            if board.name in self.boards:
+                raise RelayConfigError(
+                    self.DUPLICATE_ID_ERR_MSG.format('name', elem['name'],
+                                                     elem))
+            self.boards[board.name] = board
+
+        # Note: 'boards' is a necessary value, 'devices' is not.
+        if 'devices' in config:
+            for elem in config['devices']:
+                relay_device = self.create_relay_device(elem)
+                if relay_device.name in self.devices:
+                    raise RelayConfigError(
+                        self.DUPLICATE_ID_ERR_MSG.format(
+                            'name', elem['name'], elem))
+                self.devices[relay_device.name] = relay_device
+        else:
+            device_config = dict()
+            device_config['name'] = 'GenericRelayDevice'
+            device_config['relays'] = list()
+            for relay_id in self.relays:
+                device_config['relays'].append({
+                    'name': str(relay_id),
+                    'pos': relay_id
+                })
+            self.devices['device'] = (self.create_relay_device(device_config))
+
+    def create_relay_board(self, config):
+        """Builds a RelayBoard from the given config.
+
+        Args:
+            config: An object containing 'type', 'name', 'relays', and
+            (optionally) 'properties'. See the example json file.
+
+        Returns:
+            A RelayBoard with the given type found in the config.
+
+        Raises:
+            RelayConfigError if config['type'] doesn't exist or is not a string.
+
+        """
+        validate_key('type', config, str, '"boards" element')
+        try:
+            ret = self._board_constructors[config['type']](config)
+        except LookupError:
+            raise RelayConfigError(
+                'RelayBoard with type {} not found. Has it been added '
+                'to the _board_constructors dict?'.format(config['type']))
+        for _, relay in ret.relays.items():
+            self.relays[relay.relay_id] = relay
+        return ret
+
+    def create_relay_device(self, config):
+        """Builds a RelayDevice from the given config.
+
+        When given no 'type' key in the config, the function will default to
+        returning a GenericRelayDevice with the relays found in the 'relays'
+        array.
+
+        Args:
+            config: An object containing 'name', 'relays', and (optionally)
+            type.
+
+        Returns:
+            A RelayDevice with the given type found in the config. If no type is
+            found, it will default to GenericRelayDevice.
+
+        Raises:
+            RelayConfigError if the type given does not match any from the
+            _device_constructors dictionary.
+
+        """
+        if 'type' in config:
+            if config['type'] not in RelayRig._device_constructors:
+                raise RelayConfigError(
+                    'Device with type {} not found. Has it been added '
+                    'to the _device_constructors dict?'.format(config['type']))
+            else:
+                device = self._device_constructors[config['type']](config,
+                                                                   self)
+
+        else:
+            device = GenericRelayDevice(config, self)
+
+        return device
diff --git a/acts/framework/acts/controllers/relay_lib/sain_smart_board.py b/acts/framework/acts/controllers/relay_lib/sain_smart_board.py
new file mode 100644
index 0000000..0b273a6
--- /dev/null
+++ b/acts/framework/acts/controllers/relay_lib/sain_smart_board.py
@@ -0,0 +1,127 @@
+#!/usr/bin/env python
+#
+#   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.
+
+from future.moves.urllib.request import urlopen
+import re
+
+from acts.controllers.relay_lib.errors import RelayDeviceConnectionError
+from acts.controllers.relay_lib.helpers import validate_key
+from acts.controllers.relay_lib.relay import RelayState
+from acts.controllers.relay_lib.relay_board import RelayBoard
+
+BASE_URL = 'http://192.168.1.4/30000/'
+
+
+class SainSmartBoard(RelayBoard):
+    """Controls and queries SainSmart Web Relay Board.
+
+    Controls and queries SainSmart Web Relay Board, found here:
+    http://www.sainsmart.com/sainsmart-rj45-tcp-ip-remote-controller-board-with-8-channels-relay-integrated.html
+    this uses a web interface to toggle relays.
+
+    There is an unmentioned hidden status page that can be found at <root>/99/.
+    """
+
+    # No longer used. Here for debugging purposes.
+    #
+    # Old status pages. Used before base_url/99 was found.
+    # STATUS_1 = '40'
+    # STATUS_2 = '43'
+    #
+    # This is the regex used to parse the old status pages:
+    # r'y-\d(?P<relay>\d).+?> (?:&nbsp)?(?P<status>.*?)&'
+    #
+    # Pages that will turn all switches on or off, even the ghost switches.
+    # ALL_RELAY_OFF = '44'
+    # ALL_RELAY_ON = '45'
+
+    HIDDEN_STATUS_PAGE = '99'
+
+    VALID_RELAY_POSITIONS = [0, 1, 2, 3, 4, 5, 6, 7]
+    NUM_RELAYS = 8
+
+    def __init__(self, config):
+        # This will be lazy loaded
+        self.status_dict = None
+        self.base_url = validate_key('base_url', config, str, 'config')
+        if not self.base_url.endswith('/'):
+            self.base_url += '/'
+        RelayBoard.__init__(self, config)
+
+    def get_relay_position_list(self):
+        return self.VALID_RELAY_POSITIONS
+
+    def _load_page(self, relative_url):
+        """Loads a web page at self.base_url + relative_url.
+
+        Properly opens and closes the web page.
+
+        Args:
+            relative_url: The string appended to the base_url
+
+        Returns:
+            the contents of the web page.
+
+        Raises:
+            A RelayDeviceConnectionError is raised if the page cannot be loaded.
+
+        """
+        try:
+            page = urlopen(self.base_url + relative_url)
+            result = page.read().decode("utf-8")
+            page.close()
+        except:
+            raise RelayDeviceConnectionError(
+                'Unable to connect to board "{}" through {}'.format(
+                    self.name, self.base_url + relative_url))
+        return result
+
+    def _sync_status_dict(self):
+        """Returns a dictionary of relays and there current state."""
+        result = self._load_page(self.HIDDEN_STATUS_PAGE)
+        status_string = re.search(r'">([01]*)TUX', result).group(1)
+
+        self.status_dict = dict()
+        for index, char in enumerate(status_string):
+            self.status_dict[index] = \
+                RelayState.NC if char == '1' else RelayState.NO
+
+    def _print_status(self):
+        """Prints out the list of relays and their current state."""
+        for i in range(0, 8):
+            print('Relay {}: {}'.format(i, self.status_dict[i]))
+
+    def get_relay_status(self, relay_position):
+        """Returns the current status of the passed in relay."""
+        if self.status_dict is None:
+            self._sync_status_dict()
+        return self.status_dict[relay_position]
+
+    def set(self, relay_position, value):
+        """Sets the given relay to be either ON or OFF, indicated by value."""
+        if self.status_dict is None:
+            self._sync_status_dict()
+        self._load_page(self._get_relay_url_code(relay_position, value))
+        self.status_dict[relay_position] = value
+
+    @staticmethod
+    def _get_relay_url_code(relay_position, no_or_nc):
+        """Returns the two digit code corresponding to setting the relay."""
+        if no_or_nc == RelayState.NC:
+            on_modifier = 1
+        else:
+            on_modifier = 0
+        return '{:02d}'.format(relay_position * 2 + on_modifier)
diff --git a/acts/framework/acts/keys.py b/acts/framework/acts/keys.py
index 9c53fd6..ccd5e2e 100644
--- a/acts/framework/acts/keys.py
+++ b/acts/framework/acts/keys.py
@@ -36,6 +36,7 @@
     # Config names for controllers packaged in ACTS.
     key_android_device = "AndroidDevice"
     key_native_android_device = "NativeAndroidDevice"
+    key_relay_device = "RelayDevice"
     key_access_point = "AccessPoint"
     key_attenuator = "Attenuator"
     key_iperf_server = "IPerfServer"
@@ -51,6 +52,7 @@
     m_key_monsoon = "monsoon"
     m_key_android_device = "android_device"
     m_key_native_android_device = "native_android_device"
+    m_key_relay_device = "relay_device_controller"
     m_key_access_point = "access_point"
     m_key_attenuator = "attenuator"
     m_key_iperf_server = "iperf_server"
@@ -62,8 +64,9 @@
 
     # Controller names packaged with ACTS.
     builtin_controller_names = [
-        key_android_device, key_native_android_device, key_access_point,
-        key_attenuator, key_iperf_server, key_monsoon, key_sniffer
+        key_android_device, key_native_android_device, key_relay_device,
+        key_access_point, key_attenuator, key_iperf_server, key_monsoon,
+        key_sniffer
     ]
 
 
diff --git a/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py b/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
index 0ddf218..6808110 100644
--- a/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
+++ b/acts/framework/acts/test_utils/tel/TelephonyBaseTest.py
@@ -67,17 +67,24 @@
         inspect_stack = inspect.stack()
         trace_info = ""
         for i in range(level):
-            stack_frames = inspect_stack[2 + i]
-            info = inspect.getframeinfo(stack_frames[0])
-            trace_info = "%s[%s:%s:%s]" % (trace_info,
-                                           os.path.basename(info.filename),
-                                           info.function, info.lineno)
+            try:
+                stack_frames = inspect_stack[2 + i]
+                info = inspect.getframeinfo(stack_frames[0])
+                trace_info = "%s[%s:%s:%s]" % (trace_info,
+                                               os.path.basename(info.filename),
+                                               info.function, info.lineno)
+            except IndexError:
+                break
         return trace_info
 
     def error(self, msg, *args, **kwargs):
         trace_info = _TelephonyTraceLogger._get_trace_info(level=3)
         self._logger.error("%s %s" % (msg, trace_info), *args, **kwargs)
 
+    def warn(self, msg, *args, **kwargs):
+        trace_info = _TelephonyTraceLogger._get_trace_info(level=1)
+        self._logger.warn("%s %s" % (msg, trace_info), *args, **kwargs)
+
     def warning(self, msg, *args, **kwargs):
         trace_info = _TelephonyTraceLogger._get_trace_info(level=1)
         self._logger.warning("%s %s" % (msg, trace_info), *args, **kwargs)
@@ -213,11 +220,12 @@
 
             # Setup VoWiFi MDN for Verizon. b/33187374
             build_id = ad.build_info["build_id"]
-            if "vzw" in [sub["operator"] for sub in ad.cfg[
-                    "subscription"].values()] and ad.model in (
-                            "marlin", "sailfish") and (build_id.startswith(
-                                    "N2") or build_id.startswith("OR")):
-                ad.log.info("setup VoWiFi MDN for MR2 or OC branch per b/33187374")
+            if "vzw" in [
+                    sub["operator"] for sub in ad.cfg["subscription"].values()
+            ] and ad.model in ("marlin", "sailfish") and (
+                    build_id.startswith("N2") or build_id.startswith("OR")):
+                ad.log.info(
+                    "setup VoWiFi MDN for MR2 or OC branch per b/33187374")
                 ad.adb.shell("setprop dbg.vzw.force_wfc_nv_enabled true")
                 ad.adb.shell("am start --ei EXTRA_LAUNCH_CARRIER_APP 0 -n "
                              "\"com.google.android.wfcactivation/"
@@ -265,11 +273,10 @@
                 if "enable_wifi_verbose_logging" in self.user_params:
                     ad.droid.wifiEnableVerboseLogging(
                         WIFI_VERBOSE_LOGGING_DISABLED)
+            return True
         except Exception as e:
             self.log.error("Failure with %s", e)
 
-        return True
-
     def setup_test(self):
         if getattr(self, "diag_logger", None):
             for logger in self.diag_logger:
@@ -322,8 +329,8 @@
                 ad.adb.wait_for_device()
                 ad.take_bug_report(test_name, begin_time)
                 tombstone_path = os.path.join(
-                    ad.log_path, "BugReports",
-                    "{},{}".format(begin_time, ad.serial).replace(' ', '_'))
+                    ad.log_path, "BugReports", "{},{}".format(
+                        begin_time, ad.serial).replace(' ', '_'))
                 utils.create_dir(tombstone_path)
                 ad.adb.pull('/data/tombstones/', tombstone_path, timeout=1200)
             except Exception as e:
diff --git a/acts/framework/acts/test_utils/tel/tel_data_utils.py b/acts/framework/acts/test_utils/tel/tel_data_utils.py
index ad8d731..ac0bfd4 100644
--- a/acts/framework/acts/test_utils/tel/tel_data_utils.py
+++ b/acts/framework/acts/test_utils/tel/tel_data_utils.py
@@ -34,7 +34,7 @@
 from acts.test_utils.tel.tel_test_utils import rat_generation_from_rat
 from acts.test_utils.tel.tel_test_utils import set_wifi_to_default
 from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts.test_utils.tel.tel_test_utils import verify_http_connection
+from acts.test_utils.tel.tel_test_utils import verify_internet_connection
 from acts.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
 from acts.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
 from acts.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
@@ -113,7 +113,8 @@
     log.info("--->Start wifi_tethering_setup_teardown<---")
     log.info("Provider: {}".format(provider.serial))
     if not provider.droid.connectivityIsTetheringSupported():
-        log.error("Provider does not support tethering. Stop tethering test.")
+        provider.log.error(
+            "Provider does not support tethering. Stop tethering test.")
         return False
 
     if ssid is None:
@@ -132,49 +133,45 @@
             client.droid.telephonyToggleDataConnection(False)
         log.info("WiFI Tethering: Verify client have no Internet access.")
         for client in client_list:
-            if verify_http_connection(log, client):
-                log.error("Turn off Data on client fail. {}".format(
-                    client.serial))
+            if verify_internet_connection(log, client):
+                client.log.error("Turn off Data on client fail")
                 return False
 
-        log.info(
-            "WiFI Tethering: Turn on WiFi tethering on {}. SSID: {}, password: {}".
-            format(provider.serial, ssid, password))
+        provider.log.info(
+            "Provider turn on WiFi tethering. SSID: %s, password: %s", ssid,
+            password)
 
         if not start_wifi_tethering(log, provider, ssid, password, ap_band):
-            log.error("Provider start WiFi tethering failed.")
+            provider.log.error("Provider start WiFi tethering failed.")
             return False
         time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
 
-        log.info("Provider {} check Internet connection.".format(
-            provider.serial))
-        if not verify_http_connection(log, provider):
+        provider.log.info("Provider check Internet connection.")
+        if not verify_internet_connection(log, provider):
             return False
         for client in client_list:
-            log.info(
-                "WiFI Tethering: {} connect to WiFi and verify AP band correct.".
-                format(client.serial))
+            client.log.info(
+                "Client connect to WiFi and verify AP band correct.")
             if not ensure_wifi_connected(log, client, ssid, password):
-                log.error("Client connect to WiFi failed.")
+                client.log.error("Client connect to WiFi failed.")
                 return False
 
             wifi_info = client.droid.wifiGetConnectionInfo()
             if ap_band == WIFI_CONFIG_APBAND_5G:
                 if wifi_info["is_24ghz"]:
-                    log.error("Expected 5g network. WiFi Info: {}".format(
-                        wifi_info))
+                    client.log.error("Expected 5g network. WiFi Info: %s",
+                                     wifi_info)
                     return False
             else:
                 if wifi_info["is_5ghz"]:
-                    log.error("Expected 2g network. WiFi Info: {}".format(
-                        wifi_info))
+                    client.log.error("Expected 2g network. WiFi Info: %s",
+                                     wifi_info)
                     return False
 
-            log.info("Client{} check Internet connection.".format(
-                client.serial))
+            client.log.info("Client check Internet connection.")
             if (not wait_for_wifi_data_connection(log, client, True) or
-                    not verify_http_connection(log, client)):
-                log.error("No WiFi Data on client: {}.".format(client.serial))
+                    not verify_internet_connection(log, client)):
+                client.log.error("No WiFi Data on client")
                 return False
 
         if not tethering_check_internet_connection(
@@ -207,18 +204,24 @@
     Returns:
         True if no error happened. False otherwise.
     """
-    for i in range(1, check_iteration):
+    for i in range(1, check_iteration + 1):
+        result = True
         time.sleep(check_interval)
-        log.info("Provider {} check Internet connection after {} seconds.".
-                 format(provider.serial, check_interval * i))
-        if not verify_http_connection(log, provider):
-            return False
+        provider.log.info(
+            "Provider check Internet connection after %s seconds.",
+            check_interval * i)
+        if not verify_internet_connection(log, provider):
+            result = False
+            continue
         for client in client_list:
-            log.info("Client {} check Internet connection after {} seconds.".
-                     format(client.serial, check_interval * i))
-            if not verify_http_connection(log, client):
-                return False
-    return True
+            client.log.info(
+                "Client check Internet connection after %s seconds.",
+                check_interval * i)
+            if not verify_internet_connection(log, client):
+                result = False
+                break
+        if result: return result
+    return False
 
 
 def wifi_cell_switching(log, ad, wifi_network_ssid, wifi_network_pass, nw_gen):
@@ -244,16 +247,17 @@
     try:
 
         if not ensure_network_generation_for_subscription(
-                log, ad, get_default_data_sub_id(ad), nw_gen,
+                log, ad,
+                get_default_data_sub_id(ad), nw_gen,
                 MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
-            log.error("Device failed to register in {}".format(nw_gen))
+            ad.log.error("Device failed to register in %s", nw_gen)
             return False
 
         # Ensure WiFi can connect to live network
-        log.info("Make sure phone can connect to live network by WIFI")
+        ad.log.info("Make sure phone can connect to live network by WIFI")
         if not ensure_wifi_connected(log, ad, wifi_network_ssid,
                                      wifi_network_pass):
-            log.error("WiFi connect fail.")
+            ad.log.error("WiFi connect fail.")
             return False
         log.info("Phone connected to WIFI.")
 
@@ -262,29 +266,29 @@
         wifi_toggle_state(log, ad, True)
         ad.droid.telephonyToggleDataConnection(True)
         if (not wait_for_wifi_data_connection(log, ad, True) or
-                not verify_http_connection(log, ad)):
-            log.error("Data is not on WiFi")
+                not verify_internet_connection(log, ad)):
+            ad.log.error("Data is not on WiFi")
             return False
 
         log.info("Step2 WiFi is Off, Data is on Cell.")
         wifi_toggle_state(log, ad, False)
         if (not wait_for_cell_data_connection(log, ad, True) or
-                not verify_http_connection(log, ad)):
-            log.error("Data did not return to cell")
+                not verify_internet_connection(log, ad)):
+            ad.log.error("Data did not return to cell")
             return False
 
         log.info("Step3 WiFi is On, Data is on WiFi.")
         wifi_toggle_state(log, ad, True)
         if (not wait_for_wifi_data_connection(log, ad, True) or
-                not verify_http_connection(log, ad)):
-            log.error("Data did not return to WiFi")
+                not verify_internet_connection(log, ad)):
+            ad.log.error("Data did not return to WiFi")
             return False
 
         log.info("Step4 WiFi is Off, Data is on Cell.")
         wifi_toggle_state(log, ad, False)
         if (not wait_for_cell_data_connection(log, ad, True) or
-                not verify_http_connection(log, ad)):
-            log.error("Data did not return to cell")
+                not verify_internet_connection(log, ad)):
+            ad.log.error("Data did not return to cell")
             return False
         return True
 
@@ -317,36 +321,36 @@
 
         log.info("Step1: ensure attach")
         if not toggle_airplane_mode(log, ad, False):
-            log.error("Failed initial attach")
+            ad.log.error("Failed initial attach")
             return False
-        if not verify_http_connection(log, ad):
-            log.error("Data not available on cell.")
+        if not verify_internet_connection(log, ad):
+            ad.log.error("Data not available on cell.")
             return False
 
         log.info("Step2: enable airplane mode and ensure detach")
         if not toggle_airplane_mode(log, ad, True):
-            log.error("Failed to enable Airplane Mode")
+            ad.log.error("Failed to enable Airplane Mode")
             return False
         if not wait_for_cell_data_connection(log, ad, False):
-            log.error("Failed to disable cell data connection")
+            ad.log.error("Failed to disable cell data connection")
             return False
-        if verify_http_connection(log, ad):
-            log.error("Data available in airplane mode.")
+        if verify_internet_connection(log, ad):
+            ad.log.error("Data available in airplane mode.")
             return False
 
         log.info("Step3: disable airplane mode and ensure attach")
         if not toggle_airplane_mode(log, ad, False):
-            log.error("Failed to disable Airplane Mode")
+            ad.log.error("Failed to disable Airplane Mode")
             return False
 
         if not wait_for_cell_data_connection(log, ad, True):
-            log.error("Failed to enable cell data connection")
+            ad.log.error("Failed to enable cell data connection")
             return False
 
         time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
 
         log.info("Step4 verify internet")
-        return verify_http_connection(log, ad)
+        return verify_internet_connection(log, ad)
     finally:
         toggle_airplane_mode(log, ad, False)
 
@@ -372,11 +376,12 @@
     ensure_phones_idle(log, [ad])
     wait_time = MAX_WAIT_TIME_NW_SELECTION
     if getattr(ad, 'roaming', False):
-       wait_time = 2 * wait_time
+        wait_time = 2 * wait_time
     if not ensure_network_generation_for_subscription(
-            log, ad, get_default_data_sub_id(ad), nw_gen,
-            MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
-        ad.log.error("Device failed to connect to %s in %ss.", nw_gen,
+            log, ad,
+            get_default_data_sub_id(ad), nw_gen, MAX_WAIT_TIME_NW_SELECTION,
+            NETWORK_SERVICE_DATA):
+        ad.log.error("Device failed to connect to %s in %s seconds.", nw_gen,
                      wait_time)
         return False
 
@@ -385,42 +390,43 @@
         toggle_airplane_mode(log, ad, False)
         ad.droid.telephonyToggleDataConnection(True)
         if not wait_for_cell_data_connection(log, ad, True):
-            log.error("Failed to enable data connection.")
+            ad.log.error("Failed to enable data connection.")
             return False
 
         log.info("Step2 Verify internet")
-        if not verify_http_connection(log, ad):
-            log.error("Data not available on cell.")
+        if not verify_internet_connection(log, ad):
+            ad.log.error("Data not available on cell.")
             return False
 
         log.info("Step3 Turn off data and verify not connected.")
         ad.droid.telephonyToggleDataConnection(False)
         if not wait_for_cell_data_connection(log, ad, False):
-            log.error("Step3 Failed to disable data connection.")
+            ad.log.error("Step3 Failed to disable data connection.")
             return False
 
-        if verify_http_connection(log, ad):
-            log.error("Step3 Data still available when disabled.")
+        if verify_internet_connection(log, ad):
+            ad.log.error("Step3 Data still available when disabled.")
             return False
 
         log.info("Step4 Re-enable data.")
         ad.droid.telephonyToggleDataConnection(True)
         if not wait_for_cell_data_connection(log, ad, True):
-            log.error("Step4 failed to re-enable data.")
+            ad.log.error("Step4 failed to re-enable data.")
             return False
-        if not verify_http_connection(log, ad):
-            log.error("Data not available on cell.")
+        if not verify_internet_connection(log, ad):
+            ad.log.error("Data not available on cell.")
             return False
 
         if not is_droid_in_network_generation_for_subscription(
-                log, ad, get_default_data_sub_id(ad), nw_gen,
-                NETWORK_SERVICE_DATA):
-            log.error("Failed: droid is no longer on correct network")
-            log.info("Expected:{}, Current:{}".format(
-                nw_gen, rat_generation_from_rat(
+                log, ad,
+                get_default_data_sub_id(ad), nw_gen, NETWORK_SERVICE_DATA):
+            ad.log.error("Failed: droid is no longer on correct network")
+            ad.log.info(
+                "Expected:%s, Current:%s", nw_gen,
+                rat_generation_from_rat(
                     get_network_rat_for_subscription(
-                        log, ad, get_default_data_sub_id(
-                            ad), NETWORK_SERVICE_DATA))))
+                        log, ad,
+                        get_default_data_sub_id(ad), NETWORK_SERVICE_DATA)))
             return False
         return True
     finally:
@@ -439,13 +445,13 @@
         Data SIM changed successfully, data attached and Internet access is OK.
     """
     sub_id = get_subid_from_slot_index(log, ad, sim_slot)
-    log.info("Change Data to subId: {}, SIM slot: {}".format(sub_id, sim_slot))
+    ad.log.info("Change Data to subId: %s, SIM slot: %s", sub_id, sim_slot)
     set_subid_for_data(ad, sub_id)
     if not wait_for_data_attach_for_subscription(log, ad, sub_id,
                                                  MAX_WAIT_TIME_NW_SELECTION):
-        log.error("Failed to attach data on subId:{}".format(sub_id))
+        ad.log.error("Failed to attach data on subId:%s", sub_id)
         return False
-    if not verify_http_connection(log, ad):
-        log.error("No Internet access after changing Data SIM.")
+    if not verify_internet_connection(log, ad):
+        ad.log.error("No Internet access after changing Data SIM.")
         return False
     return True
diff --git a/acts/framework/acts/test_utils/tel/tel_defines.py b/acts/framework/acts/test_utils/tel/tel_defines.py
index 346ca23..48c4bdd 100644
--- a/acts/framework/acts/test_utils/tel/tel_defines.py
+++ b/acts/framework/acts/test_utils/tel/tel_defines.py
@@ -94,7 +94,7 @@
 MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK = 15
 
 # Max time to wait for voice mail count report correct result.
-MAX_WAIT_TIME_VOICE_MAIL_COUNT = 30
+MAX_WAIT_TIME_VOICE_MAIL_COUNT = 90
 
 # Max time to wait for data SIM change
 MAX_WAIT_TIME_DATA_SUB_CHANGE = 150
diff --git a/acts/framework/acts/test_utils/tel/tel_lookup_tables.py b/acts/framework/acts/test_utils/tel/tel_lookup_tables.py
index 26c83e3..a33569c 100644
--- a/acts/framework/acts/test_utils/tel/tel_lookup_tables.py
+++ b/acts/framework/acts/test_utils/tel/tel_lookup_tables.py
@@ -113,12 +113,21 @@
     return None
 
 
+def get_ee_voice_mail_number():
+    return "+447953222222"
+
+
 def get_voice_mail_number_function(operator):
-    return _TelTables.voice_mail_number_get_function_tbl[operator]
+    return _TelTables.voice_mail_number_get_function_tbl.get(operator)
 
 
 def get_voice_mail_count_check_function(operator):
-    return _TelTables.voice_mail_count_check_function_tbl[operator]
+    return _TelTables.voice_mail_count_check_function_tbl.get(
+        operator, check_tmo_voice_mail_count)
+
+
+def get_voice_mail_delete_digit(operator):
+    return _TelTables.voice_mail_delete_digit_tbl.get(operator, "7")
 
 
 def get_allowable_network_preference(operator, phone_type=None):
@@ -627,7 +636,8 @@
         tel_defines.CARRIER_TMO: get_tmo_voice_mail_number,
         tel_defines.CARRIER_VZW: get_vzw_voice_mail_number,
         tel_defines.CARRIER_ATT: get_att_voice_mail_number,
-        tel_defines.CARRIER_SPT: get_spt_voice_mail_number
+        tel_defines.CARRIER_SPT: get_spt_voice_mail_number,
+        tel_defines.CARRIER_EEUK: get_ee_voice_mail_number
     }
 
     voice_mail_count_check_function_tbl = {
@@ -636,6 +646,8 @@
         tel_defines.CARRIER_SPT: check_spt_voice_mail_count
     }
 
+    voice_mail_delete_digit_tbl = {tel_defines.CARRIER_EEUK: "3"}
+
 
 device_capabilities = {
     NexusModelNames.ONE:
diff --git a/acts/framework/acts/test_utils/tel/tel_test_utils.py b/acts/framework/acts/test_utils/tel/tel_test_utils.py
index df990bf..62967d7 100644
--- a/acts/framework/acts/test_utils/tel/tel_test_utils.py
+++ b/acts/framework/acts/test_utils/tel/tel_test_utils.py
@@ -116,6 +116,7 @@
 from acts.test_utils.tel.tel_lookup_tables import \
     get_voice_mail_count_check_function
 from acts.test_utils.tel.tel_lookup_tables import get_voice_mail_number_function
+from acts.test_utils.tel.tel_lookup_tables import get_voice_mail_delete_digit
 from acts.test_utils.tel.tel_lookup_tables import \
     network_preference_for_generaton
 from acts.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
@@ -136,6 +137,7 @@
     get_incoming_message_sub_id
 from acts.test_utils.wifi import wifi_test_utils
 from acts.test_utils.wifi import wifi_constants
+from acts.utils import adb_shell_ping
 from acts.utils import load_config
 
 WIFI_SSID_KEY = wifi_test_utils.WifiEnums.SSID_KEY
@@ -883,7 +885,7 @@
 
     if not wait_for_ringing_call_for_subscription(log, ad, sub_id,
                                                   incoming_number):
-        log.error("Could not reject a call: phone never rang.")
+        ad.log.error("Could not reject a call: phone never rang.")
         return False
 
     ad.ed.clear_all_events()
@@ -891,7 +893,6 @@
     if reject is True:
         # Delay between ringing and reject.
         time.sleep(delay_reject)
-        log.info("Reject on callee.")
         is_find = False
         # Loop the call list and find the matched one to disconnect.
         for call in ad.droid.telecomCallGetCallIds():
@@ -899,13 +900,14 @@
                     get_number_from_tel_uri(get_call_uri(ad, call)),
                     incoming_number):
                 ad.droid.telecomCallDisconnect(call)
+                ad.log.info("Callee reject the call")
                 is_find = True
         if is_find is False:
-            log.error("Did not find matching call to reject.")
+            ad.log.error("Callee did not find matching call to reject.")
             return False
     else:
         # don't reject on callee. Just ignore the incoming call.
-        log.info("Received incoming call. Ignore it.")
+        ad.log.info("Callee received incoming call. Ignore it.")
     try:
         ad.ed.wait_for_event(
             EventCallStateChanged,
@@ -914,7 +916,7 @@
             field=CallStateContainer.CALL_STATE,
             value_list=[TELEPHONY_STATE_IDLE, TELEPHONY_STATE_OFFHOOK])
     except Empty:
-        log.error("No onCallStateChangedIdle event received.")
+        ad.log.error("No onCallStateChangedIdle event received.")
         return False
     finally:
         ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
@@ -1201,6 +1203,13 @@
     ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
 
     try:
+        voice_mail_count_before = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
+            subid_callee)
+        ad_callee.log.info("voice mail count is %s", voice_mail_count_before)
+        # -1 means there are unread voice mail, but the count is unknown
+        # 0 means either this API not working (VZW) or no unread voice mail.
+        if voice_mail_count_before != 0:
+            log.warning("--Pending new Voice Mail, please clear on phone.--")
 
         if not initiate_call(log, ad_caller, callee_number):
             raise _CallSequenceException("Initiate call failed.")
@@ -1211,13 +1220,6 @@
 
         ad_callee.droid.telephonyStartTrackingVoiceMailStateChangeForSubscription(
             subid_callee)
-        voice_mail_count_before = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
-            subid_callee)
-
-        # -1 means there are unread voice mail, but the count is unknown
-        # 0 means either this API not working (VZW) or no unread voice mail.
-        if voice_mail_count_before != 0:
-            log.warning("--Pending new Voice Mail, please clear on phone.--")
 
         # ensure that all internal states are updated in telecom
         time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
@@ -1228,7 +1230,6 @@
 
         # TODO: b/26293512 Need to play some sound to leave message.
         # Otherwise carrier voice mail server may drop this voice mail.
-
         time.sleep(wait_time_in_call)
 
         if not verify_caller_func:
@@ -1237,8 +1238,8 @@
             caller_state_result = verify_caller_func(log, ad_caller)
         if not caller_state_result:
             raise _CallSequenceException(
-                "Caller not in correct state after {} seconds".format(
-                    wait_time_in_call))
+                "Caller %s not in correct state after %s seconds" %
+                (ad_caller.serial, wait_time_in_call))
 
         if not hangup_call(log, ad_caller):
             raise _CallSequenceException("Error in Hanging-Up Call")
@@ -1250,6 +1251,8 @@
                 _is_on_message_waiting_event_true)
             log.info(event)
         except Empty:
+            ad_callee.log.warning("No expected event %s",
+                                  EventMessageWaitingIndicatorChanged)
             raise _CallSequenceException("No expected event {}.".format(
                 EventMessageWaitingIndicatorChanged))
         voice_mail_count_after = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
@@ -1264,7 +1267,7 @@
         # -1 means there are unread voice mail, but the count is unknown
         if not check_voice_mail_count(log, ad_callee, voice_mail_count_before,
                                       voice_mail_count_after):
-            log.error("telephonyGetVoiceMailCount output is incorrect.")
+            log.error("before and after voice mail count is not incorrect.")
             return False
 
     except _CallSequenceException as e:
@@ -1302,26 +1305,33 @@
         False if error happens. True is succeed.
     """
     log.info("Erase all pending voice mail.")
-    if ad.droid.telephonyGetVoiceMailCount() == 0:
-        log.info("No Pending voice mail.")
+    count = ad.droid.telephonyGetVoiceMailCount()
+    if count == 0:
+        ad.log.info("No Pending voice mail.")
         return True
+    if count == -1:
+        ad.log.info("There is pending voice mail, but the count is unknown")
+        count = MAX_SAVED_VOICE_MAIL
+    else:
+        ad.log.info("There are %s voicemails", count)
 
     voice_mail_number = get_voice_mail_number(log, ad)
-
+    delete_digit = get_voice_mail_delete_digit(get_operator_name(log, ad))
     if not initiate_call(log, ad, voice_mail_number):
-        log.error("Initiate call failed.")
+        log.error("Initiate call to voice mail failed.")
         return False
     time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
     callId = ad.droid.telecomCallGetCallIds()[0]
     time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
-    count = MAX_SAVED_VOICE_MAIL
     while (is_phone_in_call(log, ad) and (count > 0)):
-        log.info("Press 7 to delete voice mail.")
-        ad.droid.telecomCallPlayDtmfTone(callId, VOICEMAIL_DELETE_DIGIT)
+        ad.log.info("Press %s to delete voice mail.", delete_digit)
+        ad.droid.telecomCallPlayDtmfTone(callId, delete_digit)
         ad.droid.telecomCallStopDtmfTone(callId)
         time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
         count -= 1
-    log.info("Voice mail server dropped this call.")
+    if is_phone_in_call(log, ad):
+        hangup_call(log, ad)
+
     # wait for telephonyGetVoiceMailCount to update correct result
     remaining_time = MAX_WAIT_TIME_VOICE_MAIL_COUNT
     while ((remaining_time > 0) and
@@ -1671,6 +1681,18 @@
     return task[0](*task[1])
 
 
+def verify_internet_connection(log, ad):
+    """Verify internet connection by ping test.
+
+    Args:
+        log: log object
+        ad: Android Device Object.
+
+    """
+    ad.log.info("Verify internet connection")
+    return adb_shell_ping(ad, count=5, timeout=60, loss_tolerance=40)
+
+
 def iperf_test_by_adb(log,
                       ad,
                       iperf_server,
@@ -3682,9 +3704,10 @@
             return True
         else:
             ad.log.info("Connecting to wifi %s", wifi_ssid)
-            wifi_test_utils.wifi_connect(ad, network, 1, assert_on_fail=False)
+            ad.droid.wifiConnectByConfig(network)
             time.sleep(20)
             if check_is_wifi_connected(log, ad, wifi_ssid):
+                ad.log.info("Coneected to Wifi %s", wifi_ssid)
                 return True
     ad.log.info("Fail to connected to wifi %s", wifi_ssid)
     return False
diff --git a/acts/framework/tests/acts_relay_controller_test.py b/acts/framework/tests/acts_relay_controller_test.py
new file mode 100755
index 0000000..f16d3f2
--- /dev/null
+++ b/acts/framework/tests/acts_relay_controller_test.py
@@ -0,0 +1,639 @@
+#!/usr/bin/env python
+#
+#   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.
+
+import copy
+import os
+import tempfile
+import shutil
+import unittest
+
+import acts.controllers.relay_lib.errors as errors
+from acts.controllers.relay_lib.relay import Relay
+from acts.controllers.relay_lib.relay import RelayState
+from acts.controllers.relay_lib.relay import SynchronizeRelays
+from acts.controllers.relay_lib.relay_board import RelayBoard
+from acts.controllers.relay_lib.sain_smart_board import SainSmartBoard
+from acts.controllers.relay_lib.relay_rig import RelayRig
+from acts.controllers.relay_lib.generic_relay_device import GenericRelayDevice
+from acts.controllers.relay_lib.relay_device import RelayDevice
+
+
+class MockBoard(RelayBoard):
+    def __init__(self, config):
+        self.relay_states = dict()
+        self.relay_previous_states = dict()
+        RelayBoard.__init__(self, config)
+
+    def get_relay_position_list(self):
+        return [0, 1]
+
+    def get_relay_status(self, relay_position):
+        if relay_position not in self.relay_states:
+            self.relay_states[relay_position] = RelayState.NO
+            self.relay_previous_states[relay_position] = RelayState.NO
+        return self.relay_states[relay_position]
+
+    def set(self, relay_position, state):
+        self.relay_previous_states[relay_position] = self.get_relay_status(
+            relay_position)
+        self.relay_states[relay_position] = state
+        return state
+
+
+class ActsRelayTest(unittest.TestCase):
+    def setUp(self):
+        Relay.transition_wait_time = 0
+        self.config = {
+            'name': 'MockBoard',
+            'relays': [{
+                'name': 'Relay',
+                'relay_pos': 0
+            }]
+        }
+        self.board = MockBoard(self.config)
+        self.relay = Relay(self.board, 'Relay')
+        self.board.set(self.relay.position, RelayState.NO)
+
+    def test_turn_on_from_off(self):
+        self.board.set(self.relay.position, RelayState.NO)
+        self.relay.set_nc()
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NC)
+
+    def test_turn_on_from_on(self):
+        self.board.set(self.relay.position, RelayState.NC)
+        self.relay.set_nc()
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NC)
+
+    def test_turn_off_from_on(self):
+        self.board.set(self.relay.position, RelayState.NC)
+        self.relay.set_no()
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NO)
+
+    def test_turn_off_from_off(self):
+        self.board.set(self.relay.position, RelayState.NO)
+        self.relay.set_no()
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NO)
+
+    def test_toggle_off_to_on(self):
+        self.board.set(self.relay.position, RelayState.NO)
+        self.relay.toggle()
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NC)
+
+    def test_toggle_on_to_off(self):
+        self.board.set(self.relay.position, RelayState.NC)
+        self.relay.toggle()
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NO)
+
+    def test_set_on(self):
+        self.board.set(self.relay.position, RelayState.NO)
+        self.relay.set(RelayState.NC)
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NC)
+
+    def test_set_off(self):
+        self.board.set(self.relay.position, RelayState.NC)
+        self.relay.set(RelayState.NO)
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NO)
+
+    def test_set_foo(self):
+        with self.assertRaises(ValueError):
+            self.relay.set('FOO')
+
+    def test_set_nc_for(self):
+        # Here we set twice so relay_previous_state will also be OFF
+        self.board.set(self.relay.position, RelayState.NO)
+        self.board.set(self.relay.position, RelayState.NO)
+
+        self.relay.set_nc_for(0)
+
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NO)
+        self.assertEqual(self.board.relay_previous_states[self.relay.position],
+                         RelayState.NC)
+
+    def test_set_no_for(self):
+        # Here we set twice so relay_previous_state will also be OFF
+        self.board.set(self.relay.position, RelayState.NC)
+        self.board.set(self.relay.position, RelayState.NC)
+
+        self.relay.set_no_for(0)
+
+        self.assertEqual(
+            self.board.get_relay_status(self.relay.position), RelayState.NC)
+        self.assertEqual(self.board.relay_previous_states[self.relay.position],
+                         RelayState.NO)
+
+    def test_get_status_on(self):
+        self.board.set(self.relay.position, RelayState.NC)
+        self.assertEqual(self.relay.get_status(), RelayState.NC)
+
+    def test_get_status_off(self):
+        self.board.set(self.relay.position, RelayState.NO)
+        self.assertEqual(self.relay.get_status(), RelayState.NO)
+
+    def test_clean_up_default_on(self):
+        new_relay = Relay(self.board, 0)
+        self.board.set(new_relay.position, RelayState.NO)
+        new_relay.clean_up()
+
+        self.assertEqual(
+            self.board.get_relay_status(new_relay.position), RelayState.NO)
+
+    def test_clean_up_default_off(self):
+        new_relay = Relay(self.board, 0)
+        self.board.set(new_relay.position, RelayState.NC)
+        new_relay.clean_up()
+
+        self.assertEqual(
+            self.board.get_relay_status(new_relay.position), RelayState.NO)
+
+
+class ActsSainSmartBoardTest(unittest.TestCase):
+    STATUS_MSG = ('<small><a href="{}"></a>'
+                  '</small><a href="{}/{}TUX">{}TUX</a><p>')
+
+    RELAY_ON_PAGE_CONTENTS = 'relay_on page'
+    RELAY_OFF_PAGE_CONTENTS = 'relay_off page'
+
+    def setUp(self):
+        Relay.transition_wait_time = 0
+        self.test_dir = 'file://' + tempfile.mkdtemp() + '/'
+
+        # Creates the files used for testing
+        self._set_status_page('0000000000000000')
+        with open(self.test_dir[7:] + '00', 'w+') as file:
+            file.write(self.RELAY_OFF_PAGE_CONTENTS)
+        with open(self.test_dir[7:] + '01', 'w+') as file:
+            file.write(self.RELAY_ON_PAGE_CONTENTS)
+
+        self.config = ({
+            'name':
+            'SSBoard',
+            'base_url':
+            self.test_dir,
+            'relays': [{
+                'name': '0',
+                'relay_pos': 0
+            }, {
+                'name': '1',
+                'relay_pos': 1
+            }, {
+                'name': '2',
+                'relay_pos': 7
+            }]
+        })
+        self.ss_board = SainSmartBoard(self.config)
+        self.r0 = Relay(self.ss_board, 0)
+        self.r1 = Relay(self.ss_board, 1)
+        self.r7 = Relay(self.ss_board, 7)
+
+    def tearDown(self):
+        shutil.rmtree(self.test_dir[7:])
+
+    def test_get_url_code(self):
+        result = self.ss_board._get_relay_url_code(self.r0.position,
+                                                   RelayState.NO)
+        self.assertEqual(result, '00')
+
+        result = self.ss_board._get_relay_url_code(self.r0.position,
+                                                   RelayState.NC)
+        self.assertEqual(result, '01')
+
+        result = self.ss_board._get_relay_url_code(self.r7.position,
+                                                   RelayState.NO)
+        self.assertEqual(result, '14')
+
+        result = self.ss_board._get_relay_url_code(self.r7.position,
+                                                   RelayState.NC)
+        self.assertEqual(result, '15')
+
+    def test_load_page_status(self):
+        self._set_status_page('0000111100001111')
+        result = self.ss_board._load_page(SainSmartBoard.HIDDEN_STATUS_PAGE)
+        self.assertTrue(
+            result.endswith(
+                '0000111100001111TUX">0000111100001111TUX</a><p>'))
+
+    def test_load_page_relay(self):
+        result = self.ss_board._load_page('00')
+        self.assertEqual(result, self.RELAY_OFF_PAGE_CONTENTS)
+
+        result = self.ss_board._load_page('01')
+        self.assertEqual(result, self.RELAY_ON_PAGE_CONTENTS)
+
+    def test_load_page_no_connection(self):
+        with self.assertRaises(errors.RelayDeviceConnectionError):
+            self.ss_board._load_page('**')
+
+    def _set_status_page(self, status_16_chars):
+        with open(self.test_dir[7:] + '99', 'w+') as status_file:
+            status_file.write(
+                self.STATUS_MSG.format(self.test_dir[:-1], self.test_dir[:-1],
+                                       status_16_chars, status_16_chars))
+
+    def _test_sync_status_dict(self, status_16_chars):
+        self._set_status_page(status_16_chars)
+        expected_dict = dict()
+
+        for index, char in enumerate(status_16_chars):
+            expected_dict[
+                index] = RelayState.NC if char == '1' else RelayState.NO
+
+        self.ss_board._sync_status_dict()
+        self.assertDictEqual(expected_dict, self.ss_board.status_dict)
+
+    def test_sync_status_dict(self):
+        self._test_sync_status_dict('0000111100001111')
+        self._test_sync_status_dict('0000000000000000')
+        self._test_sync_status_dict('0101010101010101')
+        self._test_sync_status_dict('1010101010101010')
+        self._test_sync_status_dict('1111111111111111')
+
+    def test_get_relay_status_status_dict_none(self):
+        self._set_status_page('1111111111111111')
+        self.ss_board.status_dict = None
+        self.assertEqual(
+            self.ss_board.get_relay_status(self.r0.position), RelayState.NC)
+
+    def test_get_relay_status_status_dict_on(self):
+        self.r0.set(RelayState.NC)
+        self.assertEqual(
+            self.ss_board.get_relay_status(self.r0.position), RelayState.NC)
+
+    def test_get_relay_status_status_dict_off(self):
+        self.r0.set(RelayState.NO)
+        self.assertEqual(
+            self.ss_board.get_relay_status(self.r0.position), RelayState.NO)
+
+    def test_set_on(self):
+        os.utime(self.test_dir[7:] + '01', (0, 0))
+        self.ss_board.set(self.r0.position, RelayState.NC)
+        self.assertNotEqual(os.stat(self.test_dir[7:] + '01').st_atime, 0)
+
+    def test_set_off(self):
+        os.utime(self.test_dir[7:] + '00', (0, 0))
+        self.ss_board.set(self.r0.position, RelayState.NO)
+        self.assertNotEqual(os.stat(self.test_dir[7:] + '00').st_atime, 0)
+
+
+class ActsRelayRigTest(unittest.TestCase):
+    def setUp(self):
+        Relay.transition_wait_time = 0
+        self.config = {
+            'boards': [{
+                'type': 'SainSmartBoard',
+                'name': 'ss_control',
+                'base_url': 'http://192.168.1.4/30000/'
+            }, {
+                'type': 'SainSmartBoard',
+                'name': 'ss_control_2',
+                'base_url': 'http://192.168.1.4/30000/'
+            }],
+            'devices': [{
+                'type':
+                'GenericRelayDevice',
+                'name':
+                'device',
+                'relays': [{
+                    'name': 'Relay00',
+                    'pos': 'ss_control/0'
+                }, {
+                    'name': 'Relay10',
+                    'pos': 'ss_control/1'
+                }]
+            }]
+        }
+
+    def test_init_relay_rig_missing_boards(self):
+        flawed_config = copy.deepcopy(self.config)
+        del flawed_config['boards']
+        with self.assertRaises(errors.RelayConfigError):
+            RelayRig(flawed_config)
+
+    def test_init_relay_rig_is_not_list(self):
+        flawed_config = copy.deepcopy(self.config)
+        flawed_config['boards'] = self.config['boards'][0]
+        with self.assertRaises(errors.RelayConfigError):
+            RelayRig(flawed_config)
+
+    def test_init_relay_rig_duplicate_board_names(self):
+        flawed_config = copy.deepcopy(self.config)
+        flawed_config['boards'][1]['name'] = (self.config['boards'][0]['name'])
+        with self.assertRaises(errors.RelayConfigError):
+            RelayRigMock(flawed_config)
+
+    def test_init_relay_rig_device_gets_relays(self):
+        modded_config = copy.deepcopy(self.config)
+        modded_config['devices'][0]['relays'] = [
+            modded_config['devices'][0]['relays'][0]
+        ]
+        relay_rig = RelayRigMock(modded_config)
+        self.assertEqual(len(relay_rig.relays), 4)
+        self.assertEqual(len(relay_rig.devices['device'].relays), 1)
+
+        relay_rig = RelayRigMock(self.config)
+        self.assertEqual(len(relay_rig.devices['device'].relays), 2)
+
+    def test_init_relay_rig_correct_device_type(self):
+        relay_rig = RelayRigMock(self.config)
+        self.assertEqual(len(relay_rig.devices), 1)
+        self.assertIsInstance(relay_rig.devices['device'], GenericRelayDevice)
+
+    def test_init_relay_rig_missing_devices_creates_generic_device(self):
+        modded_config = copy.deepcopy(self.config)
+        del modded_config['devices']
+        relay_rig = RelayRigMock(modded_config)
+        self.assertEqual(len(relay_rig.devices), 1)
+        self.assertIsInstance(relay_rig.devices['device'], GenericRelayDevice)
+        self.assertDictEqual(relay_rig.devices['device'].relays,
+                             relay_rig.relays)
+
+
+class RelayRigMock(RelayRig):
+    """A RelayRig that substitutes the MockBoard for any board."""
+
+    _board_constructors = {
+        'SainSmartBoard': lambda x: MockBoard(x),
+    }
+
+    def __init__(self, config=None):
+        if not config:
+            config = {
+                "boards": [{
+                    'name': 'MockBoard',
+                    'type': 'SainSmartBoard'
+                }]
+            }
+
+        RelayRig.__init__(self, config)
+
+
+class ActsGenericRelayDeviceTest(unittest.TestCase):
+    def setUp(self):
+        Relay.transition_wait_time = 0
+        self.board_config = {'name': 'MockBoard', 'type': 'SainSmartBoard'}
+
+        self.board = MockBoard(self.board_config)
+        self.r0 = self.board.relays[0]
+        self.r1 = self.board.relays[1]
+
+        self.device_config = {
+            'name':
+            'MockDevice',
+            'relays': [{
+                'name': 'r0',
+                'pos': 'MockBoard/0'
+            }, {
+                'name': 'r1',
+                'pos': 'MockBoard/1'
+            }]
+        }
+        config = {
+            'boards': [self.board_config],
+            'devices': [self.device_config]
+        }
+        self.rig = RelayRigMock(config)
+        self.rig.boards['MockBoard'] = self.board
+        self.rig.relays[self.r0.relay_id] = self.r0
+        self.rig.relays[self.r1.relay_id] = self.r1
+
+    def test_setup_single_relay(self):
+        self.r0.set(RelayState.NC)
+        self.r1.set(RelayState.NC)
+
+        modified_config = copy.deepcopy(self.device_config)
+        del modified_config['relays'][1]
+
+        generic_relay_device = GenericRelayDevice(modified_config, self.rig)
+        generic_relay_device.setup()
+
+        self.assertEqual(self.r0.get_status(), RelayState.NO)
+        self.assertEqual(self.r1.get_status(), RelayState.NC)
+
+    def test_setup_multiple_relays(self):
+        self.board.set(self.r0.position, RelayState.NC)
+        self.board.set(self.r1.position, RelayState.NC)
+
+        generic_relay_device = GenericRelayDevice(self.device_config, self.rig)
+        generic_relay_device.setup()
+
+        self.assertEqual(self.r0.get_status(), RelayState.NO)
+        self.assertEqual(self.r1.get_status(), RelayState.NO)
+
+    def test_cleanup_single_relay(self):
+        self.test_setup_single_relay()
+
+    def test_cleanup_multiple_relays(self):
+        self.test_setup_multiple_relays()
+
+
+class ActsRelayDeviceTest(unittest.TestCase):
+    def setUp(self):
+        Relay.transition_wait_time = 0
+
+        self.board_config = {
+            'name': 'MockBoard',
+            'relays': [{
+                'id': 0,
+                'relay_pos': 0
+            }, {
+                'id': 1,
+                'relay_pos': 1
+            }]
+        }
+
+        self.board = MockBoard(self.board_config)
+        self.r0 = Relay(self.board, 0)
+        self.r1 = Relay(self.board, 1)
+        self.board.set(self.r0.position, RelayState.NO)
+        self.board.set(self.r1.position, RelayState.NO)
+
+        self.rig = RelayRigMock()
+        self.rig.boards['MockBoard'] = self.board
+        self.rig.relays[self.r0.relay_id] = self.r0
+        self.rig.relays[self.r1.relay_id] = self.r1
+
+        self.device_config = {
+            "type":
+            "GenericRelayDevice",
+            "name":
+            "device",
+            "relays": [{
+                'name': 'r0',
+                'pos': 'MockBoard/0'
+            }, {
+                'name': 'r1',
+                'pos': 'MockBoard/1'
+            }]
+        }
+
+    def test_init_raise_on_name_missing(self):
+        flawed_config = copy.deepcopy(self.device_config)
+        del flawed_config['name']
+        with self.assertRaises(errors.RelayConfigError):
+            RelayDevice(flawed_config, self.rig)
+
+    def test_init_raise_on_name_wrong_type(self):
+        flawed_config = copy.deepcopy(self.device_config)
+        flawed_config['name'] = {}
+        with self.assertRaises(errors.RelayConfigError):
+            RelayDevice(flawed_config, self.rig)
+
+    def test_init_raise_on_relays_missing(self):
+        flawed_config = copy.deepcopy(self.device_config)
+        del flawed_config['relays']
+        with self.assertRaises(errors.RelayConfigError):
+            RelayDevice(flawed_config, self.rig)
+
+    def test_init_raise_on_relays_wrong_type(self):
+        flawed_config = copy.deepcopy(self.device_config)
+        flawed_config['relays'] = str
+        with self.assertRaises(errors.RelayConfigError):
+            RelayDevice(flawed_config, self.rig)
+
+    def test_init_raise_on_relays_is_empty(self):
+        flawed_config = copy.deepcopy(self.device_config)
+        flawed_config['relays'] = []
+        with self.assertRaises(errors.RelayConfigError):
+            RelayDevice(flawed_config, self.rig)
+
+    def test_init_raise_on_relays_are_dicts_without_names(self):
+        flawed_config = copy.deepcopy(self.device_config)
+        flawed_config['relays'] = [{'id': 0}, {'id': 1}]
+        with self.assertRaises(errors.RelayConfigError):
+            RelayDevice(flawed_config, self.rig)
+
+    def test_init_raise_on_relays_are_dicts_without_ids(self):
+        flawed_config = copy.deepcopy(self.device_config)
+        flawed_config['relays'] = [{'name': 'r0'}, {'name': 'r1'}]
+        with self.assertRaises(errors.RelayConfigError):
+            RelayDevice(flawed_config, self.rig)
+
+    def test_init_pass_relays_have_ids_and_names(self):
+        RelayDevice(self.device_config, self.rig)
+
+
+class TestRelayRigParser(unittest.TestCase):
+    def setUp(self):
+        Relay.transition_wait_time = 0
+        self.board_config = {
+            'name': 'MockBoard',
+            'relays': [{
+                'id': 'r0',
+                'relay_pos': 0
+            }, {
+                'id': 'r1',
+                'relay_pos': 1
+            }]
+        }
+        self.r0 = self.board_config['relays'][0]
+        self.r1 = self.board_config['relays'][1]
+        self.board = MockBoard(self.board_config)
+
+    def test_create_relay_board_raise_on_missing_type(self):
+        with self.assertRaises(errors.RelayConfigError):
+            RelayRigMock().create_relay_board(self.board_config)
+
+    def test_create_relay_board_valid_config(self):
+        config = copy.deepcopy(self.board_config)
+        config['type'] = 'SainSmartBoard'
+        # Note: we use a raise here because SainSmartBoard requires us to
+        # connect to the status page upon creation. SainSmartBoard is the
+        # only valid board at the moment.
+        RelayRigMock().create_relay_board(config)
+
+    def test_create_relay_board_raise_on_type_not_found(self):
+        flawed_config = copy.deepcopy(self.board_config)
+        flawed_config['type'] = 'NonExistentBoard'
+        with self.assertRaises(errors.RelayConfigError):
+            RelayRigMock().create_relay_board(flawed_config)
+
+    def test_create_relay_device_create_generic_on_missing_type(self):
+        rig = RelayRigMock()
+        rig.relays['r0'] = self.r0
+        rig.relays['r1'] = self.r1
+        config = {
+            'name':
+            'name',
+            'relays': [{
+                'name': 'r0',
+                'pos': 'MockBoard/0'
+            }, {
+                'name': 'r1',
+                'pos': 'MockBoard/1'
+            }]
+        }
+        relay_device = rig.create_relay_device(config)
+        self.assertIsInstance(relay_device, GenericRelayDevice)
+
+    def test_create_relay_device_config_with_type(self):
+        rig = RelayRigMock()
+        rig.relays['r0'] = self.r0
+        rig.relays['r1'] = self.r1
+        config = {
+            'type':
+            'GenericRelayDevice',
+            'name':
+            '.',
+            'relays': [{
+                'name': 'r0',
+                'pos': 'MockBoard/0'
+            }, {
+                'name': 'r1',
+                'pos': 'MockBoard/1'
+            }]
+        }
+        relay_device = rig.create_relay_device(config)
+        self.assertIsInstance(relay_device, GenericRelayDevice)
+
+    def test_create_relay_device_raise_on_type_not_found(self):
+        rig = RelayRigMock()
+        rig.relays['r0'] = self.r0
+        rig.relays['r1'] = self.r1
+        config = {
+            'type':
+            'SomeInvalidType',
+            'name':
+            '.',
+            'relays': [{
+                'name': 'r0',
+                'pos': 'MockBoard/0'
+            }, {
+                'name': 'r1',
+                'pos': 'MockBoard/1'
+            }]
+        }
+        with self.assertRaises(errors.RelayConfigError):
+            rig.create_relay_device(config)
+
+
+class TestSynchronizeRelays(unittest.TestCase):
+    def test_synchronize_relays(self):
+        Relay.transition_wait_time = .1
+        with SynchronizeRelays():
+            self.assertEqual(Relay.transition_wait_time, 0)
+        self.assertEqual(Relay.transition_wait_time, .1)
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/acts/tests/google/ble/gatt/GattReadTest.py b/acts/tests/google/ble/gatt/GattReadTest.py
index 6225dea..764c697 100644
--- a/acts/tests/google/ble/gatt/GattReadTest.py
+++ b/acts/tests/google/ble/gatt/GattReadTest.py
@@ -148,3 +148,51 @@
                          "Read value shall be equal to value sent from server")
 
         return True
+
+    @BluetoothBaseTest.bt_test_wrap
+    def test_read_using_char_uuid(self):
+        """Test read using characteristic UUID.
+
+        Test GATT read value using characteristic UUID.
+
+        Steps:
+        1. Central: send read by UUID request.
+        2. Peripheral: receive read request .
+        3. Peripheral: send read response with status 0 (success), and
+           characteristic value.
+        4. Central: receive read response, verify it's conent matches what was
+           sent
+
+        Expected Result:
+        Verify that read request/response is properly delivered.
+
+        Returns:
+          Pass if True
+          Fail if False
+
+        TAGS: LE, GATT, Characteristic
+        Priority: 0
+        """
+        self.cen_ad.droid.gattClientReadUsingCharacteristicUuid(
+            self.bluetooth_gatt, self.READABLE_CHAR_UUID, 0x0001, 0xFFFF)
+
+        event = self._server_wait(GattEvent.CHAR_READ_REQ)
+
+        request_id = event['data']['requestId']
+        self.assertEqual(0, event['data']['offset'], "offset should be 0")
+
+        bt_device_id = 0
+        status = 0
+        char_value = [1, 2, 3, 4, 5, 6, 7, 20]
+        offset = 0
+        self.per_ad.droid.gattServerSendResponse(self.gatt_server,
+                                                 bt_device_id, request_id,
+                                                 status, offset, char_value)
+
+        event = self._client_wait(GattEvent.CHAR_READ)
+        self.assertEqual(status, event["data"]["Status"],
+                         "Write status should be 0")
+        self.assertEqual(char_value, event["data"]["CharacteristicValue"],
+                         "Read value shall be equal to value sent from server")
+
+        return True
diff --git a/acts/tests/google/tel/live/TelLiveDataTest.py b/acts/tests/google/tel/live/TelLiveDataTest.py
index 490a3a2..6a0972e 100644
--- a/acts/tests/google/tel/live/TelLiveDataTest.py
+++ b/acts/tests/google/tel/live/TelLiveDataTest.py
@@ -72,7 +72,7 @@
 from acts.test_utils.tel.tel_test_utils import stop_wifi_tethering
 from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
 from acts.test_utils.tel.tel_test_utils import toggle_volte
-from acts.test_utils.tel.tel_test_utils import verify_http_connection
+from acts.test_utils.tel.tel_test_utils import verify_internet_connection
 from acts.test_utils.tel.tel_test_utils import verify_incall_state
 from acts.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
 from acts.test_utils.tel.tel_test_utils import wait_for_network_rat
@@ -376,7 +376,8 @@
         self.android_devices[0].droid.telephonyToggleDataConnection(True)
         if (not wait_for_cell_data_connection(self.log,
                                               self.android_devices[0], True) or
-                not verify_http_connection(self.log, self.android_devices[0])):
+                not verify_internet_connection(self.log,
+                                               self.android_devices[0])):
             self.log.error("Data not available on cell")
             return False
 
@@ -396,8 +397,8 @@
             if simultaneous_voice_data:
                 self.log.info("Step3 Verify internet.")
                 time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
-                if not verify_http_connection(self.log,
-                                              self.android_devices[0]):
+                if not verify_internet_connection(self.log,
+                                                  self.android_devices[0]):
                     raise _LocalException("Internet Inaccessible when Enabled")
 
                 self.log.info("Step4 Turn off data and verify not connected.")
@@ -407,7 +408,8 @@
                         self.log, self.android_devices[0], False):
                     raise _LocalException("Failed to Disable Cellular Data")
 
-                if verify_http_connection(self.log, self.android_devices[0]):
+                if verify_internet_connection(self.log,
+                                              self.android_devices[0]):
                     raise _LocalException("Internet Accessible when Disabled")
 
                 self.log.info("Step5 Re-enable data.")
@@ -416,12 +418,12 @@
                 if not wait_for_cell_data_connection(
                         self.log, self.android_devices[0], True):
                     raise _LocalException("Failed to Re-Enable Cellular Data")
-                if not verify_http_connection(self.log,
-                                              self.android_devices[0]):
+                if not verify_internet_connection(self.log,
+                                                  self.android_devices[0]):
                     raise _LocalException("Internet Inaccessible when Enabled")
             else:
                 self.log.info("Step3 Verify no Internet and skip step 4-5.")
-                if verify_http_connection(
+                if verify_internet_connection(
                         self.log, self.android_devices[0], retry=0):
                     raise _LocalException("Internet Accessible.")
 
@@ -433,7 +435,8 @@
             if not hangup_call(self.log, self.android_devices[0]):
                 self.log.error("Failed to hang up call")
                 return False
-            if not verify_http_connection(self.log, self.android_devices[0]):
+            if not verify_internet_connection(self.log,
+                                              self.android_devices[0]):
                 raise _LocalException("Internet Inaccessible when Enabled")
 
         except _LocalException as e:
@@ -683,8 +686,8 @@
             return False
 
         self.log.info("Verify internet")
-        if not verify_http_connection(self.log, provider):
-            provider.log.error("Provider data not available on cell.")
+        if not verify_internet_connection(self.log, provider):
+            provider.log.error("Data not available on cell.")
             return False
 
         # Turn off active SoftAP if any.
@@ -901,7 +904,7 @@
             return False
 
         if (not wait_for_wifi_data_connection(self.log, ads[0], True) or
-                not verify_http_connection(self.log, ads[0])):
+                not verify_internet_connection(self.log, ads[0])):
             self.log.error("Provider data did not return to Wifi")
             return False
         return True
@@ -946,7 +949,7 @@
                 "Disable Data on Provider, verify no data on Client.")
             ads[0].droid.telephonyToggleDataConnection(False)
             time.sleep(WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING)
-            if verify_http_connection(self.log, ads[0]):
+            if verify_internet_connection(self.log, ads[0]):
                 ads[0].log.error("Disable data on provider failed.")
                 return False
             if not ads[0].droid.wifiIsApEnabled():
@@ -962,7 +965,7 @@
             if not wait_for_cell_data_connection(self.log, ads[0], True):
                 ads[0].log.error("Provider failed to enable data connection.")
                 return False
-            if not verify_http_connection(self.log, ads[0]):
+            if not verify_internet_connection(self.log, ads[0]):
                 ads[0].log.error("Provider internet connection check failed.")
                 return False
             if not ads[0].droid.wifiIsApEnabled():
@@ -970,7 +973,7 @@
                 return False
 
             if not check_is_wifi_connected(self.log, ads[1], ssid) or (
-                    not verify_http_connection(self.log, ads[1])):
+                    not verify_internet_connection(self.log, ads[1])):
                 ads[1].log.error("Client wifi connection check failed!")
                 return False
         finally:
@@ -1025,7 +1028,7 @@
                 self.log.error("Provider failed to reselect to 3G.")
                 return False
             time.sleep(WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING)
-            if not verify_http_connection(self.log, ads[0]):
+            if not verify_internet_connection(self.log, ads[0]):
                 self.log.error("Data not available on Provider.")
                 return False
             if not ads[0].droid.wifiIsApEnabled():
@@ -1086,7 +1089,7 @@
                 self.log.error("Provider failed to reselect to 4G.")
                 return False
             time.sleep(WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING)
-            if not verify_http_connection(self.log, ads[0]):
+            if not verify_internet_connection(self.log, ads[0]):
                 self.log.error("Data not available on Provider.")
                 return False
             if not ads[0].droid.wifiIsApEnabled():
@@ -1145,7 +1148,7 @@
             if ads[0].droid.wifiIsApEnabled():
                 self.log.error("Provider WiFi tethering not stopped.")
                 return False
-            if verify_http_connection(self.log, ads[1]):
+            if verify_internet_connection(self.log, ads[1]):
                 self.log.error("Client should not have Internet connection.")
                 return False
             wifi_info = ads[1].droid.wifiGetConnectionInfo()
@@ -1164,7 +1167,7 @@
             if ads[0].droid.wifiIsApEnabled():
                 self.log.error("Provider WiFi tethering should not on.")
                 return False
-            if not verify_http_connection(self.log, ads[0]):
+            if not verify_internet_connection(self.log, ads[0]):
                 self.log.error("Provider should have Internet connection.")
                 return False
         finally:
@@ -1185,7 +1188,8 @@
 
         if (not wait_for_cell_data_connection(self.log,
                                               self.android_devices[0], True) or
-                not verify_http_connection(self.log, self.android_devices[0])):
+                not verify_internet_connection(self.log,
+                                               self.android_devices[0])):
             self.log.error("Failed cell data call for entitlement check.")
             return False
 
@@ -1446,9 +1450,9 @@
                 self.log.error("Setup Call Failed.")
                 return False
             self.log.info("3. Verify data.")
-            if not verify_http_connection(self.log, provider):
+            if not verify_internet_connection(self.log, provider):
                 self.log.error("Provider have no Internet access.")
-            if not verify_http_connection(self.log, client):
+            if not verify_internet_connection(self.log, client):
                 self.log.error("Client have no Internet access.")
             hangup_call(self.log, provider)
 
@@ -1464,9 +1468,9 @@
                 self.log.error("Setup Call Failed.")
                 return False
             self.log.info("5. Verify data.")
-            if not verify_http_connection(self.log, provider):
+            if not verify_internet_connection(self.log, provider):
                 self.log.error("Provider have no Internet access.")
-            if not verify_http_connection(self.log, client):
+            if not verify_internet_connection(self.log, client):
                 self.log.error("Client have no Internet access.")
             hangup_call(self.log, provider)
 
@@ -1628,7 +1632,7 @@
         if ((not ensure_wifi_connected(self.log, ads[0],
                                        self.wifi_network_ssid,
                                        self.wifi_network_pass)) or
-            (not verify_http_connection(self.log, ads[0]))):
+            (not verify_internet_connection(self.log, ads[0]))):
             self.log.error("WiFi connect fail.")
             return False
 
@@ -1659,7 +1663,7 @@
 
             self.log.info("Make sure WiFi can connect automatically.")
             if (not wait_for_wifi_data_connection(self.log, ads[0], True) or
-                    not verify_http_connection(self.log, ads[0])):
+                    not verify_internet_connection(self.log, ads[0])):
                 self.log.error("Data did not return to WiFi")
                 return False
 
@@ -1696,7 +1700,7 @@
         if ((not ensure_wifi_connected(self.log, ads[0],
                                        self.wifi_network_ssid,
                                        self.wifi_network_pass)) or
-            (not verify_http_connection(self.log, ads[0]))):
+            (not verify_internet_connection(self.log, ads[0]))):
             self.log.error("WiFi connect fail.")
             return False
 
@@ -1752,7 +1756,7 @@
                 "Turn off screen on provider: <{}>.".format(ads[0].serial))
             ads[0].droid.goToSleepNow()
             time.sleep(60)
-            if not verify_http_connection(self.log, ads[1]):
+            if not verify_internet_connection(self.log, ads[1]):
                 self.log.error("Client have no Internet access.")
                 return False
 
@@ -1762,7 +1766,7 @@
                 self.log.error("Failed to enable doze mode.")
                 return False
             time.sleep(60)
-            if not verify_http_connection(self.log, ads[1]):
+            if not verify_internet_connection(self.log, ads[1]):
                 self.log.error("Client have no Internet access.")
                 return False
         finally:
@@ -1811,7 +1815,7 @@
                 voice_or_data=NETWORK_SERVICE_DATA):
             self.log.error("Device data does not attach to 2G.")
             return False
-        if not verify_http_connection(self.log, ad):
+        if not verify_internet_connection(self.log, ad):
             self.log.error("No Internet access on default Data SIM.")
             return False
 
@@ -1866,8 +1870,8 @@
                 self.log.error("Failed wifi connection, aborting!")
                 return False
 
-            if not verify_http_connection(self.log, ad,
-                                          'http://www.google.com', 100, .1):
+            if not verify_internet_connection(
+                    self.log, ad, 'http://www.google.com', 100, .1):
                 self.log.error("Failed to get user-plane traffic, aborting!")
                 return False
 
@@ -1882,8 +1886,8 @@
                 self.log.error("Failed wifi connection, aborting!")
                 return False
 
-            if not verify_http_connection(self.log, ad,
-                                          'http://www.google.com', 100, .1):
+            if not verify_internet_connection(
+                    self.log, ad, 'http://www.google.com', 100, .1):
                 self.log.error("Failed to get user-plane traffic, aborting!")
                 return False
         return True
@@ -2037,11 +2041,11 @@
                 self.log.error("Provider WiFi tethering stopped.")
                 return False
             if not is_data_available_during_call:
-                if verify_http_connection(self.log, ads[1], retry=0):
+                if verify_internet_connection(self.log, ads[1], retry=0):
                     self.log.error("Client should not have Internet Access.")
                     return False
             else:
-                if not verify_http_connection(self.log, ads[1]):
+                if not verify_internet_connection(self.log, ads[1]):
                     self.log.error("Client should have Internet Access.")
                     return False
 
@@ -2052,7 +2056,7 @@
             if not ads[0].droid.wifiIsApEnabled():
                 self.log.error("Provider WiFi tethering stopped.")
                 return False
-            if not verify_http_connection(self.log, ads[1]):
+            if not verify_internet_connection(self.log, ads[1]):
                 self.log.error("Client should have Internet Access.")
                 return False
         finally:
@@ -2162,7 +2166,7 @@
                     self.log.error("Failed to change data SIM.")
                     return False
                 current_sim_slot_index = next_sim_slot_index
-                if not verify_http_connection(self.log, ads[1]):
+                if not verify_internet_connection(self.log, ads[1]):
                     self.log.error("Client should have Internet Access.")
                     return False
         finally:
@@ -2210,7 +2214,7 @@
                 voice_or_data=NETWORK_SERVICE_DATA):
             self.log.error("Device data does not attach to 2G.")
             return False
-        if not verify_http_connection(self.log, ad):
+        if not verify_internet_connection(self.log, ad):
             self.log.error("No Internet access on default Data SIM.")
             return False
 
@@ -2220,7 +2224,7 @@
             self.log.error("WiFi connect fail.")
             return False
         if (not wait_for_wifi_data_connection(self.log, ad, True) or
-                not verify_http_connection(self.log, ad)):
+                not verify_internet_connection(self.log, ad)):
             self.log.error("Data is not on WiFi")
             return False
 
@@ -2235,7 +2239,7 @@
                 self.log.error("Failed to attach data on subId:{}".format(
                     next_data_sub_id))
                 return False
-            if not verify_http_connection(self.log, ad):
+            if not verify_internet_connection(self.log, ad):
                 self.log.error("No Internet access after changing Data SIM.")
                 return False
 
@@ -2282,7 +2286,7 @@
                 voice_or_data=NETWORK_SERVICE_DATA):
             self.log.error("Device data does not attach to 2G.")
             return False
-        if not verify_http_connection(self.log, ad):
+        if not verify_internet_connection(self.log, ad):
             self.log.error("No Internet access on default Data SIM.")
             return False
 
diff --git a/acts/tests/google/tel/live/TelLiveSmsTest.py b/acts/tests/google/tel/live/TelLiveSmsTest.py
index 1e9468f..3032ce4 100644
--- a/acts/tests/google/tel/live/TelLiveSmsTest.py
+++ b/acts/tests/google/tel/live/TelLiveSmsTest.py
@@ -449,8 +449,8 @@
         else:
             return self._mms_test_mt_after_call_hangup(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="480b6ba2-1e5f-4a58-9d88-9b75c8fab1b6")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_general(self):
         """Test SMS basic function between two phone. Phones in any network.
 
@@ -472,8 +472,8 @@
 
         return self._sms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="aa87fe73-8236-44c7-865c-3fe3b733eeb4")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_general(self):
         """Test SMS basic function between two phone. Phones in any network.
 
@@ -495,8 +495,8 @@
 
         return self._sms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="57db830c-71eb-46b3-adaa-915c641de18d")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_general(self):
         """Test MMS basic function between two phone. Phones in any network.
 
@@ -518,8 +518,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="f2779e1e-7d09-43f0-8b5c-87eae5d146be")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_general(self):
         """Test MMS basic function between two phone. Phones in any network.
 
@@ -541,8 +541,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="2c229a4b-c954-4ba3-94ba-178dc7784d03")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_2g(self):
         """Test SMS basic function between two phone. Phones in 3g network.
 
@@ -564,8 +564,8 @@
 
         return self._sms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="17fafc41-7e12-47ab-a4cc-fb9bd94e79b9")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_2g(self):
         """Test SMS basic function between two phone. Phones in 3g network.
 
@@ -587,8 +587,8 @@
 
         return self._sms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="b4919317-18b5-483c-82f4-ced37a04f28d")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_2g(self):
         """Test MMS basic function between two phone. Phones in 3g network.
 
@@ -610,8 +610,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="cd56bb8a-0794-404d-95bd-c5fd00f4b35a")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_2g(self):
         """Test MMS basic function between two phone. Phones in 3g network.
 
@@ -633,8 +633,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="b39fbc30-9cc2-4d86-a9f4-6f0c1dd0a905")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_2g_wifi(self):
         """Test MMS basic function between two phone. Phones in 3g network.
 
@@ -659,8 +659,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="b158a0a7-9697-4b3b-8d5b-f9b6b6bc1c03")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_2g_wifi(self):
         """Test MMS basic function between two phone. Phones in 3g network.
 
@@ -685,8 +685,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="f094e3da-2523-4f92-a1f3-7cf9edcff850")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_3g(self):
         """Test SMS basic function between two phone. Phones in 3g network.
 
@@ -709,8 +709,8 @@
 
         return self._sms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="2186e152-bf83-4d6e-93eb-b4bf9ae2d76e")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_3g(self):
         """Test SMS basic function between two phone. Phones in 3g network.
 
@@ -733,8 +733,8 @@
 
         return self._sms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="e716c678-eee9-4a0d-a9cd-ca9eae4fea51")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_3g(self):
         """Test MMS basic function between two phone. Phones in 3g network.
 
@@ -757,8 +757,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="e864a99e-d935-4bd9-95f6-8183cdd3d760")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_3g(self):
         """Test MMS basic function between two phone. Phones in 3g network.
 
@@ -781,8 +781,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="c6cfba55-6cde-41cd-93bb-667c317a0127")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_3g_wifi(self):
         """Test MMS basic function between two phone. Phones in 3g network.
 
@@ -808,8 +808,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="83c5dd99-f2fe-433d-9775-80a36d0d493b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_3g_wifi(self):
         """Test MMS basic function between two phone. Phones in 3g network.
 
@@ -835,8 +835,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="c97687e2-155a-4cf3-9f51-22543b89d53e")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_4g(self):
         """Test SMS basic function between two phone. Phones in LTE network.
 
@@ -860,8 +860,8 @@
 
         return self._sms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="e2e01a47-2b51-4d00-a7b2-dbd3c8ffa6ae")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_4g(self):
         """Test SMS basic function between two phone. Phones in LTE network.
 
@@ -886,8 +886,8 @@
 
         return self._sms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="5795143c-5252-4536-9fd3-b28e83124e1c")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_4g(self):
         """Test MMS text function between two phone. Phones in LTE network.
 
@@ -910,8 +910,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="dc24361c-713f-45eb-ac7b-a34c649f1c36")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_4g(self):
         """Test MMS text function between two phone. Phones in LTE network.
 
@@ -934,8 +934,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="c7349fdf-a376-4846-b466-1f329bd1557f")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_4g_wifi(self):
         """Test MMS text function between two phone. Phones in LTE network.
 
@@ -960,8 +960,8 @@
                               self.wifi_network_pass)
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="1affab34-e03c-49dd-9062-e9ed8eac406b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_4g_wifi(self):
         """Test MMS text function between two phone. Phones in LTE network.
 
@@ -987,8 +987,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="7ee57edb-2962-4d20-b6eb-79cebce91fff")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_in_call_volte(self):
         """ Test MO SMS during a MO VoLTE call.
 
@@ -1023,8 +1023,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="5576276b-4ca1-41cc-bb74-31ccd71f9f96")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_in_call_volte(self):
         """ Test MT SMS during a MO VoLTE call.
 
@@ -1059,8 +1059,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="3bf8ff74-baa6-4dc6-86eb-c13816fa9bc8")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_volte(self):
         """ Test MO MMS during a MO VoLTE call.
 
@@ -1095,8 +1095,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="289e6516-5f66-403a-b292-50d067151730")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_volte(self):
         """ Test MT MMS during a MO VoLTE call.
 
@@ -1131,8 +1131,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="5654d974-3c32-4cce-9d07-0c96213dacc5")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_volte_wifi(self):
         """ Test MO MMS during a MO VoLTE call.
 
@@ -1170,8 +1170,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="cbd5ab3d-d76a-4ece-ac09-62efeead7550")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_volte_wifi(self):
         """ Test MT MMS during a MO VoLTE call.
 
@@ -1209,8 +1209,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="516457ae-5f99-41c1-b145-bfe72876b872")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_in_call_wcdma(self):
         """ Test MO SMS during a MO wcdma call.
 
@@ -1235,8 +1235,8 @@
 
         return self._mo_sms_in_3g_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="d99697f4-5be2-46f2-9d95-aa73b5d9cebc")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_in_call_wcdma(self):
         """ Test MT SMS during a MO wcdma call.
 
@@ -1261,8 +1261,8 @@
 
         return self._mt_sms_in_3g_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="2a2d64cc-88db-4ec0-9c2d-1da24a0f9eaf")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_wcdma(self):
         """ Test MO MMS during a MO wcdma call.
 
@@ -1287,8 +1287,8 @@
 
         return self._mo_mms_in_3g_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="20df9556-a8af-4346-97b8-b97596d146a4")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_wcdma(self):
         """ Test MT MMS during a MO wcdma call.
 
@@ -1313,8 +1313,8 @@
 
         return self._mt_mms_in_3g_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="c4a39519-44d8-4194-8dfc-68b1dd723b39")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_wcdma_wifi(self):
         """ Test MO MMS during a MO wcdma call.
 
@@ -1342,8 +1342,8 @@
 
         return self._mo_mms_in_3g_call(ads, wifi=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="bcc5b02d-2fef-431a-8c0b-f31c98999bfb")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_wcdma_wifi(self):
         """ Test MT MMS during a MO wcdma call.
 
@@ -1371,8 +1371,8 @@
                               self.wifi_network_pass)
         return self._mt_mms_in_3g_call(ads, wifi=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="b6e9ce80-8577-48e5-baa7-92780932f278")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_in_call_csfb(self):
         """ Test MO SMS during a MO csfb wcdma/gsm call.
 
@@ -1397,8 +1397,8 @@
 
         return self._mo_sms_in_csfb_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="93f0b58a-01e9-4bc9-944f-729d455597dd")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_in_call_csfb(self):
         """ Test MT SMS during a MO csfb wcdma/gsm call.
 
@@ -1423,8 +1423,8 @@
 
         return self._mt_sms_in_csfb_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="bd8e9e80-1955-429f-b122-96b127771bbb")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_csfb(self):
         """ Test MO MMS during a MO csfb wcdma/gsm call.
 
@@ -1449,8 +1449,8 @@
 
         return self._mo_mms_in_csfb_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="89d65fd2-fc75-4fc5-a018-2d05a4364304")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_csfb(self):
         """ Test MT MMS during a MO csfb wcdma/gsm call.
 
@@ -1475,8 +1475,8 @@
 
         return self._mt_mms_in_csfb_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="9c542b5d-3b8f-4d4a-80de-fb804f066c3d")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_csfb_wifi(self):
         """ Test MO MMS during a MO csfb wcdma/gsm call.
 
@@ -1504,8 +1504,8 @@
 
         return self._mo_mms_in_csfb_call(ads, wifi=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="c1bed6f5-f65c-4f4d-aa06-0e9f5c867819")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_csfb_wifi(self):
         """ Test MT MMS during a MO csfb wcdma/gsm call.
 
@@ -1533,8 +1533,8 @@
 
         return self._mt_mms_in_csfb_call(ads, wifi=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="60996028-b4b2-4a16-9e4b-eb6ef80179a7")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_in_call_1x(self):
         """ Test MO SMS during a MO 1x call.
 
@@ -1559,8 +1559,8 @@
 
         return self._mo_sms_in_1x_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="6b352aac-9b4e-4062-8980-3b1c0e61015b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_in_call_1x(self):
         """ Test MT SMS during a MO 1x call.
 
@@ -1585,8 +1585,8 @@
 
         return self._mt_sms_in_1x_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="cfae3613-c490-4ce0-b00b-c13286d85027")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_1x(self):
         """ Test MO MMS during a MO 1x call.
 
@@ -1612,8 +1612,8 @@
 
         return self._mo_mms_in_1x_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="4311cb8c-626d-48a9-955b-6505b41c7519")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_1x(self):
         """ Test MT MMS during a MO 1x call.
 
@@ -1638,8 +1638,8 @@
 
         return self._mt_mms_in_1x_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="18093f87-aab5-4d86-b178-8085a1651828")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_1x_wifi(self):
         """ Test MO MMS during a MO 1x call.
 
@@ -1667,8 +1667,8 @@
 
         return self._mo_mms_in_1x_call(ads, wifi=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="8fe3359a-0857-401f-a043-c47a2a2acb47")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_1x_wifi(self):
         """ Test MT MMS during a MO 1x call.
 
@@ -1695,8 +1695,8 @@
 
         return self._mt_mms_in_1x_call(ads, wifi=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="96214c7c-2843-4242-8cfa-1d08241514b0")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_in_call_csfb_1x(self):
         """ Test MO SMS during a MO csfb 1x call.
 
@@ -1721,8 +1721,8 @@
 
         return self._mo_sms_in_1x_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="3780a8e5-2649-45e6-bf6b-9ab1e86456eb")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_in_call_csfb_1x(self):
         """ Test MT SMS during a MO csfb 1x call.
 
@@ -1747,8 +1747,8 @@
 
         return self._mt_sms_in_1x_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="5de29f86-1aa8-46ff-a679-97309c314fe2")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_csfb_1x(self):
         """ Test MO MMS during a MO csfb 1x call.
 
@@ -1773,8 +1773,8 @@
 
         return self._mo_mms_in_1x_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="29ed3fea-0409-4b43-9caf-dbbaac7d430f")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_csfb_1x(self):
         """ Test MT MMS during a MO csfb 1x call.
 
@@ -1799,8 +1799,8 @@
 
         return self._mt_mms_in_1x_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="12e05635-7934-4f14-a27e-430d0fc52edb")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_csfb_1x_wifi(self):
         """ Test MO MMS during a MO csfb 1x call.
 
@@ -1827,8 +1827,8 @@
 
         return self._mo_mms_in_1x_call(ads, wifi=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="bd884be7-756b-4f0f-b233-052dc79233c0")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_csfb_1x_wifi(self):
         """ Test MT MMS during a MO csfb 1x call.
 
@@ -1855,8 +1855,8 @@
 
         return self._mt_mms_in_1x_call(ads, wifi=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="ed720013-e366-448b-8901-bb09d26cea05")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_iwlan(self):
         """ Test MO SMS, Phone in APM, WiFi connected, WFC WiFi Preferred mode.
 
@@ -1881,8 +1881,8 @@
 
         return self._sms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="4d4b0b7b-bf00-44f6-a0ed-23b438c30fc2")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_iwlan(self):
         """ Test MT SMS, Phone in APM, WiFi connected, WFC WiFi Preferred mode.
 
@@ -1907,8 +1907,8 @@
 
         return self._sms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="30139605-fdb0-4f8f-8772-2f56addb6f21")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_iwlan(self):
         """ Test MO MMS, Phone in APM, WiFi connected, WFC WiFi Preferred mode.
 
@@ -1933,8 +1933,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="d1e1b686-fa16-4715-9506-be2e2b1e1a96")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_iwlan(self):
         """ Test MT MMS, Phone in APM, WiFi connected, WFC WiFi Preferred mode.
 
@@ -1959,8 +1959,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="075933a2-df7f-4374-a405-92f96bcc7770")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_apm_wifi_wfc_off(self):
         """ Test MO SMS, Phone in APM, WiFi connected, WFC off.
 
@@ -1983,8 +1983,8 @@
 
         return self._sms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="637af228-29fc-4b74-a963-883f66ddf080")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_apm_wifi_wfc_off(self):
         """ Test MT SMS, Phone in APM, WiFi connected, WFC off.
 
@@ -2007,8 +2007,8 @@
 
         return self._sms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="502aba0d-8895-4807-b394-50a44208ecf7")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_apm_wifi_wfc_off(self):
         """ Test MO MMS, Phone in APM, WiFi connected, WFC off.
 
@@ -2031,8 +2031,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="235bfdbf-4275-4d89-99f5-41b5b7de8345")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_apm_wifi_wfc_off(self):
         """ Test MT MMS, Phone in APM, WiFi connected, WFC off.
 
@@ -2055,8 +2055,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="e5a31b94-1cb6-4770-a2bc-5a0ddba51502")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_in_call_iwlan(self):
         """ Test MO SMS, Phone in APM, WiFi connected, WFC WiFi Preferred mode.
 
@@ -2092,8 +2092,8 @@
 
         return self._sms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="d6d30cc5-f75b-42df-b517-401456ee8466")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_in_call_iwlan(self):
         """ Test MT SMS, Phone in APM, WiFi connected, WFC WiFi Preferred mode.
 
@@ -2129,8 +2129,8 @@
 
         return self._sms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="54e4244a-2c8b-4350-9b2c-ade6e05b1494")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_iwlan(self):
         """ Test MO MMS, Phone in APM, WiFi connected, WFC WiFi Preferred mode.
 
@@ -2166,8 +2166,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="6cf9d2a3-b476-4855-95d7-ce4b426a0a2f")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_iwlan(self):
         """ Test MT MMS, Phone in APM, WiFi connected, WFC WiFi Preferred mode.
 
@@ -2203,8 +2203,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="9f1933bb-c4cb-4655-8655-327c1f38e8ee")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_in_call_vt(self):
         """ Test MO SMS, Phone in ongoing VT call.
 
@@ -2236,8 +2236,8 @@
 
         return self._sms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="0a07e737-4862-4492-9b48-8d94799eab91")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_in_call_vt(self):
         """ Test MT SMS, Phone in ongoing VT call.
 
@@ -2269,8 +2269,8 @@
 
         return self._sms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="80254125-861f-4f3d-9164-eb9a2699152e")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_vt(self):
         """ Test MO MMS, Phone in ongoing VT call.
 
@@ -2302,8 +2302,8 @@
 
         return self._mms_test_mo(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="a46074f0-304b-4bb0-a2da-5102ee2be619")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_vt(self):
         """ Test MT MMS, Phone in ongoing VT call.
 
@@ -2335,8 +2335,8 @@
 
         return self._mms_test_mt(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="c60c89ba-ff72-425d-9ac0-93cb2ee5a0bc")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mo_in_call_gsm(self):
         """ Test MO SMS during a MO gsm call.
 
@@ -2375,8 +2375,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="ba55daf2-89b9-450c-9832-732fd9413410")
+    @TelephonyBaseTest.tel_test_wrap
     def test_sms_mt_in_call_gsm(self):
         """ Test MT SMS during a MO gsm call.
 
@@ -2415,8 +2415,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="2bd94d69-3621-4b94-abc7-bd24c4325485")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_gsm(self):
         """ Test MO MMS during a MO gsm call.
 
@@ -2441,8 +2441,8 @@
 
         return self._mo_mms_in_2g_call(ads)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="e20be70d-99d6-4344-a742-f69581b66d8f")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_gsm(self):
         """ Test MT MMS during a MO gsm call.
 
@@ -2468,6 +2468,7 @@
         return self._mt_mms_in_2g_call(ads)
 
     @test_tracker_info(uuid="3510d368-4b16-4716-92a3-9dd01842ba79")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mo_in_call_gsm_wifi(self):
         """ Test MO MMS during a MO gsm call.
 
@@ -2494,8 +2495,8 @@
 
         return self._mo_mms_in_2g_call(ads, wifi=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="060def89-01bd-4b44-a49b-a4536fe39165")
+    @TelephonyBaseTest.tel_test_wrap
     def test_mms_mt_in_call_gsm_wifi(self):
         """ Test MT MMS during a MO gsm call.
 
diff --git a/acts/tests/google/tel/live/TelLiveVoiceTest.py b/acts/tests/google/tel/live/TelLiveVoiceTest.py
index e843cfc..fa9db92 100644
--- a/acts/tests/google/tel/live/TelLiveVoiceTest.py
+++ b/acts/tests/google/tel/live/TelLiveVoiceTest.py
@@ -110,7 +110,8 @@
 from acts.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
 
 DEFAULT_LONG_DURATION_CALL_TOTAL_DURATION = 1 * 60 * 60  # default value 1 hour
-DEFAULT_PING_DURATION = 120 # in seconds
+DEFAULT_PING_DURATION = 120  # in seconds
+
 
 class TelLiveVoiceTest(TelephonyBaseTest):
     def __init__(self, controllers):
@@ -174,8 +175,8 @@
         return two_phone_call_short_seq(self.log, ads[1], None, None, ads[0],
                                         None, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="b2de097b-70e1-4242-b555-c1aa0a5acd8c")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_volte(self):
         """ VoLTE to VoLTE call test
 
@@ -200,8 +201,8 @@
             phone_idle_volte, is_phone_in_call_volte, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="3c7f5a09-0177-4469-9994-cd5e7dd7c7fe")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_volte_7_digit_dialing(self):
         """ VoLTE to VoLTE call test, dial with 7 digit number
 
@@ -225,17 +226,16 @@
                                                        7)
         try:
             set_phone_number(self.log, ads[1], caller_dialing_number)
-            result = call_setup_teardown(
+            return call_setup_teardown(
                 self.log, ads[0], ads[1], ads[0], is_phone_in_call_volte,
                 is_phone_in_call_volte, WAIT_TIME_IN_CALL_FOR_IMS)
         except Exception as e:
             self.log.error("Exception happened: {}".format(e))
         finally:
             set_phone_number(self.log, ads[1], callee_default_number)
-        return result
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="721ef935-a03c-4d0f-85b9-4753d857162f")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_volte_10_digit_dialing(self):
         """ VoLTE to VoLTE call test, dial with 10 digit number
 
@@ -259,17 +259,16 @@
                                                        10)
         try:
             set_phone_number(self.log, ads[1], caller_dialing_number)
-            result = call_setup_teardown(
+            return call_setup_teardown(
                 self.log, ads[0], ads[1], ads[0], is_phone_in_call_volte,
                 is_phone_in_call_volte, WAIT_TIME_IN_CALL_FOR_IMS)
         except Exception as e:
             self.log.error("Exception happened: {}".format(e))
         finally:
             set_phone_number(self.log, ads[1], callee_default_number)
-        return result
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="4fd3aa62-2398-4cee-994e-7fc5cadbcbc1")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_volte_11_digit_dialing(self):
         """ VoLTE to VoLTE call test, dial with 11 digit number
 
@@ -293,17 +292,16 @@
                                                        11)
         try:
             set_phone_number(self.log, ads[1], caller_dialing_number)
-            result = call_setup_teardown(
+            return call_setup_teardown(
                 self.log, ads[0], ads[1], ads[0], is_phone_in_call_volte,
                 is_phone_in_call_volte, WAIT_TIME_IN_CALL_FOR_IMS)
         except Exception as e:
             self.log.error("Exception happened: {}".format(e))
         finally:
             set_phone_number(self.log, ads[1], callee_default_number)
-        return result
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="969abdac-6a57-442a-9c40-48199bd8d556")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_volte_12_digit_dialing(self):
         """ VoLTE to VoLTE call test, dial with 12 digit number
 
@@ -327,17 +325,16 @@
                                                        12)
         try:
             set_phone_number(self.log, ads[1], caller_dialing_number)
-            result = call_setup_teardown(
+            return call_setup_teardown(
                 self.log, ads[0], ads[1], ads[0], is_phone_in_call_volte,
                 is_phone_in_call_volte, WAIT_TIME_IN_CALL_FOR_IMS)
         except Exception as e:
             self.log.error("Exception happened: {}".format(e))
         finally:
             set_phone_number(self.log, ads[1], callee_default_number)
-        return result
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="6b13a03d-c9ff-43d7-9798-adbead7688a4")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_csfb_3g(self):
         """ VoLTE to CSFB 3G call test
 
@@ -361,8 +358,8 @@
             self.log, ads[0], phone_idle_volte, is_phone_in_call_volte, ads[1],
             phone_idle_csfb, is_phone_in_call_csfb, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="38096fdb-324a-4ce0-8836-8bbe713cffc2")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_csfb_for_tmo(self):
         """ VoLTE to CSFB 3G call test for TMobile
 
@@ -386,8 +383,8 @@
                                         None, ads[1], phone_idle_csfb,
                                         is_phone_in_call_csfb, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="82f9515d-a52b-4dec-93a5-997ffdbca76c")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_csfb_1x_long(self):
         """ VoLTE to CSFB 1x call test
 
@@ -418,8 +415,8 @@
             self.log, ads[0], phone_idle_volte, is_phone_in_call_volte, ads[1],
             phone_idle_csfb, is_phone_in_call_1x, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="2e57fad6-5eaf-4e7d-8353-8aa6f4c52776")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_csfb_long(self):
         """ VoLTE to CSFB WCDMA call test
 
@@ -450,8 +447,8 @@
             self.log, ads[0], phone_idle_volte, is_phone_in_call_volte, ads[1],
             phone_idle_csfb, is_phone_in_call_csfb, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="4bab759f-7610-4cec-893c-0a8aed95f70c")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_3g(self):
         """ VoLTE to 3G call test
 
@@ -475,8 +472,8 @@
             self.log, ads[0], phone_idle_volte, is_phone_in_call_volte, ads[1],
             phone_idle_3g, is_phone_in_call_3g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="b394cdc5-d88d-4659-8a26-0e58fde69974")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_3g_1x_long(self):
         """ VoLTE to 3G 1x call test
 
@@ -506,8 +503,8 @@
             self.log, ads[0], phone_idle_volte, is_phone_in_call_volte, ads[1],
             phone_idle_3g, is_phone_in_call_1x, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="b39a74a9-2a89-4c0b-ac4e-71ed9317bd75")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_3g_wcdma_long(self):
         """ VoLTE to 3G WCDMA call test
 
@@ -538,8 +535,8 @@
             self.log, ads[0], phone_idle_volte, is_phone_in_call_volte, ads[1],
             phone_idle_3g, is_phone_in_call_wcdma, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="573bbcf1-6cbd-4084-9cb7-e14fb6c9521e")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_2g(self):
         """ VoLTE to 2G call test
 
@@ -586,10 +583,10 @@
         Returns:
             True if pass; False if fail.
         """
-        tasks = [(phone_setup_iwlan,
-                  (self.log, ads[0], apm_mode, wfc_mode, wifi_ssid, wifi_pwd)),
-                 (phone_setup_iwlan,
-                  (self.log, ads[1], apm_mode, wfc_mode, wifi_ssid, wifi_pwd))]
+        tasks = [(phone_setup_iwlan, (self.log, ads[0], apm_mode, wfc_mode,
+                                      wifi_ssid, wifi_pwd)),
+                 (phone_setup_iwlan, (self.log, ads[1], apm_mode, wfc_mode,
+                                      wifi_ssid, wifi_pwd))]
         if not multithread_func(self.log, tasks):
             self.log.error("Phone Failed to Set Up Properly.")
             return False
@@ -613,8 +610,8 @@
             self.log.error("ICMP transfer failed with parallel phone call.")
             return False
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="a4a043c0-f4ba-4405-9262-42c752cc4487")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_wfc_wifi_only(self):
         """ WiFi Only, WiFi calling to WiFi Calling test
 
@@ -630,8 +627,8 @@
             self.android_devices, False, WFC_MODE_WIFI_ONLY,
             self.wifi_network_ssid, self.wifi_network_pass)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="ae171d58-d4c1-43f7-aa93-4860b4b28d53")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_wfc_wifi_preferred(self):
         """ WiFi Preferred, WiFi calling to WiFi Calling test
 
@@ -647,8 +644,8 @@
             self.android_devices, False, WFC_MODE_WIFI_PREFERRED,
             self.wifi_network_ssid, self.wifi_network_pass)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="ece58857-fedc-49a9-bf10-b76bd78a51f2")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_wfc_cellular_preferred(self):
         """ Cellular Preferred, WiFi calling to WiFi Calling test
 
@@ -674,8 +671,8 @@
             self.log, ads[0], None, is_phone_in_call_not_iwlan, ads[1], None,
             is_phone_in_call_not_iwlan, None, WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="0d63c250-d9e7-490c-8c48-0a6afbad5f88")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_apm_wfc_wifi_only(self):
         """ Airplane + WiFi Only, WiFi calling to WiFi Calling test
 
@@ -691,8 +688,8 @@
             self.android_devices, True, WFC_MODE_WIFI_ONLY,
             self.wifi_network_ssid, self.wifi_network_pass)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="7678e4ee-29c6-4319-93ab-d555501d1876")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_apm_wfc_wifi_preferred(self):
         """ Airplane + WiFi Preferred, WiFi calling to WiFi Calling test
 
@@ -708,8 +705,8 @@
             self.android_devices, True, WFC_MODE_WIFI_PREFERRED,
             self.wifi_network_ssid, self.wifi_network_pass)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="8f5c637e-683a-448d-9443-b2b39626ab19")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_apm_wfc_cellular_preferred(self):
         """ Airplane + Cellular Preferred, WiFi calling to WiFi Calling test
 
@@ -725,8 +722,8 @@
             self.android_devices, True, WFC_MODE_CELLULAR_PREFERRED,
             self.wifi_network_ssid, self.wifi_network_pass)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="0b51666e-c83c-40b5-ba0f-737e64bc82a2")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_volte_wfc_wifi_only(self):
         """ WiFi Only, WiFi calling to VoLTE test
 
@@ -753,8 +750,8 @@
             phone_idle_volte, is_phone_in_call_volte, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="6e0630a9-63b2-4ea1-8ec9-6560f001905c")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_volte_wfc_wifi_preferred(self):
         """ WiFi Preferred, WiFi calling to VoLTE test
 
@@ -781,8 +778,8 @@
             phone_idle_volte, is_phone_in_call_volte, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="51077985-2229-491f-9a54-1ff53871758c")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_volte_apm_wfc_wifi_only(self):
         """ Airplane + WiFi Only, WiFi calling to VoLTE test
 
@@ -809,8 +806,8 @@
             phone_idle_volte, is_phone_in_call_volte, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="fff9edcd-1ace-4f2d-a09b-06f3eea56cca")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_volte_apm_wfc_wifi_preferred(self):
         """ Airplane + WiFi Preferred, WiFi calling to VoLTE test
 
@@ -837,8 +834,8 @@
             phone_idle_volte, is_phone_in_call_volte, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="8591554e-4e38-406c-97bf-8921d5329c47")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_csfb_3g_wfc_wifi_only(self):
         """ WiFi Only, WiFi calling to CSFB 3G test
 
@@ -864,8 +861,8 @@
             self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
             phone_idle_csfb, is_phone_in_call_csfb, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="9711888d-5b1e-4d05-86e9-98f94f46098b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_csfb_3g_wfc_wifi_preferred(self):
         """ WiFi Preferred, WiFi calling to CSFB 3G test
 
@@ -891,8 +888,8 @@
             self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
             phone_idle_csfb, is_phone_in_call_csfb, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="902c96a4-858f-43ff-bd56-6d7d27004320")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_csfb_3g_apm_wfc_wifi_only(self):
         """ Airplane + WiFi Only, WiFi calling to CSFB 3G test
 
@@ -918,8 +915,8 @@
             self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
             phone_idle_csfb, is_phone_in_call_csfb, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="362a5396-ebda-4706-a73a-d805e5028fd7")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_csfb_3g_apm_wfc_wifi_preferred(self):
         """ Airplane + WiFi Preferred, WiFi calling to CSFB 3G test
 
@@ -945,8 +942,8 @@
             self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
             phone_idle_csfb, is_phone_in_call_csfb, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="647bb859-46bc-4e3e-b6ab-7944d3bbcc26")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_3g_wfc_wifi_only(self):
         """ WiFi Only, WiFi calling to 3G test
 
@@ -972,8 +969,8 @@
             self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
             phone_idle_3g, is_phone_in_call_3g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="3688ea1f-a52d-4a35-9df4-d5ed0985e49b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_3g_wfc_wifi_preferred(self):
         """ WiFi Preferred, WiFi calling to 3G test
 
@@ -999,8 +996,8 @@
             self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
             phone_idle_3g, is_phone_in_call_3g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="f4efc821-fbaf-4ec2-b89b-5a47354344f0")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_3g_apm_wfc_wifi_only(self):
         """ Airplane + WiFi Only, WiFi calling to 3G test
 
@@ -1026,8 +1023,8 @@
             self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
             phone_idle_3g, is_phone_in_call_3g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="2b1345b7-3b62-44bd-91ad-9c5a4925b0e1")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_3g_apm_wfc_wifi_preferred(self):
         """ Airplane + WiFi Preferred, WiFi calling to 3G test
 
@@ -1053,8 +1050,8 @@
             self.log, ads[0], phone_idle_iwlan, is_phone_in_call_iwlan, ads[1],
             phone_idle_3g, is_phone_in_call_3g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="7b3fea22-114a-442e-aa12-dde3b6001681")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_csfb_3g_to_csfb_3g(self):
         """ CSFB 3G to CSFB 3G call test
 
@@ -1078,8 +1075,8 @@
             self.log, ads[0], phone_idle_csfb, is_phone_in_call_csfb, ads[1],
             phone_idle_csfb, is_phone_in_call_csfb, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="91d751ea-40c8-4ffc-b9d3-03d0ad0902bd")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_3g_to_3g(self):
         """ 3G to 3G call test
 
@@ -1103,8 +1100,8 @@
             self.log, ads[0], phone_idle_3g, is_phone_in_call_3g, ads[1],
             phone_idle_3g, is_phone_in_call_3g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="df57c481-010a-4d21-a5c1-5116917871b2")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_volte_long(self):
         """ VoLTE to VoLTE call test
 
@@ -1131,8 +1128,8 @@
             phone_idle_volte, is_phone_in_call_volte, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="b0712d8a-71cf-405f-910c-8592da082660")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_long_wfc_wifi_only(self):
         """ WiFi Only, WiFi calling to WiFi Calling test
 
@@ -1163,8 +1160,8 @@
             phone_idle_iwlan, is_phone_in_call_iwlan, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="7049de19-3abf-48df-868f-18d0af829393")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_long_wfc_wifi_preferred(self):
         """ WiFi Preferred, WiFi calling to WiFi Calling test
 
@@ -1195,8 +1192,8 @@
             phone_idle_iwlan, is_phone_in_call_iwlan, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="029af2a7-aba4-406b-9095-b32da57a7cdb")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_long_apm_wfc_wifi_only(self):
         """ Airplane + WiFi Only, WiFi calling to WiFi Calling test
 
@@ -1227,8 +1224,8 @@
             phone_idle_iwlan, is_phone_in_call_iwlan, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="2b926e4a-f493-41fa-98af-20d25ec132bb")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_long_apm_wfc_wifi_preferred(self):
         """ Airplane + WiFi Preferred, WiFi calling to WiFi Calling test
 
@@ -1259,8 +1256,8 @@
             phone_idle_iwlan, is_phone_in_call_iwlan, None,
             WAIT_TIME_IN_CALL_FOR_IMS)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="30d5d573-043f-4d8b-98e0-e7f7bc9b8d6f")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_csfb_3g_to_csfb_3g_long(self):
         """ CSFB 3G to CSFB 3G call test
 
@@ -1286,8 +1283,8 @@
             self.log, ads[0], phone_idle_csfb, is_phone_in_call_csfb, ads[1],
             phone_idle_csfb, is_phone_in_call_csfb, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="54768178-818f-4126-9e50-4f49e43a6fd3")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_3g_to_3g_long(self):
         """ 3G to 3G call test
 
@@ -1313,8 +1310,8 @@
             self.log, ads[0], phone_idle_3g, is_phone_in_call_3g, ads[1],
             phone_idle_3g, is_phone_in_call_3g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_to_volte_loop(self):
         """ Stress test: VoLTE to VoLTE call test
 
@@ -1362,14 +1359,14 @@
         self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
             success_count, fail_count,
             str(100 * success_count / (success_count + fail_count))))
-        if success_count / (success_count + fail_count
-                            ) >= MINIMUM_SUCCESS_RATE:
+        if success_count / (
+                success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
             return True
         else:
             return False
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="dfa2c1a7-0e9a-42f2-b3ba-7e196df87e1b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_loop_wfc_wifi_only(self):
         """ Stress test: WiFi Only, WiFi calling to WiFi Calling test
 
@@ -1421,14 +1418,14 @@
         self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
             success_count, fail_count,
             str(100 * success_count / (success_count + fail_count))))
-        if success_count / (success_count + fail_count
-                            ) >= MINIMUM_SUCCESS_RATE:
+        if success_count / (
+                success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
             return True
         else:
             return False
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="382f97ad-65d4-4ebb-a31b-aa243e01bce4")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_loop_wfc_wifi_preferred(self):
         """ Stress test: WiFi Preferred, WiFi Calling to WiFi Calling test
 
@@ -1480,14 +1477,14 @@
         self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
             success_count, fail_count,
             str(100 * success_count / (success_count + fail_count))))
-        if success_count / (success_count + fail_count
-                            ) >= MINIMUM_SUCCESS_RATE:
+        if success_count / (
+                success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
             return True
         else:
             return False
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="c820e2ea-8a14-421c-b608-9074b716f7dd")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_loop_apm_wfc_wifi_only(self):
         """ Stress test: Airplane + WiFi Only, WiFi Calling to WiFi Calling test
 
@@ -1539,14 +1536,14 @@
         self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
             success_count, fail_count,
             str(100 * success_count / (success_count + fail_count))))
-        if success_count / (success_count + fail_count
-                            ) >= MINIMUM_SUCCESS_RATE:
+        if success_count / (
+                success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
             return True
         else:
             return False
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="3b8cb344-1551-4244-845d-b864501f2fb4")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_to_epdg_loop_apm_wfc_wifi_preferred(self):
         """ Stress test: Airplane + WiFi Preferred, WiFi Calling to WiFi Calling test
 
@@ -1598,14 +1595,14 @@
         self.log.info("Final Count - Success: {}, Failure: {} - {}%".format(
             success_count, fail_count,
             str(100 * success_count / (success_count + fail_count))))
-        if success_count / (success_count + fail_count
-                            ) >= MINIMUM_SUCCESS_RATE:
+        if success_count / (
+                success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
             return True
         else:
             return False
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_csfb_3g_to_csfb_3g_loop(self):
         """ Stress test: CSFB 3G to CSFB 3G call test
 
@@ -1651,14 +1648,14 @@
 
         self.log.info("Final Count - Success: {}, Failure: {}".format(
             success_count, fail_count))
-        if success_count / (success_count + fail_count
-                            ) >= MINIMUM_SUCCESS_RATE:
+        if success_count / (
+                success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
             return True
         else:
             return False
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_3g_to_3g_loop(self):
         """ Stress test: 3G to 3G call test
 
@@ -1704,8 +1701,8 @@
 
         self.log.info("Final Count - Success: {}, Failure: {}".format(
             success_count, fail_count))
-        if success_count / (success_count + fail_count
-                            ) >= MINIMUM_SUCCESS_RATE:
+        if success_count / (
+                success_count + fail_count) >= MINIMUM_SUCCESS_RATE:
             return True
         else:
             return False
@@ -1767,8 +1764,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="4043c68a-c5d4-4e1d-9010-ef65b205cab1")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_mo_hold_unhold_wfc_wifi_only(self):
         """ WiFi Only, WiFi calling MO call hold/unhold test
 
@@ -1812,8 +1809,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="0667535e-dcad-49f0-9b4b-fa45d6c75f5b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_mo_hold_unhold_wfc_wifi_preferred(self):
         """ WiFi Preferred, WiFi calling MO call hold/unhold test
 
@@ -1857,8 +1854,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="cf318b4c-c920-4e80-b73f-2f092c03a144")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_mo_hold_unhold_apm_wfc_wifi_only(self):
         """ Airplane + WiFi Only, WiFi calling MO call hold/unhold test
 
@@ -1902,8 +1899,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="ace36801-1e7b-4f06-aa0b-17affc8df069")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_mo_hold_unhold_apm_wfc_wifi_preferred(self):
         """ Airplane + WiFi Preferred, WiFi calling MO call hold/unhold test
 
@@ -1947,8 +1944,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="2ad32874-0d39-4475-8ae3-d6dccda675f5")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_mt_hold_unhold_wfc_wifi_only(self):
         """ WiFi Only, WiFi calling MT call hold/unhold test
 
@@ -1992,8 +1989,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="3efd5d59-30ee-45f5-8966-56ce8fadf9a1")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_mt_hold_unhold_wfc_wifi_preferred(self):
         """ WiFi Preferred, WiFi calling MT call hold/unhold test
 
@@ -2037,8 +2034,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="35ed0f89-7435-4d3b-9ebc-c5cdc3f7e32b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_mt_hold_unhold_apm_wfc_wifi_only(self):
         """ Airplane + WiFi Only, WiFi calling MT call hold/unhold test
 
@@ -2082,8 +2079,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info("37ad003b-6426-42f7-b528-ec7c1842fd18")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_epdg_mt_hold_unhold_apm_wfc_wifi_preferred(self):
         """ Airplane + WiFi Preferred, WiFi calling MT call hold/unhold test
 
@@ -2127,8 +2124,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="fa37cd37-c30a-4caa-80b4-52507995ec77")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_mo_hold_unhold(self):
         """ VoLTE MO call hold/unhold test
 
@@ -2170,8 +2167,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="28a9acb3-83e8-4dd1-82bf-173da8bd2eca")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_volte_mt_hold_unhold(self):
         """ VoLTE MT call hold/unhold test
 
@@ -2213,8 +2210,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="ffe724ae-4223-4c15-9fed-9aba17de9a63")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_wcdma_mo_hold_unhold(self):
         """ MO WCDMA hold/unhold test
 
@@ -2260,8 +2257,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="23805165-01ce-4351-83d3-73c9fb3bda76")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_wcdma_mt_hold_unhold(self):
         """ MT WCDMA hold/unhold test
 
@@ -2307,8 +2304,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="08c846c7-1978-4ece-8f2c-731129947699")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_csfb_mo_hold_unhold(self):
         """ MO CSFB WCDMA/GSM hold/unhold test
 
@@ -2354,8 +2351,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="a6405fe6-c732-4ae6-bbae-e912a124f4a2")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_csfb_mt_hold_unhold(self):
         """ MT CSFB WCDMA/GSM hold/unhold test
 
@@ -2401,8 +2398,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="5edc5034-90ef-4113-926f-05407ed60a87")
+    @TelephonyBaseTest.tel_test_wrap
     def test_erase_all_pending_voicemail(self):
         """Script for TMO/ATT/SPT phone to erase all pending voice mail.
         This script only works if phone have already set up voice mail options,
@@ -2430,8 +2427,8 @@
         return call_voicemail_erase_all_pending_voicemail(
             self.log, self.android_devices[1])
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="c81156a2-089b-4b10-ba80-7afea61d06c6")
+    @TelephonyBaseTest.tel_test_wrap
     def test_voicemail_indicator_volte(self):
         """Test Voice Mail notification in LTE (VoLTE enabled).
         This script currently only works for TMO now.
@@ -2458,8 +2455,8 @@
         return two_phone_call_leave_voice_mail(self.log, ads[0], None, None,
                                                ads[1], phone_idle_volte)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="529e12cb-3178-4d2c-b155-d5cfb1eac0c9")
+    @TelephonyBaseTest.tel_test_wrap
     def test_voicemail_indicator_lte(self):
         """Test Voice Mail notification in LTE (VoLTE disabled).
         This script currently only works for TMO/ATT/SPT now.
@@ -2486,8 +2483,8 @@
         return two_phone_call_leave_voice_mail(self.log, ads[0], None, None,
                                                ads[1], phone_idle_csfb)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="60cef7dd-f990-4913-af9a-75e9336fc80a")
+    @TelephonyBaseTest.tel_test_wrap
     def test_voicemail_indicator_3g(self):
         """Test Voice Mail notification in 3G
         This script currently only works for TMO/ATT/SPT now.
@@ -2514,8 +2511,8 @@
         return two_phone_call_leave_voice_mail(self.log, ads[0], None, None,
                                                ads[1], phone_idle_3g)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="e4c83cfa-db60-4258-ab69-15f7de3614b0")
+    @TelephonyBaseTest.tel_test_wrap
     def test_voicemail_indicator_2g(self):
         """Test Voice Mail notification in 2G
         This script currently only works for TMO/ATT/SPT now.
@@ -2542,8 +2539,8 @@
         return two_phone_call_leave_voice_mail(self.log, ads[1], None, None,
                                                ads[0], phone_idle_2g)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="f0cb02fb-a028-43da-9c87-5b21b2f8549b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_voicemail_indicator_iwlan(self):
         """Test Voice Mail notification in WiFI Calling
         This script currently only works for TMO now.
@@ -2572,8 +2569,8 @@
         return two_phone_call_leave_voice_mail(self.log, ads[0], None, None,
                                                ads[1], phone_idle_iwlan)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="9bd0550e-abfd-436b-912f-571810f973d7")
+    @TelephonyBaseTest.tel_test_wrap
     def test_voicemail_indicator_apm_iwlan(self):
         """Test Voice Mail notification in WiFI Calling
         This script currently only works for TMO now.
@@ -2602,8 +2599,8 @@
         return two_phone_call_leave_voice_mail(self.log, ads[0], None, None,
                                                ads[1], phone_idle_iwlan)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="cfc94b2c-8e28-4e6f-b4d3-1cc8af18a52b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_2g_to_2g(self):
         """ Test 2g<->2g call functionality.
 
@@ -2627,8 +2624,8 @@
             self.log, ads[0], phone_idle_2g, is_phone_in_call_2g, ads[1],
             phone_idle_2g, is_phone_in_call_2g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="057a2213-8b78-497b-8d65-e6ed87d337cb")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_2g_to_2g_long(self):
         """ Test 2g<->2g call functionality.
 
@@ -2654,8 +2651,8 @@
             self.log, ads[0], phone_idle_2g, is_phone_in_call_2g, ads[1],
             phone_idle_2g, is_phone_in_call_2g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="6e24e64f-aa0e-4101-89ed-4cc30c738c7e")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_3g_to_2g_long(self):
         """ Test 3g<->2g call functionality.
 
@@ -2681,8 +2678,8 @@
             self.log, ads[0], phone_idle_2g, is_phone_in_call_3g, ads[1],
             phone_idle_2g, is_phone_in_call_2g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="0db7fc8b-4f83-4e30-80ab-cc53c8eff99f")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_2g_to_3g_long(self):
         """ Test 2g<->3g call functionality.
 
@@ -2708,8 +2705,8 @@
             self.log, ads[0], phone_idle_2g, is_phone_in_call_2g, ads[1],
             phone_idle_2g, is_phone_in_call_3g, None)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="d109df55-ac2f-493f-9324-9be1d3d7d6d3")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_gsm_mo_hold_unhold(self):
         """ Test GSM call hold/unhold functionality.
 
@@ -2754,8 +2751,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="a8279cda-73b3-470a-8ca7-a331ef99270b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_gsm_mt_hold_unhold(self):
         """ Test GSM call hold/unhold functionality.
 
@@ -2812,8 +2809,8 @@
             verify_caller_func=dut_incall_check_func,
             wait_time_in_call=total_duration)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="d0008b51-25ed-414a-9b82-3ffb139a6e0d")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_long_duration_volte(self):
         """ Test call drop rate for VoLTE long duration call.
 
@@ -2840,8 +2837,8 @@
         return self._test_call_long_duration(
             is_phone_in_call_volte, self.long_duration_call_total_duration)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="d4c1aec0-df05-403f-954c-496faf18605a")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_long_duration_wfc(self):
         """ Test call drop rate for WiFi Calling long duration call.
 
@@ -2870,8 +2867,8 @@
         return self._test_call_long_duration(
             is_phone_in_call_iwlan, self.long_duration_call_total_duration)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="bc44f3ca-2616-4024-b959-3a5a85503dfd")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_long_duration_3g(self):
         """ Test call drop rate for 3G long duration call.
 
@@ -2941,8 +2938,8 @@
 
         return True
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="ef4fb42d-9040-46f2-9626-d0a2e1dd854f")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mo_hangup_while_ringing(self):
         """ Call a phone and verify ringing, then hangup from the originator
 
@@ -2957,8 +2954,8 @@
         return self._test_call_hangup_while_ringing(self.android_devices[0],
                                                     self.android_devices[1])
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="f514ac72-d551-4e21-b5af-bd87b6cdf34a")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mt_hangup_while_ringing(self):
         """ Call a phone and verify ringing, then hangup from the originator
 
@@ -3043,14 +3040,13 @@
             self.log.info("Data transfer succeeded.")
             return True
         elif not allow_data_transfer_interruption:
-            self.log.error(
-                "Data transfer failed with parallel phone call.")
+            self.log.error("Data transfer failed with parallel phone call.")
             return False
         self.log.info("Retry data transfer after call hung up")
         return download_task[0](*download_task[1])
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="aa40e7e1-e64a-480b-86e4-db2242449555")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mo_voice_general_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3070,8 +3066,8 @@
         return self._test_call_setup_in_active_data_transfer(
             None, DIRECTION_MOBILE_ORIGINATED)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="d750d66b-2091-4e8d-baa2-084b9d2bbff5")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mt_voice_general_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3091,8 +3087,8 @@
         return self._test_call_setup_in_active_data_transfer(
             None, DIRECTION_MOBILE_TERMINATED)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="35703e83-b3e6-40af-aeaf-6b983d6205f4")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mo_voice_volte_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3115,8 +3111,8 @@
         return self._test_call_setup_in_active_data_transfer(
             GEN_4G, DIRECTION_MOBILE_ORIGINATED)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="a0f658d9-4212-44db-b3e8-7202f1eec04d")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mt_voice_volte_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3139,8 +3135,8 @@
         return self._test_call_setup_in_active_data_transfer(
             GEN_4G, DIRECTION_MOBILE_TERMINATED)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="e0b264ec-fc29-411e-b018-684b7ff5a37e")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mo_voice_csfb_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3165,8 +3161,8 @@
             DIRECTION_MOBILE_ORIGINATED,
             allow_data_transfer_interruption=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="98f04a27-74e1-474d-90d1-a4a45cdb6f5b")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mt_voice_csfb_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3191,8 +3187,8 @@
             DIRECTION_MOBILE_TERMINATED,
             allow_data_transfer_interruption=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="359b1ee1-36a6-427b-9d9e-4d77231fcb09")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mo_voice_3g_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3217,8 +3213,8 @@
             DIRECTION_MOBILE_ORIGINATED,
             allow_data_transfer_interruption=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="b172bbb4-2d6e-4d83-a381-ebfdf23bc30e")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mt_voice_3g_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3243,8 +3239,8 @@
             DIRECTION_MOBILE_TERMINATED,
             allow_data_transfer_interruption=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="f5d9bfd0-0996-4c18-b11e-c6113dc201e2")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mo_voice_2g_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3269,8 +3265,8 @@
             DIRECTION_MOBILE_ORIGINATED,
             allow_data_transfer_interruption=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="99cfd1be-b992-48bf-a50e-fc3eec8e5a67")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mt_voice_2g_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3295,8 +3291,8 @@
             DIRECTION_MOBILE_TERMINATED,
             allow_data_transfer_interruption=True)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="12677cf2-40d3-4bb1-8afa-91ebcbd0f862")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mo_voice_wifi_wfc_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3319,8 +3315,8 @@
         return self._test_call_setup_in_active_data_transfer(
             None, DIRECTION_MOBILE_ORIGINATED)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="84adcc19-43bb-4ea3-9284-7322ab139aac")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mt_voice_wifi_wfc_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3343,8 +3339,8 @@
         return self._test_call_setup_in_active_data_transfer(
             None, DIRECTION_MOBILE_TERMINATED)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="42566255-c33f-406c-abab-932a0aaa01a8")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mo_voice_apm_wifi_wfc_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
@@ -3367,8 +3363,8 @@
         return self._test_call_setup_in_active_data_transfer(
             None, DIRECTION_MOBILE_ORIGINATED)
 
-    @TelephonyBaseTest.tel_test_wrap
     @test_tracker_info(uuid="fbf52f60-449b-46f2-9486-36d338a1b070")
+    @TelephonyBaseTest.tel_test_wrap
     def test_call_mt_voice_apm_wifi_wfc_in_active_data_transfer(self):
         """Test call can be established during active data connection.
 
diff --git a/acts/tests/google/tel/live/TelWifiVoiceTest.py b/acts/tests/google/tel/live/TelWifiVoiceTest.py
index cf283ef..d6317cb 100755
--- a/acts/tests/google/tel/live/TelWifiVoiceTest.py
+++ b/acts/tests/google/tel/live/TelWifiVoiceTest.py
@@ -87,8 +87,10 @@
 from acts.test_utils.tel.tel_voice_utils import phone_idle_volte
 
 # Attenuator name
-ATTEN_NAME_FOR_WIFI = 'wifi0'
-ATTEN_NAME_FOR_CELL = 'cell0'
+ATTEN_NAME_FOR_WIFI_2G = 'wifi0'
+ATTEN_NAME_FOR_WIFI_5G = 'wifi1'
+ATTEN_NAME_FOR_CELL_3G = 'cell0'
+ATTEN_NAME_FOR_CELL_4G = 'cell1'
 
 # WiFi RSSI settings for ROVE_IN test
 WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN = -60
@@ -111,146 +113,6 @@
 class TelWifiVoiceTest(TelephonyBaseTest):
     def __init__(self, controllers):
         TelephonyBaseTest.__init__(self, controllers)
-        self.tests = (
-            # WFC Call Routing tests.
-            # epdg, WFC, APM, WiFi strong
-            "test_call_epdg_wfc_wifi_only_wifi_strong_apm",
-            "test_call_epdg_wfc_wifi_preferred_wifi_strong_apm",
-            "test_call_epdg_wfc_cellular_preferred_wifi_strong_apm",
-
-            # epdg, WFC, APM, WiFi Absent
-            "test_call_epdg_wfc_wifi_only_wifi_absent_apm",
-            "test_call_epdg_wfc_wifi_preferred_wifi_absent_apm",
-            "test_call_epdg_wfc_cellular_preferred_wifi_absent_apm",
-
-            # epdg, WFC, APM, WiFi Disabled
-            "test_call_epdg_wfc_wifi_only_wifi_disabled_apm",
-            "test_call_epdg_wfc_wifi_preferred_wifi_disabled_apm",
-            "test_call_epdg_wfc_cellular_preferred_wifi_disabled_apm",
-
-            # epdg, WFC, cellular strong, WiFi strong
-            "test_call_epdg_wfc_wifi_preferred_wifi_strong_cellular_strong",
-            "test_call_epdg_wfc_cellular_preferred_wifi_strong_cellular_strong",
-
-            # epdg, WFC, cellular strong, WiFi weak
-            "test_call_epdg_wfc_wifi_preferred_wifi_weak_cellular_strong",
-            "test_call_epdg_wfc_cellular_preferred_wifi_weak_cellular_strong",
-
-            # epdg, WFC, cellular strong, WiFi Absent
-            "test_call_epdg_wfc_wifi_preferred_wifi_absent_cellular_strong",
-            "test_call_epdg_wfc_cellular_preferred_wifi_absent_cellular_strong",
-
-            # epdg, WFC, cellular strong, WiFi Disabled
-            "test_call_epdg_wfc_wifi_preferred_wifi_disabled_cellular_strong",
-            "test_call_epdg_wfc_cellular_preferred_wifi_disabled_cellular_strong",
-
-            # epdg, WFC, cellular weak, WiFi strong
-            "test_call_epdg_wfc_wifi_preferred_wifi_strong_cellular_weak",
-
-            # epdg, WFC, cellular weak, WiFi Absent=
-            "test_call_epdg_wfc_wifi_preferred_wifi_absent_cellular_weak",
-            "test_call_epdg_wfc_cellular_preferred_wifi_absent_cellular_weak",
-
-            # epdg, WFC, cellular weak, WiFi Disabled
-            "test_call_epdg_wfc_wifi_preferred_wifi_disabled_cellular_weak",
-            "test_call_epdg_wfc_cellular_preferred_wifi_disabled_cellular_weak",
-
-            # epdg, WiFI strong, WFC disabled
-            "test_call_epdg_wfc_disabled_wifi_strong_apm",
-            "test_call_epdg_wfc_disabled_wifi_strong_cellular_strong",
-            "test_call_epdg_wfc_disabled_wifi_strong_cellular_weak",
-
-            # WFC Idle-Mode Mobility
-            # Rove-in, Rove-out test
-            "test_rove_in_lte_wifi_preferred",
-            "test_rove_in_lte_wifi_only",
-            "test_rove_in_wcdma_wifi_preferred",
-            "test_rove_in_wcdma_wifi_only",
-            "test_rove_out_lte_wifi_preferred",
-            "test_rove_out_lte_wifi_only",
-            "test_rove_out_wcdma_wifi_preferred",
-            "test_rove_out_wcdma_wifi_only",
-            "test_rove_out_in_stress",
-
-            # WFC Active-Mode Mobility
-            # Hand-in, Hand-out test
-            "test_hand_out_wifi_only",
-            "test_hand_out_wifi_preferred",
-            "test_hand_out_in_wifi_preferred",
-            "test_hand_in_wifi_preferred",
-            "test_hand_in_out_wifi_preferred",
-            "test_hand_out_in_stress",
-
-            # WFC test with E4G disabled
-            "test_call_epdg_wfc_wifi_preferred_e4g_disabled",
-            "test_call_epdg_wfc_wifi_preferred_e4g_disabled_wifi_not_connected",
-            "test_call_epdg_wfc_wifi_preferred_e4g_disabled_leave_wifi_coverage",
-
-            # ePDG Active-Mode Mobility: Hand-in, Hand-out test
-            "test_hand_out_cellular_preferred",
-            "test_hand_in_cellular_preferred",
-
-            # epdg, WFC, cellular weak, WiFi strong
-            "test_call_epdg_wfc_wifi_only_wifi_strong_cellular_weak",
-            "test_call_epdg_wfc_cellular_preferred_wifi_strong_cellular_weak",
-
-            # epdg, WFC, cellular weak, WiFi weak
-            "test_call_epdg_wfc_wifi_only_wifi_weak_cellular_weak",
-            "test_call_epdg_wfc_wifi_preferred_wifi_weak_cellular_weak",
-            "test_call_epdg_wfc_cellular_preferred_wifi_weak_cellular_weak",
-
-            # epdg, WFC, cellular weak, WiFi Absent
-            "test_call_epdg_wfc_wifi_only_wifi_absent_cellular_weak",
-
-            # epdg, WFC, cellular weak, WiFi Disabled
-            "test_call_epdg_wfc_wifi_only_wifi_disabled_cellular_weak",
-
-            # epdg, WFC, cellular absent, WiFi strong
-            "test_call_epdg_wfc_wifi_only_wifi_strong_cellular_absent",
-            "test_call_epdg_wfc_wifi_preferred_wifi_strong_cellular_absent",
-            "test_call_epdg_wfc_cellular_preferred_wifi_strong_cellular_absent",
-
-            # epdg, WFC, cellular absent, WiFi weak
-            "test_call_epdg_wfc_wifi_only_wifi_weak_cellular_absent",
-            "test_call_epdg_wfc_wifi_preferred_wifi_weak_cellular_absent",
-            "test_call_epdg_wfc_cellular_preferred_wifi_weak_cellular_absent",
-
-            # epdg, WFC, cellular absent, WiFi Absent
-            "test_call_epdg_wfc_wifi_only_wifi_absent_cellular_absent",
-            "test_call_epdg_wfc_wifi_preferred_wifi_absent_cellular_absent",
-            "test_call_epdg_wfc_cellular_preferred_wifi_absent_cellular_absent",
-
-            # epdg, WFC, cellular absent, WiFi Disabled
-            "test_call_epdg_wfc_wifi_only_wifi_disabled_cellular_absent",
-            "test_call_epdg_wfc_wifi_preferred_wifi_disabled_cellular_absent",
-            "test_call_epdg_wfc_cellular_preferred_wifi_disabled_cellular_absent",
-
-            # epdg, WiFI strong, WFC disabled
-            "test_call_epdg_wfc_disabled_wifi_strong_cellular_absent",
-
-            # Below test fail now, because:
-            # 1. wifi weak not working now. (phone don't rove-in)
-            # 2. wifi-only mode not working now.
-            # epdg, WFC, APM, WiFi weak
-            "test_call_epdg_wfc_wifi_only_wifi_weak_apm",
-            "test_call_epdg_wfc_wifi_preferred_wifi_weak_apm",
-            "test_call_epdg_wfc_cellular_preferred_wifi_weak_apm",
-
-            # epdg, WFC, cellular strong, WiFi strong
-            "test_call_epdg_wfc_wifi_only_wifi_strong_cellular_strong",
-
-            # epdg, WFC, cellular strong, WiFi weak
-            "test_call_epdg_wfc_wifi_only_wifi_weak_cellular_strong",
-
-            # epdg, WFC, cellular strong, WiFi Absent
-            "test_call_epdg_wfc_wifi_only_wifi_absent_cellular_strong",
-
-            # epdg, WFC, cellular strong, WiFi Disabled
-            "test_call_epdg_wfc_wifi_only_wifi_disabled_cellular_strong",
-
-            # RSSI monitoring
-            "test_rssi_monitoring", )
-
         self.stress_test_number = self.get_stress_test_number()
         self.live_network_ssid = self.user_params["wifi_network_ssid"]
 
@@ -274,10 +136,15 @@
             0].droid.telephonyStartTrackingSignalStrengthChange()
 
         # Do WiFi RSSI calibration.
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI], 0,
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
                  MAX_RSSI_RESERVED_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL], 0,
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
                  MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+
         if not ensure_network_generation(
                 self.log,
                 self.android_devices[0],
@@ -335,10 +202,13 @@
     def teardown_test(self):
 
         super().teardown_test()
-
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI], 0,
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
                  MAX_RSSI_RESERVED_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL], 0,
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
                  MAX_RSSI_RESERVED_VALUE)
         return True
 
@@ -855,74 +725,110 @@
 
     def _wfc_set_wifi_strong_cell_strong(self):
         self.log.info("--->Setting WiFi strong cell strong<---")
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
-                 self.wifi_rssi_with_no_atten, MAX_RSSI_RESERVED_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
-                 self.cell_rssi_with_no_atten, MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
         return True
 
     def _wfc_set_wifi_strong_cell_weak(self):
         self.log.info("--->Setting WiFi strong cell weak<---")
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
-                 self.wifi_rssi_with_no_atten, MAX_RSSI_RESERVED_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
-                 self.cell_rssi_with_no_atten, CELL_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 CELL_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 CELL_WEAK_RSSI_VALUE)
         return True
 
     def _wfc_set_wifi_strong_cell_absent(self):
         self.log.info("--->Setting WiFi strong cell absent<---")
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
-                 self.wifi_rssi_with_no_atten, MAX_RSSI_RESERVED_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
-                 self.cell_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
         return True
 
     def _wfc_set_wifi_weak_cell_strong(self):
         self.log.info("--->Setting WiFi weak cell strong<---")
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
-                 self.wifi_rssi_with_no_atten, WIFI_WEAK_RSSI_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
-                 self.cell_rssi_with_no_atten, MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+                 WIFI_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 WIFI_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
         return True
 
     def _wfc_set_wifi_weak_cell_weak(self):
         self.log.info("--->Setting WiFi weak cell weak<---")
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
-                 self.cell_rssi_with_no_atten, CELL_WEAK_RSSI_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
-                 self.wifi_rssi_with_no_atten, WIFI_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+                 WIFI_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 WIFI_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 CELL_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 CELL_WEAK_RSSI_VALUE)
         return True
 
     def _wfc_set_wifi_weak_cell_absent(self):
         self.log.info("--->Setting WiFi weak cell absent<---")
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
-                 self.wifi_rssi_with_no_atten, WIFI_WEAK_RSSI_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
-                 self.cell_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+                 WIFI_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 WIFI_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
         return True
 
     def _wfc_set_wifi_absent_cell_strong(self):
         self.log.info("--->Setting WiFi absent cell strong<---")
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
-                 self.wifi_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
-                 self.cell_rssi_with_no_atten, MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 MAX_RSSI_RESERVED_VALUE)
         return True
 
     def _wfc_set_wifi_absent_cell_weak(self):
         self.log.info("--->Setting WiFi absent cell weak<---")
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
-                 self.wifi_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
-                 self.cell_rssi_with_no_atten, CELL_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 CELL_WEAK_RSSI_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 CELL_WEAK_RSSI_VALUE)
         return True
 
     def _wfc_set_wifi_absent_cell_absent(self):
         self.log.info("--->Setting WiFi absent cell absent<---")
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
-                 self.wifi_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
-                 self.cell_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G], 0,
+                 MIN_RSSI_RESERVED_VALUE)
         return True
 
     """ Tests Begin """
@@ -2560,7 +2466,10 @@
             return False
 
         # set up wifi to WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_NOT_ROVE_IN in 10 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten,
+                 WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_NOT_ROVE_IN, 5, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten,
                  WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_NOT_ROVE_IN, 5, 1)
         if (not wait_for_wifi_data_connection(self.log,
@@ -2575,7 +2484,10 @@
             return False
 
         # set up wifi to WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN in 10 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten,
+                 WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN, 1, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten,
                  WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN, 1, 1)
         if not self._phone_idle_iwlan():
@@ -2601,10 +2513,15 @@
         Make a call.
         """
         # set up cell strong
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G],
+                 self.cell_rssi_with_no_atten, MAX_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G],
                  self.cell_rssi_with_no_atten, MAX_RSSI_RESERVED_VALUE)
         # set up wifi WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_INITIAL_STATE
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten,
+                 WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_INITIAL_STATE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten,
                  WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_INITIAL_STATE)
         # ensure cellular rat, wfc mode, wifi associated
@@ -2639,7 +2556,10 @@
             return False
 
         # set up wifi to WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_NOT_ROVE_OUT in 10 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten,
+                 WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_NOT_ROVE_OUT, 1, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten,
                  WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_NOT_ROVE_OUT, 1, 1)
         if (not wait_for_wifi_data_connection(self.log,
@@ -2653,7 +2573,10 @@
             return False
 
         # set up wifi to WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT in 10 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten,
+                 WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT, 2, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten,
                  WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT, 2, 1)
         if (not wait_for_wifi_data_connection(self.log,
@@ -2729,7 +2652,10 @@
                 current_iteration, total_iteration))
 
             # set up wifi to WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT in 10 seconds
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT, 2, 1)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT, 2, 1)
             if (not wait_for_wifi_data_connection(
@@ -2744,7 +2670,10 @@
                 break
             self.log.info("Rove-out succeed.")
             # set up wifi to WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN in 10 seconds
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN, 2, 1)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN, 2, 1)
             if (not wait_for_wifi_data_connection(
@@ -2802,7 +2731,10 @@
                 current_iteration, total_iteration))
 
             # set up wifi to WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN in 10 seconds
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN, 2, 1)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      WIFI_RSSI_FOR_ROVE_IN_TEST_PHONE_ROVE_IN, 2, 1)
             if (not wait_for_wifi_data_connection(
@@ -2818,7 +2750,10 @@
             self.log.info("Rove-in succeed.")
 
             # set up wifi to WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT in 10 seconds
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT, 2, 1)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      WIFI_RSSI_FOR_ROVE_OUT_TEST_PHONE_ROVE_OUT, 2, 1)
             if (not wait_for_wifi_data_connection(
@@ -3002,7 +2937,10 @@
         PhoneA call should remain active.
         """
         # Increase WiFI RSSI to WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_NOT_HAND_IN in 10s
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten,
+                 WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_NOT_HAND_IN, 5, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten,
                  WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_NOT_HAND_IN, 5, 1)
         # Make sure WiFI connected and data OK.
@@ -3016,7 +2954,10 @@
             self.log.error("Phone hand-in to wfc.")
             return False
         # Increase WiFI RSSI to WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_HAND_IN in 10s
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten,
+                 WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_HAND_IN, 2, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten,
                  WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_HAND_IN, 2, 1)
         # Make sure phone hand in to iwlan.
@@ -3093,7 +3034,9 @@
         PhoneA should either drop or hands over to 3g/2g.
         """
         # Decrease LTE RSSI to CELL_WEAK_RSSI_VALUE in 30 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G],
+                 self.cell_rssi_with_no_atten, CELL_WEAK_RSSI_VALUE, 1, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G],
                  self.cell_rssi_with_no_atten, CELL_WEAK_RSSI_VALUE, 1, 1)
         # Make sure phone not hand in to iwlan.
         if self._phone_wait_for_wfc():
@@ -3138,7 +3081,10 @@
         """
         # Decrease WiFi RSSI to WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_NOT_HAND_OUT
         # in 10 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten,
+                 WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_NOT_HAND_OUT, 2, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten,
                  WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_NOT_HAND_OUT, 2, 1)
         # Make sure WiFi still connected and have data.
@@ -3157,7 +3103,10 @@
 
         # Decrease WiFi RSSI to WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_HAND_OUT
         # in 10 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten,
+                 WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_HAND_OUT, 2, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten,
                  WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_HAND_OUT, 2, 1)
         # Make sure WiFi still connected and have data.
@@ -3249,7 +3198,10 @@
             # Decrease WiFi RSSI to WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_HAND_OUT
             # in 10 seconds
             self.log.info("Decrease WiFi RSSI to hand out.")
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_HAND_OUT, 2, 1)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_HAND_OUT, 2, 1)
             # Make sure WiFi still connected and have data.
@@ -3269,7 +3221,10 @@
                 break
             # Increase WiFI RSSI to WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_HAND_IN in 10s
             self.log.info("Increase WiFi RSSI to hand in.")
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_HAND_IN, 2, 1)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_HAND_IN, 2, 1)
             # Make sure WiFi still connected and have data.
@@ -3338,7 +3293,10 @@
             # Increase WiFi RSSI to WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_HAND_IN
             # in 10 seconds
             self.log.info("Increase WiFi RSSI to hand in.")
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_HAND_IN, 2, 1)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      WIFI_RSSI_FOR_HAND_IN_TEST_PHONE_HAND_IN, 2, 1)
             # Make sure WiFi still connected and have data.
@@ -3358,7 +3316,10 @@
 
             # Decrease WiFI RSSI to WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_HAND_OUT in 10s
             self.log.info("Decrease WiFi RSSI to hand out.")
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_HAND_OUT, 2, 1)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      WIFI_RSSI_FOR_HAND_OUT_TEST_PHONE_HAND_OUT, 2, 1)
             # Make sure WiFi still connected and have data.
@@ -3421,7 +3382,9 @@
         PhoneA should have data on WiFi.
         """
         # Increase Cellular RSSI to CELL_STRONG_RSSI_VALUE in 30 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_3G],
+                 self.cell_rssi_with_no_atten, CELL_STRONG_RSSI_VALUE, 1, 1)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_CELL_4G],
                  self.cell_rssi_with_no_atten, CELL_STRONG_RSSI_VALUE, 1, 1)
         # Make sure phone hand-out, not drop call
         if not self._phone_wait_for_not_wfc():
@@ -3464,7 +3427,9 @@
         PhoneA data should be on LTE.
         """
         # Decrease WiFi RSSI to <-100dBm in 30 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
         # Make sure PhoneA data is on LTE.
         if (not wait_for_cell_data_connection(self.log,
@@ -3539,7 +3504,9 @@
         Decrease WiFi RSSI to make sure WiFI not connected. Call should Drop.
         """
         # Decrease WiFi RSSI to <-100dBm in 30 seconds
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten, MIN_RSSI_RESERVED_VALUE)
         # Make sure PhoneA data is on cellular.
         if (not wait_for_cell_data_connection(self.log,
@@ -3602,7 +3569,9 @@
 
         ad = self.android_devices[0]
 
-        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                 self.wifi_rssi_with_no_atten, INITIAL_RSSI)
+        set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                  self.wifi_rssi_with_no_atten, INITIAL_RSSI)
         if not ensure_wifi_connected(self.log, ad, self.live_network_ssid,
                                      self.live_network_pwd):
@@ -3631,7 +3600,12 @@
 
             self.log.info("Set RSSI to HIGHER_RSSI_THRESHOLD+5,"
                           "rssi_monitoring_id_higher should be available.")
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     HIGHER_RSSI_THRESHOLD + RSSI_THRESHOLD_MARGIN,
+                     WIFI_RSSI_CHANGE_STEP_SIZE,
+                     WIFI_RSSI_CHANGE_DELAY_PER_STEP)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      HIGHER_RSSI_THRESHOLD + RSSI_THRESHOLD_MARGIN,
                      WIFI_RSSI_CHANGE_STEP_SIZE,
@@ -3650,7 +3624,12 @@
 
             self.log.info("Set RSSI to HIGHER_RSSI_THRESHOLD-5,"
                           "rssi_monitoring_id_higher should be lost.")
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     HIGHER_RSSI_THRESHOLD - RSSI_THRESHOLD_MARGIN,
+                     WIFI_RSSI_CHANGE_STEP_SIZE,
+                     WIFI_RSSI_CHANGE_DELAY_PER_STEP)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      HIGHER_RSSI_THRESHOLD - RSSI_THRESHOLD_MARGIN,
                      WIFI_RSSI_CHANGE_STEP_SIZE,
@@ -3669,7 +3648,12 @@
 
             self.log.info("Set RSSI to LOWER_RSSI_THRESHOLD-5,"
                           "rssi_monitoring_id_lower should be lost.")
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     LOWER_RSSI_THRESHOLD - RSSI_THRESHOLD_MARGIN,
+                     WIFI_RSSI_CHANGE_STEP_SIZE,
+                     WIFI_RSSI_CHANGE_DELAY_PER_STEP)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      LOWER_RSSI_THRESHOLD - RSSI_THRESHOLD_MARGIN,
                      WIFI_RSSI_CHANGE_STEP_SIZE,
@@ -3688,7 +3672,12 @@
 
             self.log.info("Set RSSI to LOWER_RSSI_THRESHOLD+5,"
                           "rssi_monitoring_id_lower should be available.")
-            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI],
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_2G],
+                     self.wifi_rssi_with_no_atten,
+                     LOWER_RSSI_THRESHOLD + RSSI_THRESHOLD_MARGIN,
+                     WIFI_RSSI_CHANGE_STEP_SIZE,
+                     WIFI_RSSI_CHANGE_DELAY_PER_STEP)
+            set_rssi(self.log, self.attens[ATTEN_NAME_FOR_WIFI_5G],
                      self.wifi_rssi_with_no_atten,
                      LOWER_RSSI_THRESHOLD + RSSI_THRESHOLD_MARGIN,
                      WIFI_RSSI_CHANGE_STEP_SIZE,
diff --git a/acts/tests/google/wifi/WifiAwareManagerTest.py b/acts/tests/google/wifi/WifiAwareManagerTest.py
index 0ead0ee..7ce7750 100644
--- a/acts/tests/google/wifi/WifiAwareManagerTest.py
+++ b/acts/tests/google/wifi/WifiAwareManagerTest.py
@@ -1027,7 +1027,7 @@
             event_pub_rx['data']['peerId'], publisher_passphrase)
         self.log.info("Publisher network specifier - '%s'", pub_ns)
         self.network_req['NetworkSpecifier'] = pub_ns
-        pub_req_key = self.publisher.droid.connectivityRequestNetwork(
+        pub_req_key = self.publisher.droid.connectivityRequestWifiAwareNetwork(
             self.network_req)
 
         # P sends message to S
@@ -1051,7 +1051,7 @@
             event_sub_rx['data']['peerId'], subscriber_passphrase)
         self.log.info("Subscriber network specifier - '%s'", sub_ns)
         self.network_req['NetworkSpecifier'] = sub_ns
-        sub_req_key = self.subscriber.droid.connectivityRequestNetwork(
+        sub_req_key = self.subscriber.droid.connectivityRequestWifiAwareNetwork(
             self.network_req)
 
         # Wait until both S and P get confirmation that network formed
diff --git a/acts/tests/sample/RelayDeviceSampleTest.py b/acts/tests/sample/RelayDeviceSampleTest.py
new file mode 100644
index 0000000..040ef62
--- /dev/null
+++ b/acts/tests/sample/RelayDeviceSampleTest.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+#
+#   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.
+from acts import base_test
+from acts import test_runner
+from acts.controllers.relay_lib.relay import SynchronizeRelays
+
+
+class RelayDeviceSampleTest(base_test.BaseTestClass):
+    """ Demonstrates example usage of a configurable access point."""
+
+    def setup_class(self):
+        # Take devices from relay_devices.
+        self.relay_device = self.relay_devices[0]
+
+        # You can use this workaround to get devices by name:
+
+        relay_rig = self.relay_devices[0].rig
+        self.other_relay_device = relay_rig.devices['UniqueDeviceName']
+        # Note: If the "devices" key from the config is missing
+        # a GenericRelayDevice that contains every switch in the config
+        # will be stored in relay_devices[0]. Its name will be
+        # "GenericRelayDevice".
+
+    def setup_test(self):
+        # setup() will set the relay device to the default state.
+        # Unless overridden, the default state is all switches set to off.
+        self.relay_device.setup()
+
+    def teardown_test(self):
+        # clean_up() will set the relay device back to a default state.
+        # Unless overridden, the default state is all switches set to off.
+        self.relay_device.clean_up()
+
+    # Typical use of a GenericRelayDevice looks like this:
+    def test_relay_device(self):
+
+        # This function call will sleep until .25 seconds are up.
+        # Blocking_nc_for will emulate a button press, which turns on the relay
+        # (or stays on if it already was on) for the given time, and then turns
+        # off.
+        self.relay_device.relays['BT_Power_Button'].set_nc_for(.25)
+
+        # do_something_after_turning_on_bt_power()
+
+        # Note that the relays are mechanical switches, and do take real time
+        # to go from one state to the next.
+
+        self.relay_device.relays['BT_Pair'].set_nc()
+
+        # do_something_while_holding_down_the_pair_button()
+
+        self.relay_device.relays['BT_Pair'].set_no()
+
+        # do_something_after_releasing_bt_pair()
+
+        # Note that although cleanup sets the relays to the 'NO' state after
+        # each test, they do not press things like the power button to turn
+        # off whatever hardware is attached. When using a GenericRelayDevice,
+        # you'll have to do this manually.
+        # Other RelayDevices may handle this for you in their clean_up() call.
+        self.relay_device.relays['BT_Power_Button'].set_nc_for(.25)
+
+    def test_toggling(self):
+        # This test just spams the toggle on each relay.
+        for _ in range(0, 2):
+            self.relay_device.relays['BT_Power_Button'].toggle()
+            self.relay_device.relays['BT_Pair'].toggle()
+            self.relay_device.relays['BT_Reset'].toggle()
+            self.relay_device.relays['BT_SomethingElse'].toggle()
+
+    def test_synchronize_relays(self):
+        """Toggles relays using SynchronizeRelays().
+
+        This makes each relay do it's action at the same time, without waiting
+        after each relay to swap. Instead, all relays swap at the same time, and
+        the wait is done after exiting the with statement.
+        """
+        for _ in range(0, 10):
+            with SynchronizeRelays():
+                self.relay_device.relays['BT_Power_Button'].toggle()
+                self.relay_device.relays['BT_Pair'].toggle()
+                self.relay_device.relays['BT_Reset'].toggle()
+                self.relay_device.relays['BT_SomethingElse'].toggle()
+
+        # For more fine control over the wait time of relays, you can set
+        # Relay.transition_wait_time. This is not recommended unless you are
+        # using solid state relays, or async calls.
+
+
+if __name__ == "__main__":
+    test_runner.main()