Merge "Fix for BtCarPairing Test" into pi-dev
diff --git a/acts/framework/acts/controllers/ap_lib/ap_get_interface.py b/acts/framework/acts/controllers/ap_lib/ap_get_interface.py
index 65c8938..b80add5 100644
--- a/acts/framework/acts/controllers/ap_lib/ap_get_interface.py
+++ b/acts/framework/acts/controllers/ap_lib/ap_get_interface.py
@@ -140,6 +140,10 @@
         if wan:
             return wan
 
+        output = self.ssh.run('ifconfig')
+        interfaces_all = output.stdout.split('\n')
+        logging.info("IFCONFIG output = %s" % interfaces_all)
+
         raise ApInterfacesError('No WAN interface available')
 
     def get_lan_interface(self):
diff --git a/acts/framework/acts/test_utils/power/PowerBTBaseTest.py b/acts/framework/acts/test_utils/power/PowerBTBaseTest.py
new file mode 100644
index 0000000..5dfda12
--- /dev/null
+++ b/acts/framework/acts/test_utils/power/PowerBTBaseTest.py
@@ -0,0 +1,135 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 time
+import acts.test_utils.power.PowerBaseTest as PBT
+from acts.test_utils.bt.bt_test_utils import enable_bluetooth
+from acts.test_utils.bt.bt_test_utils import disable_bluetooth
+
+BT_BASE_UUID = '00000000-0000-1000-8000-00805F9B34FB'
+BT_CLASSICAL_DATA = [1, 2, 3]
+BLE_LOCATION_SCAN_ENABLE = 'settings put global ble_scan_always_enabled 1'
+BLE_LOCATION_SCAN_DISABLE = 'settings put global ble_scan_always_enabled 0'
+START_PMC_CMD = 'am start -n com.android.pmc/com.android.pmc.PMCMainActivity'
+PMC_VERBOSE_CMD = 'setprop log.tag.PMC VERBOSE'
+PMC_BASE_SCAN = 'am broadcast -a com.android.pmc.BLESCAN --es ScanMode '
+
+
+class PowerBTBaseTest(PBT.PowerBaseTest):
+    """Base class for BT power related tests.
+
+    Inherited from the PowerBaseTest class
+    """
+
+    def setup_test(self):
+
+        super().setup_test()
+        # Reset BT to factory defaults
+        self.dut.droid.bluetoothFactoryReset()
+        time.sleep(2)
+        # Start PMC app.
+        self.log.info('Start PMC app...')
+        self.dut.adb.shell(START_PMC_CMD)
+        self.dut.adb.shell(PMC_VERBOSE_CMD)
+
+    def teardown_test(self):
+        """Tear down necessary objects after test case is finished.
+
+        Bring down the AP interface, delete the bridge interface, stop the
+        packet sender, and reset the ethernet interface for the packet sender
+        """
+        super().teardown_test()
+        self.dut.droid.bluetoothFactoryReset()
+        self.dut.adb.shell(BLE_LOCATION_SCAN_DISABLE)
+
+    def teardown_class(self):
+        """Clean up the test class after tests finish running
+
+        """
+        super().teardown_class()
+        self.dut.droid.bluetoothFactoryReset()
+
+    def phone_setup_for_BT(self, bt_on, ble_on, screen_status):
+        """Sets the phone and Bluetooth in the desired state
+
+        Args:
+            bt_on: Enable/Disable BT
+            ble_on: Enable/Disable BLE
+            screen_status: screen ON or OFF
+        """
+
+        # Check if we are enabling a background scan
+        # TODO: Turn OFF cellular wihtout having to turn ON airplane mode
+        if bt_on == 'OFF' and ble_on == 'ON':
+            self.dut.adb.shell(BLE_LOCATION_SCAN_ENABLE)
+            self.dut.droid.connectivityToggleAirplaneMode(False)
+            time.sleep(2)
+
+        # Turn ON/OFF BT
+        if bt_on == 'ON':
+            enable_bluetooth(self.dut.droid, self.dut.ed)
+            self.dut.log.info('BT is ON')
+        else:
+            disable_bluetooth(self.dut.droid)
+            self.dut.droid.bluetoothDisableBLE()
+            self.dut.log.info('BT is OFF')
+        time.sleep(2)
+
+        # Turn ON/OFF BLE
+        if ble_on == 'ON':
+            self.dut.droid.bluetoothEnableBLE()
+            self.dut.log.info('BLE is ON')
+        else:
+            self.dut.droid.bluetoothDisableBLE()
+            self.dut.log.info('BLE is OFF')
+        time.sleep(2)
+
+        # Set the desired screen status
+        if screen_status == 'OFF':
+            self.dut.droid.goToSleepNow()
+            self.dut.log.info('Screen is OFF')
+        time.sleep(2)
+
+    def start_pmc_ble_scan(self,
+                           scan_mode,
+                           offset_start,
+                           scan_time,
+                           idle_time=None,
+                           num_reps=1):
+        """Starts a generic BLE scan via the PMC app
+
+        Args:
+            dut: object of the android device under test
+            scan mode: desired BLE scan type
+            offset_start: Time delay in seconds before scan starts
+            scan_time: active scan time
+            idle_time: iddle time (i.e., no scans occuring)
+            num_reps: Number of repetions of the ative+idle scan sequence
+        """
+        scan_dur = scan_time
+        if not idle_time:
+            idle_time = 0.2 * scan_time
+            scan_dur = 0.8 * scan_time
+
+        first_part_msg = '%s%s --es StartTime %d --es ScanTime %d' % (
+            PMC_BASE_SCAN, scan_mode, offset_start, scan_dur)
+
+        msg = '%s --es NoScanTime %d --es Repetitions %d' % (first_part_msg,
+                                                             idle_time,
+                                                             num_reps)
+
+        self.dut.log.info('Sent BLE scan broadcast message: %s', msg)
+        self.dut.adb.shell(msg)
diff --git a/acts/framework/acts/test_utils/power/PowerBaseTest.py b/acts/framework/acts/test_utils/power/PowerBaseTest.py
new file mode 100644
index 0000000..0a45dd1
--- /dev/null
+++ b/acts/framework/acts/test_utils/power/PowerBaseTest.py
@@ -0,0 +1,496 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 acts
+import json
+import logging
+import math
+import os
+import time
+import acts.controllers.iperf_server as ipf
+from acts import asserts
+from acts import base_test
+from acts import utils
+from acts.controllers import monsoon
+from acts.test_utils.wifi import wifi_test_utils as wutils
+from acts.test_utils.wifi import wifi_power_test_utils as wputils
+
+SETTINGS_PAGE = 'am start -n com.android.settings/.Settings'
+SCROLL_BOTTOM = 'input swipe 0 2000 0 0'
+UNLOCK_SCREEN = 'input keyevent 82'
+SCREENON_USB_DISABLE = 'dumpsys battery unplug'
+RESET_BATTERY_STATS = 'dumpsys batterystats --reset'
+AOD_OFF = 'settings put secure doze_always_on 0'
+MUSIC_IQ_OFF = 'pm disable-user com.google.intelligence.sense'
+# Command to disable gestures
+LIFT = 'settings put secure doze_pulse_on_pick_up 0'
+DOUBLE_TAP = 'settings put secure doze_pulse_on_double_tap 0'
+JUMP_TO_CAMERA = 'settings put secure camera_double_tap_power_gesture_disabled 1'
+RAISE_TO_CAMERA = 'settings put secure camera_lift_trigger_enabled 0'
+FLIP_CAMERA = 'settings put secure camera_double_twist_to_flip_enabled 0'
+ASSIST_GESTURE = 'settings put secure assist_gesture_enabled 0'
+ASSIST_GESTURE_ALERT = 'settings put secure assist_gesture_silence_alerts_enabled 0'
+ASSIST_GESTURE_WAKE = 'settings put secure assist_gesture_wake_enabled 0'
+SYSTEM_NAVI = 'settings put secure system_navigation_keys_enabled 0'
+# End of command to disable gestures
+AUTO_TIME_OFF = 'settings put global auto_time 0'
+AUTO_TIMEZONE_OFF = 'settings put global auto_time_zone 0'
+FORCE_YOUTUBE_STOP = 'am force-stop com.google.android.youtube'
+FORCE_DIALER_STOP = 'am force-stop com.google.android.dialer'
+IPERF_TIMEOUT = 180
+THRESHOLD_TOLERANCE = 0.2
+GET_FROM_PHONE = 'get_from_dut'
+GET_FROM_AP = 'get_from_ap'
+PHONE_BATTERY_VOLTAGE = 4.2
+MONSOON_MAX_CURRENT = 8.0
+MONSOON_RETRY_INTERVAL = 300
+MEASUREMENT_RETRY_COUNT = 3
+RECOVER_MONSOON_RETRY_COUNT = 3
+MIN_PERCENT_SAMPLE = 95
+ENABLED_MODULATED_DTIM = 'gEnableModulatedDTIM='
+MAX_MODULATED_DTIM = 'gMaxLIModulatedDTIM='
+TEMP_FILE = '/sdcard/Download/tmp.log'
+IPERF_DURATION = 'iperf_duration'
+INITIAL_ATTEN = [0, 0, 90, 90]
+
+
+class ObjNew():
+    """Create a random obj with unknown attributes and value.
+
+    """
+
+    def __init__(self, **kwargs):
+        self.__dict__.update(kwargs)
+
+    def __contains__(self, item):
+        """Function to check if one attribute is contained in the object.
+
+        Args:
+            item: the item to check
+        Return:
+            True/False
+        """
+        return hasattr(self, item)
+
+
+class PowerBaseTest(base_test.BaseTestClass):
+    """Base class for all wireless power related tests.
+
+    """
+
+    def __init__(self, controllers):
+
+        base_test.BaseTestClass.__init__(self, controllers)
+
+    def setup_class(self):
+
+        self.log = logging.getLogger()
+        self.tests = self._get_all_test_names()
+
+        # Setup the must have controllers, phone and monsoon
+        self.dut = self.android_devices[0]
+        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
+        self.mon = self.monsoons[0]
+        self.mon.set_max_current(8.0)
+        self.mon.set_voltage(4.2)
+        self.mon.attach_device(self.dut)
+
+        # Unpack the test/device specific parameters
+        TEST_PARAMS = self.TAG + '_params'
+        req_params = [TEST_PARAMS, 'custom_files']
+        self.unpack_userparams(req_params)
+        # Unpack the custom files based on the test configs
+        for file in self.custom_files:
+            if 'pass_fail_threshold_' + self.dut.model in file:
+                self.threshold_file = file
+            elif 'attenuator_setting' in file:
+                self.attenuation_file = file
+            elif 'network_config' in file:
+                self.network_file = file
+
+        # Unpack test specific configs
+        self.unpack_testparams(getattr(self, TEST_PARAMS))
+        if hasattr(self, 'attenuators'):
+            self.num_atten = self.attenuators[0].instrument.num_atten
+            self.atten_level = self.unpack_custom_file(self.attenuation_file)
+        self.set_attenuation(INITIAL_ATTEN)
+        self.threshold = self.unpack_custom_file(self.threshold_file)
+        self.mon_info = self.create_monsoon_info()
+
+        # Onetime task for each test class
+        # Temporary fix for b/77873679
+        self.adb_disable_verity()
+        self.dut.adb.shell('mv /vendor/bin/chre /vendor/bin/chre_renamed')
+        self.dut.adb.shell('pkill chre')
+
+    def setup_test(self):
+        """Set up test specific parameters or configs.
+
+        """
+        # Set the device into rockbottom state
+        self.dut_rockbottom()
+        # Wait for extra time if needed for the first test
+        if hasattr(self, 'extra_wait'):
+            self.more_wait_first_test()
+
+    def teardown_test(self):
+        """Tear down necessary objects after test case is finished.
+
+        """
+        self.log.info('Tearing down the test case')
+        self.mon.usb('on')
+
+    def teardown_class(self):
+        """Clean up the test class after tests finish running
+
+        """
+        self.log.info('Tearing down the test class')
+        self.mon.usb('on')
+
+    def unpack_testparams(self, bulk_params):
+        """Unpack all the test specific parameters.
+
+        Args:
+            bulk_params: dict with all test specific params in the config file
+        """
+        for key in bulk_params.keys():
+            setattr(self, key, bulk_params[key])
+
+    def unpack_custom_file(self, file, test_specific=True):
+        """Unpack the pass_fail_thresholds from a common file.
+
+        Args:
+            file: the common file containing pass fail threshold.
+        """
+        with open(file, 'r') as f:
+            params = json.load(f)
+        if test_specific:
+            try:
+                return params[self.TAG]
+            except KeyError:
+                pass
+        else:
+            return params
+
+    def decode_test_configs(self, attrs, indices):
+        """Decode the test config/params from test name.
+
+        Remove redundant function calls when tests are similar.
+        Args:
+            attrs: a list of the attrs of the test config obj
+            indices: a list of the location indices of keyword in the test name.
+        """
+        # Decode test parameters for the current test
+        test_params = self.current_test_name.split('_')
+        values = [test_params[x] for x in indices]
+        config_dict = dict(zip(attrs, values))
+        self.test_configs = ObjNew(**config_dict)
+
+    def more_wait_first_test(self):
+        # For the first test, increase the offset for longer wait time
+        if self.current_test_name == self.tests[0]:
+            self.mon_info.offset = self.mon_offset + self.extra_wait
+        else:
+            self.mon_info.offset = self.mon_offset
+
+    def set_attenuation(self, atten_list):
+        """Function to set the attenuator to desired attenuations.
+
+        Args:
+            atten_list: list containing the attenuation for each attenuator.
+        """
+        if len(atten_list) != self.num_atten:
+            raise Exception('List given does not have the correct length')
+        for i in range(self.num_atten):
+            self.attenuators[i].set_atten(atten_list[i])
+
+    def dut_rockbottom(self):
+        """Set the phone into Rock-bottom state.
+
+        """
+        self.dut.log.info('Now set the device to Rockbottom State')
+        utils.require_sl4a((self.dut, ))
+        self.dut.droid.connectivityToggleAirplaneMode(False)
+        time.sleep(2)
+        self.dut.droid.connectivityToggleAirplaneMode(True)
+        time.sleep(2)
+        utils.set_ambient_display(self.dut, False)
+        utils.set_auto_rotate(self.dut, False)
+        utils.set_adaptive_brightness(self.dut, False)
+        utils.sync_device_time(self.dut)
+        utils.set_location_service(self.dut, False)
+        utils.set_mobile_data_always_on(self.dut, False)
+        utils.disable_doze_light(self.dut)
+        utils.disable_doze(self.dut)
+        wutils.reset_wifi(self.dut)
+        wutils.wifi_toggle_state(self.dut, False)
+        try:
+            self.dut.droid.nfcDisable()
+        except acts.controllers.sl4a_lib.rpc_client.Sl4aApiError:
+            self.dut.log.info('NFC is not available')
+        self.dut.droid.setScreenBrightness(0)
+        self.dut.adb.shell(AOD_OFF)
+        self.dut.droid.setScreenTimeout(2200)
+        self.dut.droid.wakeUpNow()
+        self.dut.adb.shell(LIFT)
+        self.dut.adb.shell(DOUBLE_TAP)
+        self.dut.adb.shell(JUMP_TO_CAMERA)
+        self.dut.adb.shell(RAISE_TO_CAMERA)
+        self.dut.adb.shell(FLIP_CAMERA)
+        self.dut.adb.shell(ASSIST_GESTURE)
+        self.dut.adb.shell(ASSIST_GESTURE_ALERT)
+        self.dut.adb.shell(ASSIST_GESTURE_WAKE)
+        self.dut.adb.shell(SCREENON_USB_DISABLE)
+        self.dut.adb.shell(UNLOCK_SCREEN)
+        self.dut.adb.shell(SETTINGS_PAGE)
+        self.dut.adb.shell(SCROLL_BOTTOM)
+        self.dut.adb.shell(MUSIC_IQ_OFF)
+        self.dut.adb.shell(AUTO_TIME_OFF)
+        self.dut.adb.shell(AUTO_TIMEZONE_OFF)
+        self.dut.adb.shell(FORCE_YOUTUBE_STOP)
+        self.dut.adb.shell(FORCE_DIALER_STOP)
+        self.dut.droid.wifiSetCountryCode('US')
+        self.dut.droid.wakeUpNow()
+        self.dut.log.info('Device has been set to Rockbottom state')
+        self.dut.log.info('Screen is ON')
+
+    def measure_power_and_validate(self):
+        """The actual test flow and result processing and validate.
+
+        """
+        self.collect_power_data()
+        self.pass_fail_check()
+
+    def collect_power_data(self):
+        """Measure power, plot and take log if needed.
+
+        """
+        tag = ''
+        # Collecting current measurement data and plot
+        begin_time = utils.get_current_epoch_time()
+        self.file_path, self.test_result = self.monsoon_data_collect_save()
+        wputils.monsoon_data_plot(self.mon_info, self.file_path, tag=tag)
+        # Take Bugreport
+        if self.bug_report:
+            self.dut.take_bug_report(self.test_name, begin_time)
+
+    def pass_fail_check(self):
+        """Check the test result and decide if it passed or failed.
+
+        The threshold is provided in the config file. In this class, result is
+        current in mA.
+        """
+        current_threshold = self.threshold[self.test_name]
+        if self.test_result:
+            asserts.assert_true(
+                abs(self.test_result - current_threshold) / current_threshold <
+                THRESHOLD_TOLERANCE,
+                ('Measured average current in [{}]: {}, which is '
+                 'more than {} percent off than acceptable threshold {:.2f}mA'
+                 ).format(self.test_name, self.test_result,
+                          self.pass_fail_tolerance * 100, current_threshold))
+            asserts.explicit_pass('Measurement finished for {}.'.format(
+                self.test_name))
+        else:
+            asserts.fail(
+                'Something happened, measurement is not complete, test failed')
+
+    def create_monsoon_info(self):
+        """Creates the config dictionary for monsoon
+
+        Returns:
+            mon_info: Dictionary with the monsoon packet config
+        """
+        if hasattr(self, IPERF_DURATION):
+            self.mon_duration = self.iperf_duration - 10
+        mon_info = ObjNew(
+            dut=self.mon,
+            freq=self.mon_freq,
+            duration=self.mon_duration,
+            offset=self.mon_offset,
+            data_path=self.mon_data_path)
+        return mon_info
+
+    def monsoon_recover(self):
+        """Test loop to wait for monsoon recover from unexpected error.
+
+        Wait for a certain time duration, then quit.0
+        Args:
+            mon: monsoon object
+        Returns:
+            True/False
+        """
+        try:
+            self.mon.reconnect_monsoon()
+            time.sleep(2)
+            self.mon.usb('on')
+            logging.info('Monsoon recovered from unexpected error')
+            time.sleep(2)
+            return True
+        except monsoon.MonsoonError:
+            logging.info(self.mon.mon.ser.in_waiting)
+            logging.warning('Unable to recover monsoon from unexpected error')
+            return False
+
+    def monsoon_data_collect_save(self):
+        """Current measurement and save the log file.
+
+        Collect current data using Monsoon box and return the path of the
+        log file. Take bug report if requested.
+
+        Returns:
+            data_path: the absolute path to the log file of monsoon current
+                       measurement
+            avg_current: the average current of the test
+        """
+
+        tag = '{}_{}_{}'.format(self.test_name, self.dut.model,
+                                self.dut.build_info['build_id'])
+        data_path = os.path.join(self.mon_info.data_path, '{}.txt'.format(tag))
+        total_expected_samples = self.mon_info.freq * (
+            self.mon_info.duration + self.mon_info.offset)
+        min_required_samples = total_expected_samples * MIN_PERCENT_SAMPLE / 100
+        # Retry counter for monsoon data aquisition
+        retry_measure = 1
+        # Indicator that need to re-collect data
+        need_collect_data = 1
+        result = None
+        while retry_measure <= MEASUREMENT_RETRY_COUNT:
+            try:
+                # If need to retake data
+                if need_collect_data == 1:
+                    #Resets the battery status right before the test started
+                    self.dut.adb.shell(RESET_BATTERY_STATS)
+                    self.log.info(
+                        'Starting power measurement with monsoon box, try #{}'.
+                        format(retry_measure))
+                    #Start the power measurement using monsoon
+                    self.mon_info.dut.monsoon_usb_auto()
+                    result = self.mon_info.dut.measure_power(
+                        self.mon_info.freq,
+                        self.mon_info.duration,
+                        tag=tag,
+                        offset=self.mon_info.offset)
+                    self.mon_info.dut.reconnect_dut()
+                # Reconnect to dut
+                else:
+                    self.mon_info.dut.reconnect_dut()
+                # Reconnect and return measurement results if no error happens
+                avg_current = result.average_current
+                monsoon.MonsoonData.save_to_text_file([result], data_path)
+                self.log.info('Power measurement done within {} try'.format(
+                    retry_measure))
+                return data_path, avg_current
+            # Catch monsoon errors during measurement
+            except monsoon.MonsoonError:
+                self.log.info(self.mon_info.dut.mon.ser.in_waiting)
+                # Break early if it's one count away from limit
+                if retry_measure == MEASUREMENT_RETRY_COUNT:
+                    self.log.error(
+                        'Test failed after maximum measurement retry')
+                    break
+
+                self.log.warning('Monsoon error happened, now try to recover')
+                # Retry loop to recover monsoon from error
+                retry_monsoon = 1
+                while retry_monsoon <= RECOVER_MONSOON_RETRY_COUNT:
+                    mon_status = self.monsoon_recover(self.mon_info.dut)
+                    if mon_status:
+                        break
+                    else:
+                        retry_monsoon += 1
+                        self.log.warning(
+                            'Wait for {} second then try again'.format(
+                                MONSOON_RETRY_INTERVAL))
+                        time.sleep(MONSOON_RETRY_INTERVAL)
+
+                # Break the loop to end test if failed to recover monsoon
+                if not mon_status:
+                    self.log.error(
+                        'Tried our best, still failed to recover monsoon')
+                    break
+                else:
+                    # If there is no data, or captured samples are less than min
+                    # required, re-take
+                    if not result:
+                        self.log.warning('No data taken, need to remeasure')
+                    elif len(result._data_points) <= min_required_samples:
+                        self.log.warning(
+                            'More than {} percent of samples are missing due to monsoon error. Need to remeasure'.
+                            format(100 - MIN_PERCENT_SAMPLE))
+                    else:
+                        need_collect_data = 0
+                        self.log.warning(
+                            'Data collected is valid, try reconnect to DUT to finish test'
+                        )
+                    retry_measure += 1
+
+        if retry_measure > MEASUREMENT_RETRY_COUNT:
+            self.log.error('Test failed after maximum measurement retry')
+
+    def setup_ap_connection(self, network, bandwidth=80, connect=True):
+        """Setup AP and connect DUT to it.
+
+        Args:
+            network: the network config for the AP to be setup
+            bandwidth: bandwidth of the WiFi network to be setup
+            connect: indicator of if connect dut to the network after setup
+        Returns:
+            self.brconfigs: dict for bridge interface configs
+        """
+        wutils.wifi_toggle_state(self.dut, True)
+        self.brconfigs = wputils.ap_setup(
+            self.access_point, network, bandwidth=bandwidth)
+        if connect:
+            wutils.wifi_connect(self.dut, network)
+        return self.brconfigs
+
+    def process_iperf_results(self):
+        """Get the iperf results and process.
+
+        Returns:
+             throughput: the average throughput during tests.
+        """
+        # Get IPERF results and add this to the plot title
+        RESULTS_DESTINATION = os.path.join(self.iperf_server.log_path,
+                                           'iperf_client_output_{}.log'.format(
+                                               self.current_test_name))
+        PULL_FILE = '{} {}'.format(TEMP_FILE, RESULTS_DESTINATION)
+        self.dut.adb.pull(PULL_FILE)
+        # Calculate the average throughput
+        if self.use_client_output:
+            iperf_file = RESULTS_DESTINATION
+        else:
+            iperf_file = self.iperf_server.log_files[-1]
+        try:
+            iperf_result = ipf.IPerfResult(iperf_file)
+            throughput = (math.fsum(iperf_result.instantaneous_rates[:-1]) /
+                          len(iperf_result.instantaneous_rates[:-1])) * 8
+            self.log.info('The average throughput is {}'.format(throughput))
+        except ValueError:
+            self.log.warning('Cannot get iperf result. Setting to 0')
+            throughput = 0
+        return throughput
+
+    # TODO(@qijiang)Merge with tel_test_utils.py
+    def adb_disable_verity(self):
+        """Disable verity on the device.
+
+        """
+        if self.dut.adb.getprop("ro.boot.veritymode") == "enforcing":
+            self.dut.adb.disable_verity()
+            self.dut.reboot()
+            self.dut.adb.root()
+            self.dut.adb.remount()
diff --git a/acts/framework/acts/test_utils/power/PowerCoexBaseTest.py b/acts/framework/acts/test_utils/power/PowerCoexBaseTest.py
new file mode 100644
index 0000000..1976b0f
--- /dev/null
+++ b/acts/framework/acts/test_utils/power/PowerCoexBaseTest.py
@@ -0,0 +1,78 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - The Android Open Source Project
+8
+#   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 acts.test_utils.power.PowerBTBaseTest as PBtBT
+import acts.test_utils.power.PowerWiFiBaseTest as PWBT
+from acts import utils
+from acts.test_utils.wifi import wifi_test_utils as wutils
+
+
+class PowerCoexBaseTest(PBtBT.PowerBTBaseTest, PWBT.PowerWiFiBaseTest):
+    """Base class for BT power related tests.
+
+    Inherited from the PowerBaseTest class
+    """
+
+    def coex_test_phone_setup(self, Screen_status, WiFi_status, WiFi_band,
+                              BT_status, BLE_status, Cellular_status,
+                              Celluar_band):
+        """Setup the phone in desired state for coex tests.
+
+        Args:
+            Screen_status: 'ON' or 'OFF'
+            WiFi_status: 'ON', 'Connected', 'Disconnected', or 'OFF'
+            WiFi_band: '2g', '5g' or None, the band of AP
+            BT_status: 'ON' or 'OFF'
+            BLE_status: 'ON' or 'OFF'
+            Cellular_status: 'ON' or 'OFF'
+            Celluar_band: 'Verizon', 'Tmobile', or 'ATT' for live network,
+                actual band for callbox setup; 'None' when celluar is OFF
+        """
+        # Setup WiFi
+        if WiFi_status is 'ON':
+            wutils.wifi_toggle_state(self.dut, True)
+        elif WiFi_status is 'Connected':
+            self.setup_ap_connection(self.main_network[WiFi_band])
+        elif WiFi_status is 'Disconnected':
+            self.setup_ap_connection(
+                self.main_network[WiFi_band], connect=False)
+
+        # Setup BT/BLE
+        self.phone_setup_for_BT(BT_status, BLE_status, Screen_status)
+
+        # Setup Cellular
+        if Cellular_status is 'ON':
+            self.dut.droid.connectivityToggleAirplaneMode(False)
+            utils.set_mobile_data_always_on(self.dut, True)
+
+    def coex_scan_setup(self, WiFi_scan, BLE_scan_mode, wifi_scan_command):
+        """Setup for scan activities on WiFi, BT/BLE, and cellular.
+
+        Args:
+            WiFi_scan: 'ON', 'OFF' or 'PNO'
+            BLE_scan_mode: 'balanced', 'opportunistic', 'low_power', or 'low_latency'
+        """
+        if WiFi_scan is 'ON':
+            self.dut.adb.shell(wifi_scan_command)
+        if WiFi_scan is 'PNO':
+            self.log.info(
+                'Set attenuation so device loses connection to trigger PNO scans'
+            )
+            # Set to maximum attenuation 95 dB to cut down connection
+            [self.attenuators[i].set_atten(95) for i in range(self.num_atten)]
+        if BLE_scan_mode is not None:
+            self.start_pmc_ble_scan(BLE_scan_mode, self.mon_info.offset,
+                                    self.mon_info.duration)
diff --git a/acts/framework/acts/test_utils/power/PowerWiFiBaseTest.py b/acts/framework/acts/test_utils/power/PowerWiFiBaseTest.py
new file mode 100644
index 0000000..167e73f
--- /dev/null
+++ b/acts/framework/acts/test_utils/power/PowerWiFiBaseTest.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 acts.test_utils.power.PowerBaseTest as PBT
+from acts.test_utils.wifi import wifi_power_test_utils as wputils
+
+IPERF_DURATION = 'iperf_duration'
+
+
+class PowerWiFiBaseTest(PBT.PowerBaseTest):
+    """Base class for WiFi power related tests.
+
+    Inherited from the PowerBaseTest class
+    """
+
+    def setup_class(self):
+
+        super().setup_class()
+        if hasattr(self, 'access_points'):
+            self.access_point = self.access_points[0]
+            self.access_point_main = self.access_points[0]
+            if len(self.access_points) > 1:
+                self.access_point_aux = self.access_points[1]
+            self.networks = self.unpack_custom_file(self.network_file, False)
+            self.main_network = self.networks['main_network']
+            self.aux_network = self.networks['aux_network']
+        if hasattr(self, 'packet_senders'):
+            self.pkt_sender = self.packet_senders[0]
+        if hasattr(self, 'iperf_servers'):
+            self.iperf_server = self.iperf_servers[0]
+        if hasattr(self, 'iperf_duration'):
+            self.mon_duration = self.iperf_duration - 10
+            self.create_monsoon_info()
+
+    def teardown_test(self):
+        """Tear down necessary objects after test case is finished.
+
+        Bring down the AP interface, delete the bridge interface, stop the
+        packet sender, and reset the ethernet interface for the packet sender
+        """
+        super().teardown_test()
+        if hasattr(self, 'pkt_sender'):
+            self.pkt_sender.stop_sending(ignore_status=True)
+        if hasattr(self, 'brconfigs'):
+            self.access_point.bridge.teardown(self.brconfigs)
+        if hasattr(self, 'brconfigs_main'):
+            self.access_point_main.bridge.teardown(self.brconfigs_main)
+        if hasattr(self, 'brconfigs_aux'):
+            self.access_point_aux.bridge.teardown(self.brconfigs_aux)
+        if hasattr(self, 'access_points'):
+            for ap in self.access_points:
+                ap.close()
+        if hasattr(self, 'pkt_sender'):
+            wputils.reset_host_interface(self.pkt_sender.interface)
+        if hasattr(self, 'iperf_server'):
+            self.iperf_server.stop()
+
+    def teardown_class(self):
+        """Clean up the test class after tests finish running
+
+        """
+        super().teardown_class()
+        if hasattr(self, 'access_points'):
+            for ap in self.access_points:
+                ap.close()
+
+    def collect_power_data(self):
+        """Measure power, plot and check pass/fail.
+
+        If IPERF is run, need to pull iperf results and attach it to the plot.
+        """
+        super().collect_power_data()
+        tag = ''
+        if hasattr(self, IPERF_DURATION):
+            throughput = self.process_iperf_results()
+            tag = '_RSSI_{0:d}dBm_Throughput_{1:.2f}Mbps'.format(
+                self.RSSI, throughput)
+            wputils.monsoon_data_plot(self.mon_info, self.file_path, tag=tag)
diff --git a/acts/framework/acts/test_utils/wifi/wifi_power_test_utils.py b/acts/framework/acts/test_utils/wifi/wifi_power_test_utils.py
index 8f4b449..e2a91aa 100644
--- a/acts/framework/acts/test_utils/wifi/wifi_power_test_utils.py
+++ b/acts/framework/acts/test_utils/wifi/wifi_power_test_utils.py
@@ -14,12 +14,8 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import acts
-import json
 import logging
-import os
 import time
-from acts import asserts
 from acts import utils
 from acts.controllers import monsoon
 from acts.libs.proc import job
@@ -32,261 +28,17 @@
 from bokeh.plotting import figure, output_file, save
 from acts.controllers.ap_lib import hostapd_security
 from acts.controllers.ap_lib import hostapd_ap_preset
-from acts.test_utils.bt.bt_test_utils import enable_bluetooth
-from acts.test_utils.bt.bt_test_utils import disable_bluetooth
 
 # http://www.secdev.org/projects/scapy/
 # On ubuntu, sudo pip3 install scapy-python3
 import scapy.all as scapy
 
-SETTINGS_PAGE = "am start -n com.android.settings/.Settings"
-SCROLL_BOTTOM = "input swipe 0 2000 0 0"
-UNLOCK_SCREEN = "input keyevent 82"
-SCREENON_USB_DISABLE = "dumpsys battery unplug"
-RESET_BATTERY_STATS = "dumpsys batterystats --reset"
-AOD_OFF = "settings put secure doze_always_on 0"
-MUSIC_IQ_OFF = "pm disable-user com.google.intelligence.sense"
-# Command to disable gestures
-LIFT = "settings put secure doze_pulse_on_pick_up 0"
-DOUBLE_TAP = "settings put secure doze_pulse_on_double_tap 0"
-JUMP_TO_CAMERA = "settings put secure camera_double_tap_power_gesture_disabled 1"
-RAISE_TO_CAMERA = "settings put secure camera_lift_trigger_enabled 0"
-FLIP_CAMERA = "settings put secure camera_double_twist_to_flip_enabled 0"
-ASSIST_GESTURE = "settings put secure assist_gesture_enabled 0"
-ASSIST_GESTURE_ALERT = "settings put secure assist_gesture_silence_alerts_enabled 0"
-ASSIST_GESTURE_WAKE = "settings put secure assist_gesture_wake_enabled 0"
-SYSTEM_NAVI = "settings put secure system_navigation_keys_enabled 0"
-# End of command to disable gestures
-AUTO_TIME_OFF = "settings put global auto_time 0"
-AUTO_TIMEZONE_OFF = "settings put global auto_time_zone 0"
-FORCE_YOUTUBE_STOP = "am force-stop com.google.android.youtube"
-FORCE_DIALER_STOP = "am force-stop com.google.android.dialer"
-IPERF_TIMEOUT = 180
-THRESHOLD_TOLERANCE = 0.2
 GET_FROM_PHONE = 'get_from_dut'
 GET_FROM_AP = 'get_from_ap'
-PHONE_BATTERY_VOLTAGE = 4.2
-MONSOON_MAX_CURRENT = 8.0
-MONSOON_RETRY_INTERVAL = 300
-MEASUREMENT_RETRY_COUNT = 3
-RECOVER_MONSOON_RETRY_COUNT = 3
-MIN_PERCENT_SAMPLE = 95
 ENABLED_MODULATED_DTIM = 'gEnableModulatedDTIM='
 MAX_MODULATED_DTIM = 'gMaxLIModulatedDTIM='
 
 
-def dut_rockbottom(ad):
-    """Set the phone into Rock-bottom state.
-
-    Args:
-        ad: the target android device, AndroidDevice object
-
-    """
-    ad.log.info("Now set the device to Rockbottom State")
-    utils.require_sl4a((ad, ))
-    ad.droid.connectivityToggleAirplaneMode(False)
-    time.sleep(5)
-    ad.droid.connectivityToggleAirplaneMode(True)
-    utils.set_ambient_display(ad, False)
-    utils.set_auto_rotate(ad, False)
-    utils.set_adaptive_brightness(ad, False)
-    utils.sync_device_time(ad)
-    utils.set_location_service(ad, False)
-    utils.set_mobile_data_always_on(ad, False)
-    utils.disable_doze_light(ad)
-    utils.disable_doze(ad)
-    wutils.reset_wifi(ad)
-    wutils.wifi_toggle_state(ad, False)
-    try:
-        ad.droid.nfcDisable()
-    except acts.controllers.sl4a_lib.rpc_client.Sl4aApiError:
-        ad.log.info('NFC is not available')
-    ad.droid.setScreenBrightness(0)
-    ad.adb.shell(AOD_OFF)
-    ad.droid.setScreenTimeout(2200)
-    ad.droid.wakeUpNow()
-    ad.adb.shell(LIFT)
-    ad.adb.shell(DOUBLE_TAP)
-    ad.adb.shell(JUMP_TO_CAMERA)
-    ad.adb.shell(RAISE_TO_CAMERA)
-    ad.adb.shell(FLIP_CAMERA)
-    ad.adb.shell(ASSIST_GESTURE)
-    ad.adb.shell(ASSIST_GESTURE_ALERT)
-    ad.adb.shell(ASSIST_GESTURE_WAKE)
-    ad.adb.shell(SCREENON_USB_DISABLE)
-    ad.adb.shell(UNLOCK_SCREEN)
-    ad.adb.shell(SETTINGS_PAGE)
-    ad.adb.shell(SCROLL_BOTTOM)
-    ad.adb.shell(MUSIC_IQ_OFF)
-    ad.adb.shell(AUTO_TIME_OFF)
-    ad.adb.shell(AUTO_TIMEZONE_OFF)
-    ad.adb.shell(FORCE_YOUTUBE_STOP)
-    ad.adb.shell(FORCE_DIALER_STOP)
-    ad.droid.wifiSetCountryCode('US')
-    ad.droid.wakeUpNow()
-    ad.log.info('Device has been set to Rockbottom state')
-    ad.log.info('Screen is ON')
-
-
-def unpack_custom_file(file, test_class=None):
-    """Unpack the pass_fail_thresholds from a common file.
-
-    Args:
-        file: the common file containing pass fail threshold.
-    """
-    with open(file, 'r') as f:
-        params = json.load(f)
-    if test_class:
-        return params[test_class]
-    else:
-        return params
-
-
-def pass_fail_check(test_class, test_result):
-    """Check the test result and decide if it passed or failed.
-    The threshold is provided in the config file
-
-    Args:
-        test_class: the specific test class where test is running
-        test_result: the average current as the test result
-    """
-    test_name = test_class.current_test_name
-    current_threshold = test_class.threshold[test_name]
-    if test_result:
-        asserts.assert_true(
-            abs(test_result - current_threshold) / current_threshold <
-            THRESHOLD_TOLERANCE,
-            ("Measured average current in [%s]: %s, which is "
-             "more than %d percent off than acceptable threshold %.2fmA") %
-            (test_name, test_result, test_class.pass_fail_tolerance * 100,
-             current_threshold))
-        asserts.explicit_pass("Measurement finished for %s." % test_name)
-    else:
-        asserts.fail(
-            "Something happened, measurement is not complete, test failed")
-
-
-def monsoon_recover(mon):
-    """Test loop to wait for monsoon recover from unexpected error.
-
-    Wait for a certain time duration, then quit.0
-    Args:
-        mon: monsoon object
-    """
-    try:
-        mon.reconnect_monsoon()
-        time.sleep(2)
-        mon.usb('on')
-        logging.info("Monsoon recovered from unexpected error")
-        time.sleep(2)
-        return True
-    except monsoon.MonsoonError:
-        logging.info(mon.mon.ser.in_waiting)
-        logging.warning("Unable to recover monsoon from unexpected error")
-        return False
-
-
-def monsoon_data_collect_save(ad, mon_info, test_name):
-    """Current measurement and save the log file.
-
-    Collect current data using Monsoon box and return the path of the
-    log file. Take bug report if requested.
-
-    Args:
-        ad: the android device under test
-        mon_info: dict with information of monsoon measurement, including
-                  monsoon device object, measurement frequency, duration and
-                  offset etc.
-        test_name: current test name, used to contruct the result file name
-        bug_report: indicator to take bug report or not, 0 or 1
-    Returns:
-        data_path: the absolute path to the log file of monsoon current
-                   measurement
-        avg_current: the average current of the test
-    """
-
-    log = logging.getLogger()
-    tag = (test_name + '_' + ad.model + '_' + ad.build_info['build_id'])
-    data_path = os.path.join(mon_info['data_path'], "%s.txt" % tag)
-    total_expected_samples = mon_info['freq'] * (
-        mon_info['duration'] + mon_info['offset'])
-    min_required_samples = total_expected_samples * MIN_PERCENT_SAMPLE / 100
-    # Retry counter for monsoon data aquisition
-    retry_measure = 1
-    # Indicator that need to re-collect data
-    need_collect_data = 1
-    result = None
-    while retry_measure <= MEASUREMENT_RETRY_COUNT:
-        try:
-            # If need to retake data
-            if need_collect_data == 1:
-                #Resets the battery status right before the test started
-                ad.adb.shell(RESET_BATTERY_STATS)
-                log.info(
-                    "Starting power measurement with monsoon box, try #{}".
-                    format(retry_measure))
-                #Start the power measurement using monsoon
-                mon_info['dut'].monsoon_usb_auto()
-                result = mon_info['dut'].measure_power(
-                    mon_info['freq'],
-                    mon_info['duration'],
-                    tag=tag,
-                    offset=mon_info['offset'])
-                mon_info['dut'].reconnect_dut()
-            # Reconnect to dut
-            else:
-                mon_info['dut'].reconnect_dut()
-            # Reconnect and return measurement results if no error happens
-            avg_current = result.average_current
-            monsoon.MonsoonData.save_to_text_file([result], data_path)
-            log.info(
-                "Power measurement done within {} try".format(retry_measure))
-            return data_path, avg_current
-        # Catch monsoon errors during measurement
-        except monsoon.MonsoonError:
-            log.info(mon_info['dut'].mon.ser.in_waiting)
-            # Break early if it's one count away from limit
-            if retry_measure == MEASUREMENT_RETRY_COUNT:
-                log.error('Test failed after maximum measurement retry')
-                break
-
-            log.warning('Monsoon error happened, now try to recover')
-            # Retry loop to recover monsoon from error
-            retry_monsoon = 1
-            while retry_monsoon <= RECOVER_MONSOON_RETRY_COUNT:
-                mon_status = monsoon_recover(mon_info['dut'])
-                if mon_status:
-                    break
-                else:
-                    retry_monsoon += 1
-                    log.warning('Wait for {} second then try again'.format(
-                        MONSOON_RETRY_INTERVAL))
-                    time.sleep(MONSOON_RETRY_INTERVAL)
-
-            # Break the loop to end test if failed to recover monsoon
-            if not mon_status:
-                log.error('Tried our best, still failed to recover monsoon')
-                break
-            else:
-                # If there is no data or captured samples are less than min
-                # required, re-take
-                if not result:
-                    log.warning('No data taken, need to remeasure')
-                elif len(result._data_points) <= min_required_samples:
-                    log.warning(
-                        'More than {} percent of samples are missing due to monsoon error. Need to remeasure'.
-                        format(100 - MIN_PERCENT_SAMPLE))
-                else:
-                    need_collect_data = 0
-                    log.warning(
-                        'Data collected is valid, try reconnect to DUT to finish test'
-                    )
-                retry_measure += 1
-
-    if retry_measure > MEASUREMENT_RETRY_COUNT:
-        log.error('Test failed after maximum measurement retry')
-
-
 def monsoon_data_plot(mon_info, file_path, tag=""):
     """Plot the monsoon current data using bokeh interactive plotting tool.
 
@@ -297,7 +49,7 @@
     https://drive.google.com/open?id=0Bwp8Cq841VnpT2dGUUxLYWZvVjA
 
     Args:
-        mon_info: dict with information of monsoon measurement, including
+        mon_info: obj with information of monsoon measurement, including
                   monsoon device object, measurement frequency, duration and
                   offset etc.
         file_path: the path to the monsoon log file with current data
@@ -319,7 +71,7 @@
     voltage = results[0].voltage
     [current_data.extend(x.data_points) for x in results]
     [timestamps.extend(x.timestamps) for x in results]
-    period = 1 / float(mon_info['freq'])
+    period = 1 / float(mon_info.freq)
     time_relative = [x * period for x in range(len(current_data))]
     #Calculate the average current for the test
     current_data = [x * 1000 for x in current_data]
@@ -331,11 +83,11 @@
         data=dict(x0=time_relative, y0=current_data, color=color))
     s2 = ColumnDataSource(
         data=dict(
-            z0=[mon_info['duration']],
+            z0=[mon_info.duration],
             y0=[round(avg_current, 2)],
             x0=[round(avg_current * voltage, 2)],
-            z1=[round(avg_current * voltage * mon_info['duration'], 2)],
-            z2=[round(avg_current * mon_info['duration'], 2)]))
+            z1=[round(avg_current * voltage * mon_info.duration, 2)],
+            z2=[round(avg_current * mon_info.duration, 2)]))
     #Setting up data table for the output
     columns = [
         TableColumn(field='z0', title='Total Duration (s)'),
@@ -348,7 +100,7 @@
         source=s2, columns=columns, width=1300, height=60, editable=True)
 
     plot_title = file_path[file_path.rfind('/') + 1:-4] + tag
-    output_file("%s/%s.html" % (mon_info['data_path'], plot_title))
+    output_file("%s/%s.html" % (mon_info.data_path, plot_title))
     TOOLS = ('box_zoom,box_select,pan,crosshair,redo,undo,reset,hover,save')
     # Create a new plot with the datatable above
     plot = figure(
@@ -748,87 +500,3 @@
         'gw_ipv4': ipv4_gw
     }
     return pkt_gen_config
-
-
-def create_monsoon_info(test_class):
-    """Creates the config dictionary for monsoon
-
-    Args:
-        test_class: object with all the parameters
-
-    Returns:
-        Dictionary with the monsoon packet config
-    """
-    mon_info = {
-        'dut': test_class.mon,
-        'freq': test_class.mon_freq,
-        'duration': test_class.mon_duration,
-        'offset': test_class.mon_offset,
-        'data_path': test_class.mon_data_path
-    }
-    return mon_info
-
-
-def setup_phone_wireless(test_class,
-                         bt_on,
-                         wifi_on,
-                         screen_status,
-                         network=None,
-                         regular_mode=False):
-    """Sets the phone in rock-bottom and in the desired wireless mode
-
-    Args:
-        test_class: the specific test class where test is running
-        bt_on: Enable/Disable BT
-        wifi_on: Enable/Disable WiFi
-        screen_status: screen ON or OFF
-        network: a dict of information for the WiFi network to connect
-        regular_mode: enable cellular data (i.e., disable airplane mode)
-    """
-    # Initialize the dut to rock-bottom state
-    dut_rockbottom(test_class.dut)
-    brconfigs = None
-    time.sleep(1)
-
-    if regular_mode:
-        test_class.dut.droid.connectivityToggleAirplaneMode(False)
-        utils.set_mobile_data_always_on(test_class.dut, True)
-        time.sleep(2)
-
-    # Turn ON/OFF BT
-    if bt_on == 'ON':
-        enable_bluetooth(test_class.dut.droid, test_class.dut.ed)
-        test_class.dut.log.info('BT is ON')
-    else:
-        disable_bluetooth(test_class.dut.droid)
-        test_class.dut.droid.bluetoothDisableBLE()
-        test_class.dut.log.info('BT is OFF')
-    time.sleep(2)
-
-    # Turn ON/OFF Wifi
-    if wifi_on == 'ON':
-        wutils.wifi_toggle_state(test_class.dut, True)
-        test_class.dut.log.info('WiFi is ON')
-        if network:
-            # Set attenuation and connect to AP
-            for attn in range(test_class.num_atten):
-                test_class.attenuators[attn].set_atten(
-                    test_class.atten_level['zero_atten'][attn])
-            test_class.log.info('Set attenuation level to all zero')
-            brconfigs = ap_setup(test_class.access_point, network)
-            wutils.wifi_connect(test_class.dut, network)
-    else:
-        wutils.wifi_toggle_state(test_class.dut, False)
-        test_class.dut.log.info('WiFi is OFF')
-    time.sleep(1)
-
-    # Set the desired screen status
-    if screen_status == 'OFF':
-        test_class.dut.droid.goToSleepNow()
-        test_class.dut.log.info('Screen is OFF')
-    time.sleep(1)
-
-    if brconfigs:
-        return brconfigs
-    else:
-        return None
diff --git a/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py b/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py
index 6e1ca7b..a05eca4 100644
--- a/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py
+++ b/acts/framework/acts/test_utils/wifi/wifi_retail_ap.py
@@ -14,8 +14,9 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 import splinter
+import time
+from acts.libs.proc import job
 from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
-from time import sleep
 
 BROWSER_WAIT_SHORT = 1
 BROWSER_WAIT_MED = 3
@@ -24,7 +25,7 @@
 
 
 def create(configs):
-    """ Factory method for retail AP class.
+    """Factory method for retail AP class.
 
     Args:
         configs: list of dicts containing ap settings. ap settings must contain
@@ -51,8 +52,55 @@
     return
 
 
+def start_chrome_browser(headless, max_allowed_sessions, timeout):
+    """Method to start chrome browser for retail AP configuration
+
+    This function starts a chrome browser session to interface with the APs
+    web interface. The function attempts to maintain only one chromedriver
+    session by waiting until no chromedriver sessions are running on a machine.
+
+    Args:
+        headless: boolean controlling headless operation
+        max_allowed_sessions: maximum number of concurrent chrome sessions
+        timeout: maximum waiting time to launch chrome session
+    Returns:
+        browser: chrome browser session
+    Raises:
+        TimeoutError: raised when a browser session could not be started
+        withing the specified timeout
+    """
+    chrome_options = splinter.driver.webdriver.chrome.Options()
+    chrome_options.add_argument("--no-proxy-server")
+    chrome_options.add_argument("--no-sandbox")
+    chrome_options.add_argument("--allow-running-insecure-content")
+    chrome_options.add_argument("--ignore-certificate-errors")
+    chrome_capabilities = DesiredCapabilities.CHROME.copy()
+    chrome_capabilities["acceptSslCerts"] = True
+    chrome_capabilities["acceptInsecureCerts"] = True
+    if headless:
+        chrome_options.add_argument("--headless")
+        chrome_options.add_argument("--disable-gpu")
+
+    start_time = time.time()
+    end_time = start_time + timeout
+    while time.time() < end_time:
+        browsers_running = int(job.run('pgrep chromedriver | wc -l').stdout)
+        if browsers_running >= max_allowed_sessions:
+            time.sleep(BROWSER_WAIT_SHORT)
+        else:
+            try:
+                browser = splinter.Browser(
+                    "chrome",
+                    options=chrome_options,
+                    desired_capabilities=chrome_capabilities)
+                return browser
+            except:
+                time.sleep(BROWSER_WAIT_SHORT)
+    raise TimeoutError("Could not start chrome browser in time.")
+
+
 def visit_config_page(browser, url, page_load_timeout, num_tries):
-    """ Method to visit Netgear AP webpages.
+    """Method to visit Netgear AP webpages.
 
     This function visits a web page and checks the the resulting URL matches
     the intended URL, i.e. no redirects have happened
@@ -67,7 +115,7 @@
         try:
             browser.visit(url)
         except:
-            browser.visit("https://www.google.com/")
+            browser.visit("about:blank")
         if browser.url.split("/")[-1] == url.split("/")[-1]:
             break
         if idx == num_tries - 1:
@@ -75,7 +123,7 @@
 
 
 class WifiRetailAP(object):
-    """ Base class implementation for retail ap.
+    """Base class implementation for retail ap.
 
     Base class provides functions whose implementation is shared by all aps.
     If some functions such as set_power not supported by ap, checks will raise
@@ -86,7 +134,7 @@
         raise NotImplementedError
 
     def read_ap_settings(self):
-        """ Function that reads current ap settings.
+        """Function that reads current ap settings.
 
         Function implementation is AP dependent and thus base class raises exception
         if function not implemented in child class.
@@ -94,7 +142,7 @@
         raise NotImplementedError
 
     def validate_ap_settings(self):
-        """ Function to validate ap settings.
+        """Function to validate ap settings.
 
         This function compares the actual ap settings read from the web GUI
         with the assumed settings saved in the AP object. When called after AP
@@ -111,7 +159,7 @@
                 "Discrepancy in AP settings. Potential configuration error.")
 
     def configure_ap(self):
-        """ Function that configures ap based on values of ap_settings.
+        """Function that configures ap based on values of ap_settings.
 
         Function implementation is AP dependent and thus base class raises exception
         if function not implemented in child class.
@@ -119,7 +167,7 @@
         raise NotImplementedError
 
     def set_radio_on_off(self, network, status):
-        """ Function that turns the radio on or off.
+        """Function that turns the radio on or off.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -129,7 +177,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_ssid(self, network, ssid):
-        """ Function that sets network SSID.
+        """Function that sets network SSID.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -139,7 +187,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_channel(self, network, channel):
-        """ Function that sets network channel.
+        """Function that sets network channel.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -149,7 +197,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_bandwidth(self, network, bandwidth):
-        """ Function that sets network bandwidth/mode.
+        """Function that sets network bandwidth/mode.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -159,7 +207,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_power(self, network, power):
-        """ Function that sets network transmit power.
+        """Function that sets network transmit power.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -169,7 +217,7 @@
         self.update_ap_settings(setting_to_update)
 
     def set_security(self, network, security_type, *password):
-        """ Function that sets network security setting and password.
+        """Function that sets network security setting and password.
 
         Args:
             network: string containing network identifier (2G, 5G_1, 5G_2)
@@ -188,7 +236,7 @@
         self.update_ap_settings(setting_to_update)
 
     def update_ap_settings(self, *dict_settings, **named_settings):
-        """ Function to update settings of existing AP.
+        """Function to update settings of existing AP.
 
         Function copies arguments into ap_settings and calls configure_retail_ap
         to apply them.
@@ -225,54 +273,53 @@
             self.configure_ap()
 
     def band_lookup_by_channel(self, channel):
-        """ Function that gives band name by channel number.
+        """Function that gives band name by channel number.
 
         Args:
             channel: channel number to lookup
         Returns:
             band: name of band which this channel belongs to on this ap
         """
-        for key, value in self.CHANNEL_BAND_MAP.items():
+        for key, value in self.channel_band_map.items():
             if channel in value:
                 return key
         raise ValueError("Invalid channel passed in argument.")
 
 
 class NetgearR7000AP(WifiRetailAP):
-    """ Class that implements Netgear R7500 AP."""
+    """Class that implements Netgear R7500 AP."""
 
     def __init__(self, ap_settings):
         self.ap_settings = ap_settings.copy()
-        self.CONFIG_PAGE = "{}://{}:{}@{}:{}/WLG_wireless_dual_band_r10.htm".format(
+        self.init_gui_data()
+        # Read and update AP settings
+        self.read_ap_settings()
+        if ap_settings.items() <= self.ap_settings.items():
+            return
+        else:
+            self.update_ap_settings(ap_settings)
+
+    def init_gui_data(self):
+        """Function to initialize data used while interacting with web GUI"""
+        self.config_page = "{}://{}:{}@{}:{}/WLG_wireless_dual_band_r10.htm".format(
             self.ap_settings["protocol"], self.ap_settings["admin_username"],
             self.ap_settings["admin_password"], self.ap_settings["ip_address"],
             self.ap_settings["port"])
-        self.CONFIG_PAGE_NOLOGIN = "{}://{}:{}/WLG_wireless_dual_band_r10.htm".format(
+        self.config_page_nologin = "{}://{}:{}/WLG_wireless_dual_band_r10.htm".format(
             self.ap_settings["protocol"], self.ap_settings["ip_address"],
             self.ap_settings["port"])
-        self.CONFIG_PAGE_ADVANCED = "{}://{}:{}/WLG_adv_dual_band2.htm".format(
+        self.config_page_advanced = "{}://{}:{}/WLG_adv_dual_band2.htm".format(
             self.ap_settings["protocol"], self.ap_settings["ip_address"],
             self.ap_settings["port"])
-        self.CHROME_OPTIONS = splinter.driver.webdriver.chrome.Options()
-        self.CHROME_OPTIONS.add_argument("--no-proxy-server")
-        self.CHROME_OPTIONS.add_argument("--no-sandbox")
-        self.CHROME_OPTIONS.add_argument("--allow-running-insecure-content")
-        self.CHROME_OPTIONS.add_argument("--ignore-certificate-errors")
-        self.CHROME_CAPABILITIES = DesiredCapabilities.CHROME.copy()
-        self.CHROME_CAPABILITIES["acceptSslCerts"] = True
-        self.CHROME_CAPABILITIES["acceptInsecureCerts"] = True
-        if self.ap_settings["headless_browser"]:
-            self.CHROME_OPTIONS.add_argument("--headless")
-            self.CHROME_OPTIONS.add_argument("--disable-gpu")
-        self.NETWORKS = ["2G", "5G_1"]
-        self.CHANNEL_BAND_MAP = {
+        self.networks = ["2G", "5G_1"]
+        self.channel_band_map = {
             "2G": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
             "5G_1": [
                 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
                 124, 128, 132, 136, 140, 149, 153, 157, 161, 165
             ]
         }
-        self.REGION_MAP = {
+        self.region_map = {
             "1": "Africa",
             "2": "Asia",
             "3": "Australia",
@@ -296,7 +343,7 @@
             "23": "Singapore",
             "24": "Taiwan"
         }
-        self.CONFIG_PAGE_FIELDS = {
+        self.config_page_fields = {
             "region": "WRegion",
             ("2G", "status"): "enable_ap",
             ("5G_1", "status"): "enable_ap_an",
@@ -313,61 +360,54 @@
             ("2G", "password"): "passphrase",
             ("5G_1", "password"): "passphrase_an"
         }
-        self.BW_MODE_VALUES = {
+        self.bw_mode_values = {
             "g and b": "11g",
             "145Mbps": "VHT20",
             "300Mbps": "VHT40",
             "HT80": "VHT80"
         }
-        self.POWER_MODE_VALUES = {
+        self.power_mode_values = {
             "1": "100%",
             "2": "75%",
             "3": "50%",
             "4": "25%"
         }
-        self.BW_MODE_TEXT = {
+        self.bw_mode_text = {
             "11g": "Up to 54 Mbps",
             "VHT20": "Up to 289 Mbps",
             "VHT40": "Up to 600 Mbps",
             "VHT80": "Up to 1300 Mbps"
         }
-        self.read_ap_settings()
-        if ap_settings.items() <= self.ap_settings.items():
-            return
-        else:
-            self.update_ap_settings(ap_settings)
 
     def read_ap_settings(self):
-        """ Function to read ap settings."""
-        with splinter.Browser(
-                "chrome",
-                options=self.CHROME_OPTIONS,
-                desired_capabilities=self.CHROME_CAPABILITIES) as browser:
+        """Function to read ap settings."""
+        with start_chrome_browser(self.ap_settings["headless_browser"], 1,
+                                  600) as browser:
             # Visit URL
-            visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
-            visit_config_page(browser, self.CONFIG_PAGE_NOLOGIN,
+            visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+            visit_config_page(browser, self.config_page_nologin,
                               BROWSER_WAIT_MED, 10)
 
-            for key, value in self.CONFIG_PAGE_FIELDS.items():
+            for key, value in self.config_page_fields.items():
                 if "status" in key:
-                    visit_config_page(browser, self.CONFIG_PAGE_ADVANCED,
+                    visit_config_page(browser, self.config_page_advanced,
                                       BROWSER_WAIT_MED, 10)
                     config_item = browser.find_by_name(value)
                     self.ap_settings["{}_{}".format(key[1], key[0])] = int(
                         config_item.first.checked)
-                    visit_config_page(browser, self.CONFIG_PAGE_NOLOGIN,
+                    visit_config_page(browser, self.config_page_nologin,
                                       BROWSER_WAIT_MED, 10)
                 else:
                     config_item = browser.find_by_name(value)
                     if "bandwidth" in key:
                         self.ap_settings["{}_{}".format(key[1], key[
-                            0])] = self.BW_MODE_VALUES[config_item.first.value]
+                            0])] = self.bw_mode_values[config_item.first.value]
                     elif "power" in key:
                         self.ap_settings["{}_{}".format(
-                            key[1], key[0])] = self.POWER_MODE_VALUES[
+                            key[1], key[0])] = self.power_mode_values[
                                 config_item.first.value]
                     elif "region" in key:
-                        self.ap_settings["region"] = self.REGION_MAP[
+                        self.ap_settings["region"] = self.region_map[
                             config_item.first.value]
                     elif "security_type" in key:
                         for item in config_item:
@@ -381,21 +421,19 @@
         return self.ap_settings.copy()
 
     def configure_ap(self):
-        """ Function to configure ap wireless settings."""
+        """Function to configure ap wireless settings."""
         # Turn radios on or off
         self.configure_radio_on_off()
         # Configure radios
-        with splinter.Browser(
-                "chrome",
-                options=self.CHROME_OPTIONS,
-                desired_capabilities=self.CHROME_CAPABILITIES) as browser:
+        with start_chrome_browser(self.ap_settings["headless_browser"], 1,
+                                  600) as browser:
             # Visit URL
-            visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
-            visit_config_page(browser, self.CONFIG_PAGE_NOLOGIN,
+            visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+            visit_config_page(browser, self.config_page_nologin,
                               BROWSER_WAIT_MED, 10)
 
             # Update region, and power/bandwidth for each network
-            for key, value in self.CONFIG_PAGE_FIELDS.items():
+            for key, value in self.config_page_fields.items():
                 if "power" in key:
                     config_item = browser.find_by_name(value).first
                     config_item.select_by_text(self.ap_settings["{}_{}".format(
@@ -406,18 +444,18 @@
                 elif "bandwidth" in key:
                     config_item = browser.find_by_name(value).first
                     config_item.select_by_text(
-                        self.BW_MODE_TEXT[self.ap_settings["{}_{}".format(
+                        self.bw_mode_text[self.ap_settings["{}_{}".format(
                             key[1], key[0])]])
 
             # Update security settings (passwords updated only if applicable)
-            for key, value in self.CONFIG_PAGE_FIELDS.items():
+            for key, value in self.config_page_fields.items():
                 if "security_type" in key:
                     browser.choose(value, self.ap_settings["{}_{}".format(
                         key[1], key[0])])
                     if self.ap_settings["{}_{}".format(key[1],
                                                        key[0])] == "WPA2-PSK":
                         config_item = browser.find_by_name(
-                            self.CONFIG_PAGE_FIELDS[(key[0],
+                            self.config_page_fields[(key[0],
                                                      "password")]).first
                         config_item.fill(self.ap_settings["{}_{}".format(
                             "password", key[0])])
@@ -427,7 +465,7 @@
             # wherein channel and SSID get overwritten when some other
             # variables are changed. However, region does have to be set before
             # channel in all cases.
-            for key, value in self.CONFIG_PAGE_FIELDS.items():
+            for key, value in self.config_page_fields.items():
                 if "ssid" in key:
                     config_item = browser.find_by_name(value).first
                     config_item.fill(self.ap_settings["{}_{}".format(
@@ -436,40 +474,38 @@
                     config_item = browser.find_by_name(value).first
                     config_item.select(self.ap_settings["{}_{}".format(
                         key[1], key[0])])
-                    sleep(BROWSER_WAIT_SHORT)
+                    time.sleep(BROWSER_WAIT_SHORT)
                     try:
                         alert = browser.get_alert()
                         alert.accept()
                     except:
                         pass
 
-            sleep(BROWSER_WAIT_SHORT)
+            time.sleep(BROWSER_WAIT_SHORT)
             browser.find_by_name("Apply").first.click()
-            sleep(BROWSER_WAIT_SHORT)
+            time.sleep(BROWSER_WAIT_SHORT)
             try:
                 alert = browser.get_alert()
                 alert.accept()
-                sleep(BROWSER_WAIT_SHORT)
+                time.sleep(BROWSER_WAIT_SHORT)
             except:
-                sleep(BROWSER_WAIT_SHORT)
-            visit_config_page(browser, self.CONFIG_PAGE,
+                time.sleep(BROWSER_WAIT_SHORT)
+            visit_config_page(browser, self.config_page,
                               BROWSER_WAIT_EXTRA_LONG, 10)
-            self.validate_ap_settings()
+        self.validate_ap_settings()
 
     def configure_radio_on_off(self):
-        """ Helper configuration function to turn radios on/off."""
-        with splinter.Browser(
-                "chrome",
-                options=self.CHROME_OPTIONS,
-                desired_capabilities=self.CHROME_CAPABILITIES) as browser:
+        """Helper configuration function to turn radios on/off."""
+        with start_chrome_browser(self.ap_settings["headless_browser"], 1,
+                                  600) as browser:
             # Visit URL
-            visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
-            visit_config_page(browser, self.CONFIG_PAGE_ADVANCED,
+            visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+            visit_config_page(browser, self.config_page_advanced,
                               BROWSER_WAIT_MED, 10)
 
             # Turn radios on or off
             status_toggled = False
-            for key, value in self.CONFIG_PAGE_FIELDS.items():
+            for key, value in self.config_page_fields.items():
                 if "status" in key:
                     config_item = browser.find_by_name(value).first
                     current_status = int(config_item.checked)
@@ -482,48 +518,47 @@
                             config_item.uncheck()
 
             if status_toggled:
-                sleep(BROWSER_WAIT_SHORT)
+                time.sleep(BROWSER_WAIT_SHORT)
                 browser.find_by_name("Apply").first.click()
-                sleep(BROWSER_WAIT_EXTRA_LONG)
-                visit_config_page(browser, self.CONFIG_PAGE,
+                time.sleep(BROWSER_WAIT_EXTRA_LONG)
+                visit_config_page(browser, self.config_page,
                                   BROWSER_WAIT_EXTRA_LONG, 10)
 
 
 class NetgearR7500AP(WifiRetailAP):
-    """ Class that implements Netgear R7500 AP."""
+    """Class that implements Netgear R7500 AP."""
 
     def __init__(self, ap_settings):
         self.ap_settings = ap_settings.copy()
-        self.CONFIG_PAGE = "{}://{}:{}@{}:{}/index.htm".format(
+        self.init_gui_data()
+        # Read and update AP settings
+        self.read_ap_settings()
+        if ap_settings.items() <= self.ap_settings.items():
+            return
+        else:
+            self.update_ap_settings(ap_settings)
+
+    def init_gui_data(self):
+        """Function to initialize data used while interacting with web GUI"""
+        self.config_page = "{}://{}:{}@{}:{}/index.htm".format(
             self.ap_settings["protocol"], self.ap_settings["admin_username"],
             self.ap_settings["admin_password"], self.ap_settings["ip_address"],
             self.ap_settings["port"])
-        self.CONFIG_PAGE_NOLOGIN = "{}://{}:{}/index.htm".format(
+        self.config_page_nologin = "{}://{}:{}/index.htm".format(
             self.ap_settings["protocol"], self.ap_settings["ip_address"],
             self.ap_settings["port"])
-        self.CONFIG_PAGE_ADVANCED = "{}://{}:{}/adv_index.htm".format(
+        self.config_page_advanced = "{}://{}:{}/adv_index.htm".format(
             self.ap_settings["protocol"], self.ap_settings["ip_address"],
             self.ap_settings["port"])
-        self.CHROME_OPTIONS = splinter.driver.webdriver.chrome.Options()
-        self.CHROME_OPTIONS.add_argument("--no-proxy-server")
-        self.CHROME_OPTIONS.add_argument("--no-sandbox")
-        self.CHROME_OPTIONS.add_argument("--allow-running-insecure-content")
-        self.CHROME_OPTIONS.add_argument("--ignore-certificate-errors")
-        self.CHROME_CAPABILITIES = DesiredCapabilities.CHROME.copy()
-        self.CHROME_CAPABILITIES["acceptSslCerts"] = True
-        self.CHROME_CAPABILITIES["acceptInsecureCerts"] = True
-        if self.ap_settings["headless_browser"]:
-            self.CHROME_OPTIONS.add_argument("--headless")
-            self.CHROME_OPTIONS.add_argument("--disable-gpu")
-        self.NETWORKS = ["2G", "5G_1"]
-        self.CHANNEL_BAND_MAP = {
+        self.networks = ["2G", "5G_1"]
+        self.channel_band_map = {
             "2G": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
             "5G_1": [
                 36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
                 124, 128, 132, 136, 140, 149, 153, 157, 161, 165
             ]
         }
-        self.CONFIG_PAGE_FIELDS = {
+        self.config_page_fields = {
             "region": "WRegion",
             ("2G", "status"): "enable_ap",
             ("5G_1", "status"): "enable_ap_an",
@@ -538,7 +573,7 @@
             ("2G", "password"): "passphrase",
             ("5G_1", "password"): "passphrase_an"
         }
-        self.REGION_MAP = {
+        self.region_map = {
             "0": "Africa",
             "1": "Asia",
             "2": "Australia",
@@ -562,17 +597,17 @@
             "20": "Singapore",
             "21": "Taiwan"
         }
-        self.BW_MODE_TEXT_2G = {
+        self.bw_mode_text_2g = {
             "11g": "Up to 54 Mbps",
             "VHT20": "Up to 289 Mbps",
             "VHT40": "Up to 600 Mbps"
         }
-        self.BW_MODE_TEXT_5G = {
+        self.bw_mode_text_5g = {
             "VHT20": "Up to 347 Mbps",
             "VHT40": "Up to 800 Mbps",
             "VHT80": "Up to 1733 Mbps"
         }
-        self.BW_MODE_VALUES = {
+        self.bw_mode_values = {
             "1": "11g",
             "2": "VHT20",
             "3": "VHT40",
@@ -580,39 +615,32 @@
             "8": "VHT40",
             "9": "VHT80"
         }
-        self.read_ap_settings()
-        if ap_settings.items() <= self.ap_settings.items():
-            return
-        else:
-            self.update_ap_settings(ap_settings)
 
     def read_ap_settings(self):
-        """ Function to read ap wireless settings."""
+        """Function to read ap wireless settings."""
         # Get radio status (on/off)
         self.read_radio_on_off()
         # Get radio configuration. Note that if both radios are off, the below
         # code will result in an error
-        with splinter.Browser(
-                "chrome",
-                options=self.CHROME_OPTIONS,
-                desired_capabilities=self.CHROME_CAPABILITIES) as browser:
-            visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
-            visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
-            sleep(BROWSER_WAIT_SHORT)
+        with start_chrome_browser(self.ap_settings["headless_browser"], 1,
+                                  600) as browser:
+            visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+            visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+            time.sleep(BROWSER_WAIT_SHORT)
             wireless_button = browser.find_by_id("wireless").first
             wireless_button.click()
-            sleep(BROWSER_WAIT_MED)
+            time.sleep(BROWSER_WAIT_MED)
 
             with browser.get_iframe("formframe") as iframe:
-                for key, value in self.CONFIG_PAGE_FIELDS.items():
+                for key, value in self.config_page_fields.items():
                     if "bandwidth" in key:
                         config_item = iframe.find_by_name(value).first
                         self.ap_settings["{}_{}".format(
                             key[1],
-                            key[0])] = self.BW_MODE_VALUES[config_item.value]
+                            key[0])] = self.bw_mode_values[config_item.value]
                     elif "region" in key:
                         config_item = iframe.find_by_name(value).first
-                        self.ap_settings["region"] = self.REGION_MAP[
+                        self.ap_settings["region"] = self.region_map[
                             config_item.value]
                     elif "password" in key:
                         try:
@@ -635,29 +663,27 @@
         return self.ap_settings.copy()
 
     def configure_ap(self):
-        """ Function to configure ap wireless settings."""
+        """Function to configure ap wireless settings."""
         # Turn radios on or off
         self.configure_radio_on_off()
         # Configure radios
-        with splinter.Browser(
-                "chrome",
-                options=self.CHROME_OPTIONS,
-                desired_capabilities=self.CHROME_CAPABILITIES) as browser:
-            visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
-            visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
-            sleep(BROWSER_WAIT_SHORT)
+        with start_chrome_browser(self.ap_settings["headless_browser"], 1,
+                                  600) as browser:
+            visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+            visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+            time.sleep(BROWSER_WAIT_SHORT)
             wireless_button = browser.find_by_id("wireless").first
             wireless_button.click()
-            sleep(BROWSER_WAIT_MED)
+            time.sleep(BROWSER_WAIT_MED)
 
             with browser.get_iframe("formframe") as iframe:
                 # Update AP region. Must be done before channel setting
-                for key, value in self.CONFIG_PAGE_FIELDS.items():
+                for key, value in self.config_page_fields.items():
                     if "region" in key:
                         config_item = iframe.find_by_name(value).first
                         config_item.select_by_text(self.ap_settings["region"])
                 # Update wireless settings for each network
-                for key, value in self.CONFIG_PAGE_FIELDS.items():
+                for key, value in self.config_page_fields.items():
                     if "ssid" in key:
                         config_item = iframe.find_by_name(value).first
                         config_item.fill(self.ap_settings["{}_{}".format(
@@ -674,69 +700,67 @@
                     elif key == ("2G", "bandwidth"):
                         config_item = iframe.find_by_name(value).first
                         config_item.select_by_text(
-                            str(self.BW_MODE_TEXT_2G[self.ap_settings[
+                            str(self.bw_mode_text_2g[self.ap_settings[
                                 "{}_{}".format(key[1], key[0])]]))
                     elif key == ("5G_1", "bandwidth"):
                         config_item = iframe.find_by_name(value).first
                         config_item.select_by_text(
-                            str(self.BW_MODE_TEXT_5G[self.ap_settings[
+                            str(self.bw_mode_text_5g[self.ap_settings[
                                 "{}_{}".format(key[1], key[0])]]))
 
                 # Update passwords for WPA2-PSK protected networks
                 # (Must be done after security type is selected)
-                for key, value in self.CONFIG_PAGE_FIELDS.items():
+                for key, value in self.config_page_fields.items():
                     if "security_type" in key:
                         iframe.choose(value, self.ap_settings["{}_{}".format(
                             key[1], key[0])])
                         if self.ap_settings["{}_{}".format(
                                 key[1], key[0])] == "WPA2-PSK":
                             config_item = iframe.find_by_name(
-                                self.CONFIG_PAGE_FIELDS[(key[0],
+                                self.config_page_fields[(key[0],
                                                          "password")]).first
                             config_item.fill(self.ap_settings["{}_{}".format(
                                 "password", key[0])])
 
                 apply_button = iframe.find_by_name("Apply")
                 apply_button[0].click()
-                sleep(BROWSER_WAIT_SHORT)
+                time.sleep(BROWSER_WAIT_SHORT)
                 try:
                     alert = browser.get_alert()
                     alert.accept()
                 except:
                     pass
-                sleep(BROWSER_WAIT_SHORT)
+                time.sleep(BROWSER_WAIT_SHORT)
                 try:
                     alert = browser.get_alert()
                     alert.accept()
                 except:
                     pass
-                sleep(BROWSER_WAIT_SHORT)
-            sleep(BROWSER_WAIT_EXTRA_LONG)
-            visit_config_page(browser, self.CONFIG_PAGE,
+                time.sleep(BROWSER_WAIT_SHORT)
+            time.sleep(BROWSER_WAIT_EXTRA_LONG)
+            visit_config_page(browser, self.config_page,
                               BROWSER_WAIT_EXTRA_LONG, 10)
-            self.validate_ap_settings()
+        self.validate_ap_settings()
 
     def configure_radio_on_off(self):
-        """ Helper configuration function to turn radios on/off."""
-        with splinter.Browser(
-                "chrome",
-                options=self.CHROME_OPTIONS,
-                desired_capabilities=self.CHROME_CAPABILITIES) as browser:
-            visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
-            visit_config_page(browser, self.CONFIG_PAGE_ADVANCED,
+        """Helper configuration function to turn radios on/off."""
+        with start_chrome_browser(self.ap_settings["headless_browser"], 1,
+                                  600) as browser:
+            visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+            visit_config_page(browser, self.config_page_advanced,
                               BROWSER_WAIT_MED, 10)
-            sleep(BROWSER_WAIT_SHORT)
+            time.sleep(BROWSER_WAIT_SHORT)
             wireless_button = browser.find_by_id("advanced_bt").first
             wireless_button.click()
-            sleep(BROWSER_WAIT_SHORT)
+            time.sleep(BROWSER_WAIT_SHORT)
             wireless_button = browser.find_by_id("wladv").first
             wireless_button.click()
-            sleep(BROWSER_WAIT_MED)
+            time.sleep(BROWSER_WAIT_MED)
 
             with browser.get_iframe("formframe") as iframe:
                 # Turn radios on or off
                 status_toggled = False
-                for key, value in self.CONFIG_PAGE_FIELDS.items():
+                for key, value in self.config_page_fields.items():
                     if "status" in key:
                         config_item = iframe.find_by_name(value).first
                         current_status = int(config_item.checked)
@@ -750,31 +774,29 @@
                                 config_item.uncheck()
 
                 if status_toggled:
-                    sleep(BROWSER_WAIT_SHORT)
+                    time.sleep(BROWSER_WAIT_SHORT)
                     browser.find_by_name("Apply").first.click()
-                    sleep(BROWSER_WAIT_EXTRA_LONG)
-                    visit_config_page(browser, self.CONFIG_PAGE,
+                    time.sleep(BROWSER_WAIT_EXTRA_LONG)
+                    visit_config_page(browser, self.config_page,
                                       BROWSER_WAIT_EXTRA_LONG, 10)
 
     def read_radio_on_off(self):
-        """ Helper configuration function to read radio status."""
-        with splinter.Browser(
-                "chrome",
-                options=self.CHROME_OPTIONS,
-                desired_capabilities=self.CHROME_CAPABILITIES) as browser:
-            visit_config_page(browser, self.CONFIG_PAGE, BROWSER_WAIT_MED, 10)
-            visit_config_page(browser, self.CONFIG_PAGE_ADVANCED,
+        """Helper configuration function to read radio status."""
+        with start_chrome_browser(self.ap_settings["headless_browser"], 1,
+                                  600) as browser:
+            visit_config_page(browser, self.config_page, BROWSER_WAIT_MED, 10)
+            visit_config_page(browser, self.config_page_advanced,
                               BROWSER_WAIT_MED, 10)
             wireless_button = browser.find_by_id("advanced_bt").first
             wireless_button.click()
-            sleep(BROWSER_WAIT_SHORT)
+            time.sleep(BROWSER_WAIT_SHORT)
             wireless_button = browser.find_by_id("wladv").first
             wireless_button.click()
-            sleep(BROWSER_WAIT_MED)
+            time.sleep(BROWSER_WAIT_MED)
 
             with browser.get_iframe("formframe") as iframe:
                 # Turn radios on or off
-                for key, value in self.CONFIG_PAGE_FIELDS.items():
+                for key, value in self.config_page_fields.items():
                     if "status" in key:
                         config_item = iframe.find_by_name(value).first
                         self.ap_settings["{}_{}".format(key[1], key[0])] = int(
@@ -782,96 +804,18 @@
 
 
 class NetgearR7800AP(NetgearR7500AP):
-    """ Class that implements Netgear R7800 AP."""
+    """Class that implements Netgear R7800 AP.
+
+    Since most of the class' implementation is shared with the R7500, this
+    class inherits from NetgearR7500AP and simply redifines config parameters
+    """
 
     def __init__(self, ap_settings):
         self.ap_settings = ap_settings.copy()
-        self.CONFIG_PAGE = "{}://{}:{}@{}:{}/index.htm".format(
-            self.ap_settings["protocol"], self.ap_settings["admin_username"],
-            self.ap_settings["admin_password"], self.ap_settings["ip_address"],
-            self.ap_settings["port"])
-        self.CONFIG_PAGE_NOLOGIN = "{}://{}:{}/index.htm".format(
-            self.ap_settings["protocol"], self.ap_settings["ip_address"],
-            self.ap_settings["port"])
-        self.CONFIG_PAGE_ADVANCED = "{}://{}:{}/adv_index.htm".format(
-            self.ap_settings["protocol"], self.ap_settings["ip_address"],
-            self.ap_settings["port"])
-        self.CHROME_OPTIONS = splinter.driver.webdriver.chrome.Options()
-        self.CHROME_OPTIONS.add_argument("--no-proxy-server")
-        self.CHROME_OPTIONS.add_argument("--no-sandbox")
-        self.CHROME_OPTIONS.add_argument("--allow-running-insecure-content")
-        self.CHROME_OPTIONS.add_argument("--ignore-certificate-errors")
-        self.CHROME_CAPABILITIES = DesiredCapabilities.CHROME.copy()
-        self.CHROME_CAPABILITIES["acceptSslCerts"] = True
-        self.CHROME_CAPABILITIES["acceptInsecureCerts"] = True
-        if self.ap_settings["headless_browser"]:
-            self.CHROME_OPTIONS.add_argument("--headless")
-            self.CHROME_OPTIONS.add_argument("--disable-gpu")
-        self.NETWORKS = ["2G", "5G_1"]
-        self.CHANNEL_BAND_MAP = {
-            "2G": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
-            "5G_1": [
-                36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120,
-                124, 128, 132, 136, 140, 149, 153, 157, 161, 165
-            ]
-        }
-        self.CONFIG_PAGE_FIELDS = {
-            "region": "WRegion",
-            ("2G", "status"): "enable_ap",
-            ("5G_1", "status"): "enable_ap_an",
-            ("2G", "ssid"): "ssid",
-            ("5G_1", "ssid"): "ssid_an",
-            ("2G", "channel"): "w_channel",
-            ("5G_1", "channel"): "w_channel_an",
-            ("2G", "bandwidth"): "opmode",
-            ("5G_1", "bandwidth"): "opmode_an",
-            ("2G", "security_type"): "security_type",
-            ("5G_1", "security_type"): "security_type_an",
-            ("2G", "password"): "passphrase",
-            ("5G_1", "password"): "passphrase_an"
-        }
-        self.REGION_MAP = {
-            "0": "Africa",
-            "1": "Asia",
-            "2": "Australia",
-            "3": "Canada",
-            "4": "Europe",
-            "5": "Israel",
-            "6": "Japan",
-            "7": "Korea",
-            "8": "Mexico",
-            "9": "South America",
-            "10": "United States",
-            "11": "China",
-            "12": "India",
-            "13": "Malaysia",
-            "14": "Middle East(Algeria/Syria/Yemen)",
-            "15": "Middle East(Iran/Labanon/Qatar)",
-            "16": "Middle East(Turkey/Egypt/Tunisia/Kuwait)",
-            "17": "Middle East(Saudi Arabia)",
-            "18": "Middle East(United Arab Emirates)",
-            "19": "Russia",
-            "20": "Singapore",
-            "21": "Taiwan"
-        }
-        self.BW_MODE_TEXT_2G = {
-            "11g": "Up to 54 Mbps",
-            "VHT20": "Up to 347 Mbps",
-            "VHT40": "Up to 600 Mbps"
-        }
-        self.BW_MODE_TEXT_5G = {
-            "VHT20": "Up to 347 Mbps",
-            "VHT40": "Up to 800 Mbps",
-            "VHT80": "Up to 1733 Mbps"
-        }
-        self.BW_MODE_VALUES = {
-            "1": "11g",
-            "2": "VHT20",
-            "3": "VHT40",
-            "7": "VHT20",
-            "8": "VHT40",
-            "9": "VHT80"
-        }
+        self.init_gui_data()
+        # Overwrite minor differences from R7500 AP
+        self.bw_mode_text_2g["VHT20"] = "Up to 347 Mbps"
+        # Read and update AP settings
         self.read_ap_settings()
         if ap_settings.items() <= self.ap_settings.items():
             return
@@ -880,7 +824,7 @@
 
 
 class NetgearR8000AP(NetgearR7000AP):
-    """ Class that implements Netgear R8000 AP.
+    """Class that implements Netgear R8000 AP.
 
     Since most of the class' implementation is shared with the R7000, this
     class inherits from NetgearR7000AP and simply redifines config parameters
@@ -888,50 +832,25 @@
 
     def __init__(self, ap_settings):
         self.ap_settings = ap_settings.copy()
-        self.CONFIG_PAGE = "http://{}:{}@{}/WLG_wireless_dual_band_r8000.htm".format(
-            self.ap_settings["admin_username"],
-            self.ap_settings["admin_password"], self.ap_settings["ip_address"])
-        self.CONFIG_PAGE_NOLOGIN = "http://{}/WLG_wireless_dual_band_r8000.htm".format(
-            self.ap_settings["ip_address"])
-        self.CONFIG_PAGE_ADVANCED = "http://{}/WLG_adv_dual_band2_r8000.htm".format(
-            self.ap_settings["ip_address"])
-        self.CHROME_OPTIONS = splinter.driver.webdriver.chrome.Options()
-        self.CHROME_OPTIONS.add_argument("--no-proxy-server")
-        self.CHROME_OPTIONS.add_argument("--no-sandbox")
-        if self.ap_settings["headless_browser"]:
-            self.CHROME_OPTIONS.add_argument("--headless")
-            self.CHROME_OPTIONS.add_argument("--disable-gpu")
-        self.NETWORKS = ["2G", "5G_1", "5G_2"]
-        self.CHANNEL_BAND_MAP = {
+        self.init_gui_data()
+        # Overwrite minor differences from R7000 AP
+        self.config_page = "{}://{}:{}@{}:{}/WLG_wireless_dual_band_r8000.htm".format(
+            self.ap_settings["protocol"], self.ap_settings["admin_username"],
+            self.ap_settings["admin_password"], self.ap_settings["ip_address"],
+            self.ap_settings["port"])
+        self.config_page_nologin = "{}://{}:{}/WLG_wireless_dual_band_r8000.htm".format(
+            self.ap_settings["protocol"], self.ap_settings["ip_address"],
+            self.ap_settings["port"])
+        self.config_page_advanced = "{}://{}:{}/WLG_adv_dual_band2_r8000.htm".format(
+            self.ap_settings["protocol"], self.ap_settings["ip_address"],
+            self.ap_settings["port"])
+        self.networks = ["2G", "5G_1", "5G_2"]
+        self.channel_band_map = {
             "2G": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
             "5G_1": [36, 40, 44, 48],
             "5G_2": [149, 153, 157, 161, 165]
         }
-        self.REGION_MAP = {
-            "1": "Africa",
-            "2": "Asia",
-            "3": "Australia",
-            "4": "Canada",
-            "5": "Europe",
-            "6": "Israel",
-            "7": "Japan",
-            "8": "Korea",
-            "9": "Mexico",
-            "10": "South America",
-            "11": "United States",
-            "12": "Middle East(Algeria/Syria/Yemen)",
-            "14": "Russia",
-            "16": "China",
-            "17": "India",
-            "18": "Malaysia",
-            "19": "Middle East(Iran/Labanon/Qatar)",
-            "20": "Middle East(Turkey/Egypt/Tunisia/Kuwait)",
-            "21": "Middle East(Saudi Arabia)",
-            "22": "Middle East(United Arab Emirates)",
-            "23": "Singapore",
-            "24": "Taiwan"
-        }
-        self.CONFIG_PAGE_FIELDS = {
+        self.config_page_fields = {
             "region": "WRegion",
             ("2G", "status"): "enable_ap",
             ("5G_1", "status"): "enable_ap_an",
@@ -952,6 +871,7 @@
             ("5G_1", "password"): "passphrase_an",
             ("5G_2", "password"): "passphrase_an_2"
         }
+        # Read and update AP settings
         self.read_ap_settings()
         if ap_settings.items() <= self.ap_settings.items():
             return
diff --git a/acts/framework/acts/utils.py b/acts/framework/acts/utils.py
index 62c5d58..f8c8291 100755
--- a/acts/framework/acts/utils.py
+++ b/acts/framework/acts/utils.py
@@ -707,6 +707,12 @@
             If new_state is False, turn off location service.
             If new_state if True, set location service to "High accuracy".
     """
+    ad.adb.shell("adb shell content insert --uri "
+                 " content://com.google.settings/partner --bind "
+                 "name:s:network_location_opt_in --bind value:s:1")
+    ad.adb.shell("adb shell content insert --uri "
+                 " content://com.google.settings/partner --bind "
+                 "name:s:use_location_for_services --bind value:s:1")
     if new_state:
         ad.adb.shell("settings put secure location_providers_allowed +gps")
         ad.adb.shell("settings put secure location_providers_allowed +network")
diff --git a/acts/tests/google/power/bt/PowerBTbaselineTest.py b/acts/tests/google/power/bt/PowerBTbaselineTest.py
index 89eceaa..b7e5745 100644
--- a/acts/tests/google/power/bt/PowerBTbaselineTest.py
+++ b/acts/tests/google/power/bt/PowerBTbaselineTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2017 - The Android Open Source Project
+#   Copyright 2018 - 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.
@@ -14,152 +14,54 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import logging
-import os
-import time
-
 from acts import base_test
-from acts import utils
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-from acts.test_utils.bt import bt_power_test_utils as btutils
 from acts.test_decorators import test_tracker_info
+import acts.test_utils.power.PowerBTBaseTest as PBtBT
 
 
-class PowerBTbaselineTest(base_test.BaseTestClass):
+class PowerBTbaselineTest(PBtBT.PowerBTBaseTest):
     def __init__(self, controllers):
 
         base_test.BaseTestClass.__init__(self, controllers)
 
-    def setup_class(self):
+    def bt_baseline_test_func(self):
+        """Base function for BT baseline measurement.
 
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        req_params = ['btbaseline_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.btbaseline_params)
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(wputils.MONSOON_MAX_CURRENT)
-        self.mon.set_voltage(wputils.PHONE_BATTERY_VOLTAGE)
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-
-        # Reset BT to factory defaults
-        self.dut.droid.bluetoothFactoryReset()
-        time.sleep(2)
-
-    def teardown_class(self):
-        """Clean up the test class after all tests finish running
-
+        Steps:
+        1. Sets the phone in airplane mode, disables gestures and location
+        2. Turns ON/OFF BT, BLE and screen according to test conditions
+        3. Measures the power consumption
+        4. Asserts pass/fail criteria based on measured power
         """
-        self.mon.usb('on')
-        self.dut.droid.bluetoothFactoryReset()
 
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters.
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    def measure_power(self):
-        """Measures current consumption and evaluates pass/fail criteria
-
-        """
-        # Measure current and plot
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-
-        # Compute pass or fail check
-        wputils.pass_fail_check(self, avg_current)
+        # Decode the test params from test name
+        attrs = ['screen_status', 'bt_status', 'ble_status', 'scan_status']
+        indices = [2, 4, 6, 7]
+        self.decode_test_configs(attrs, indices)
+        # Setup the phoen at desired state
+        self.phone_setup_for_BT(self.test_configs.bt_status,
+                                self.test_configs.ble_status,
+                                self.test_configs.screen_status)
+        if self.test_configs.scan_status == 'connectable':
+            self.dut.droid.bluetoothMakeConnectable()
+        elif self.test_configs.scan_status == 'discoverable':
+            self.dut.droid.bluetoothMakeDiscoverable(
+                self.mon_info.duration + self.mon_info.offset)
+        self.measure_power_and_validate()
 
     # Test cases- Baseline
     @test_tracker_info(uuid='3f8ac0cb-f20d-4569-a58e-6009c89ea049')
-    def test_bt_ON_screen_OFF_connectable(self):
-        """Measures baseline power when BT is toggled ON and screen is OFF
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. Turns ON BT (i.e., page scan) and turns screen OFF
-        4. Measures the power consumption
-        5. Asserts pass/fail criteria based on measured power
-        """
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'ON', 'ON', 'OFF')
-
-        # This is the default mode: devices enters paging periodically
-        self.dut.droid.bluetoothMakeConnectable()
-
-        # Measure power
-        self.measure_power()
+    def test_screen_OFF_bt_ON_ble_ON_connectable(self):
+        self.bt_baseline_test_func()
 
     @test_tracker_info(uuid='d54a992e-37ed-460a-ada7-2c51941557fd')
-    def test_bt_ON_screen_OFF_discoverable(self):
-        """Measures baseline power when BT is discoverable and screen is OFF
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. Sets phone discoverable (i.e., inquiry scan) and turns screen OFF
-        4. Measures the power consumption
-        5. Asserts pass/fail criteria based on measured power
-        """
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'ON', 'ON', 'OFF')
-
-        # Device will enter Inquiry state
-        duration = self.mon_info['duration'] + self.mon_info['offset']
-        self.dut.droid.bluetoothMakeDiscoverable(duration)
-
-        # Measure power
-        self.measure_power()
+    def test_screen_OFF_bt_ON_ble_ON_discoverable(self):
+        self.bt_baseline_test_func()
 
     @test_tracker_info(uuid='8f4c36b5-b18e-4aa5-9fe5-aafb729c1034')
-    def test_bt_ON_screen_ON_connectable(self):
-        """Measures baseline power when BT is toggled ON and screen is ON
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. Turns ON BT (i.e., page scan) and turns screen ON
-        4. Measures the power consumption
-        5. Asserts pass/fail criteria based on measured power
-        """
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'ON', 'ON', 'ON')
-
-        # This is the default mode: devices enters paging periodically
-        self.dut.droid.bluetoothMakeConnectable()
-
-        # Measure power
-        self.measure_power()
+    def test_screen_ON_bt_ON_ble_ON_connectable(self):
+        self.bt_baseline_test_func()
 
     @test_tracker_info(uuid='7128356f-67d8-46b3-9d6b-1a4c9a7a1745')
-    def test_bt_ON_screen_ON_discoverable(self):
-        """Measures baseline power when BT is discoverable and screen is ON
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. Sets phone discoverable (i.e., inquiry scan) and turns screen ON
-        4. Measures the power consumption
-        5. Asserts pass/fail criteria based on measured power
-        """
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'ON', 'ON', 'ON')
-
-        # Device will enter Inquiry state
-        duration = self.mon_info['duration'] + self.mon_info['offset']
-        self.dut.droid.bluetoothMakeDiscoverable(duration)
-
-        # Measure power
-        self.measure_power()
+    def test_screen_ON_bt_ON_ble_ON_discoverable(self):
+        self.bt_baseline_test_func()
diff --git a/acts/tests/google/power/bt/PowerBTscanTest.py b/acts/tests/google/power/bt/PowerBTscanTest.py
index 59818e1..0ef622c 100644
--- a/acts/tests/google/power/bt/PowerBTscanTest.py
+++ b/acts/tests/google/power/bt/PowerBTscanTest.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3.4
 #
-#   Copyright 2017 - The Android Open Source Project
+#   Copyright 2018 - 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.
@@ -14,75 +14,13 @@
 #   See the License for the specific language governing permissions and
 #   limitations under the License.
 
-import logging
-import os
-import time
-
-from acts import base_test
-from acts import utils
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-from acts.test_utils.bt.bt_constants import ble_scan_settings_modes
-from acts.test_utils.bt import bt_power_test_utils as btutils
+import acts.test_utils.power.PowerBTBaseTest as PBtBT
 from acts.test_decorators import test_tracker_info
 
 
-class PowerBTscanTest(base_test.BaseTestClass):
-    def __init__(self, controllers):
-
-        base_test.BaseTestClass.__init__(self, controllers)
-
-    def setup_class(self):
-
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        req_params = ['btscan_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.btscan_params)
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(wputils.MONSOON_MAX_CURRENT)
-        self.mon.set_voltage(wputils.PHONE_BATTERY_VOLTAGE)
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-
-        # Start PMC app.
-        self.log.info('Start PMC app...')
-        self.dut.adb.shell(btutils.START_PMC_CMD)
-        self.dut.adb.shell(btutils.PMC_VERBOSE_CMD)
-
-        # Reset BT to factory defaults
-        self.dut.droid.bluetoothFactoryReset()
-        time.sleep(2)
-
-    def teardown_test(self):
-        """Tear down necessary objects/settings after test finishes
-
-        """
-        self.dut.adb.shell(btutils.BLE_LOCATION_SCAN_DISABLE)
-
-    def teardown_class(self):
-        """Clean up the test class after all tests finish running
-
-        """
-        self.mon.usb('on')
-        self.dut.droid.bluetoothFactoryReset()
-
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters.
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    def scan_ble_measure_power(self, scan_mode):
-        """Starts a generic BLE scan and measures the power
+class PowerBTscanTest(PBtBT.PowerBTBaseTest):
+    def ble_scan_base_func(self):
+        """Base function to start a generic BLE scan and measures the power
 
         Steps:
         1. Sets the phone in airplane mode, disables gestures and location
@@ -90,97 +28,58 @@
         3. Sends the adb shell command to PMC to start scan
         4. Measures the power consumption
         5. Asserts pass/fail criteria based on measured power
-
-        Args:
-            scan_mode: BLE scan type (e.g., low_power)
         """
-        # Start BLE scan
-        btutils.start_pmc_ble_scan(self.dut, scan_mode,
-                                   self.mon_info['offset'],
-                                   self.mon_info['duration'])
-
-        # Measure current and plot
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-
-        # Compute pass or fail check
-        wputils.pass_fail_check(self, avg_current)
+        # Decode the test params from test name
+        attrs = ['screen_status', 'bt_status', 'ble_status', 'scan_mode']
+        indices = [2, 4, 6, -1]
+        self.decode_test_configs(attrs, indices)
+        if self.test_configs.scan_mode == 'lowpower':
+            scan_mode = 'low_power'
+        elif self.test_configs.scan_mode == 'lowlatency':
+            scan_mode = 'low_latency'
+        else:
+            scan_mode = self.test_configs.scan_mode
+        self.phone_setup_for_BT(self.test_configs.bt_status,
+                                self.test_configs.ble_status,
+                                self.test_configs.screen_status)
+        self.start_pmc_ble_scan(scan_mode, self.mon_info.offset,
+                                self.mon_info.duration)
+        self.measure_power_and_validate()
 
     # Test Cases: BLE Scans + Filtered scans
     @test_tracker_info(uuid='e9a36161-1d0c-4b9a-8bd8-80fef8cdfe28')
-    def test_ble_screen_ON_default_scan(self):
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'ON', 'ON', 'ON')
-
-        # Start scan and measure power
-        self.scan_ble_measure_power(ble_scan_settings_modes['balanced'])
+    def test_screen_ON_bt_ON_ble_ON_default_scan_balanced(self):
+        self.ble_scan_base_func()
 
     @test_tracker_info(uuid='5fa61bf4-5f04-40bf-af52-6644b534d02e')
-    def test_ble_screen_OFF_filter_scan_opport(self):
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'ON', 'ON', 'OFF')
-
-        # Start BLE scan and measure power
-        self.scan_ble_measure_power(ble_scan_settings_modes['opportunistic'])
+    def test_screen_OFF_bt_ON_ble_ON_filter_scan_opportunistic(self):
+        self.ble_scan_base_func()
 
     @test_tracker_info(uuid='512b6cde-be83-43b0-b799-761380ba69ff')
-    def test_ble_screen_OFF_filter_scan_low_power(self):
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'ON', 'ON', 'OFF')
-
-        # Start BLE scan and measure power
-        self.scan_ble_measure_power(ble_scan_settings_modes['low_power'])
+    def test_screen_OFF_bt_ON_ble_ON_filter_scan_lowpower(self):
+        self.ble_scan_base_func()
 
     @test_tracker_info(uuid='3a526838-ae7b-4cdb-bc29-89a5503d2306')
-    def test_ble_screen_OFF_filter_scan_balanced(self):
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'ON', 'ON', 'OFF')
-
-        # Start BLE scan and measure power
-        self.scan_ble_measure_power(ble_scan_settings_modes['balanced'])
+    def test_screen_OFF_bt_ON_ble_ON_filter_scan_balanced(self):
+        self.ble_scan_base_func()
 
     @test_tracker_info(uuid='03a57cfd-4269-4a09-8544-84f878d2e801')
-    def test_ble_screen_OFF_filter_scan_low_lat(self):
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'ON', 'ON', 'OFF')
-
-        # Start BLE scan and measure power
-        self.scan_ble_measure_power(ble_scan_settings_modes['low_latency'])
+    def test_screen_OFF_bt_ON_ble_ON_filter_scan_lowlatency(self):
+        self.ble_scan_base_func()
 
     # Test Cases: Background scans
     @test_tracker_info(uuid='20145317-e362-4bfd-9860-4ceddf764784')
-    def test_ble_screen_ON_backgnd_scan_low_lat(self):
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'OFF', 'ON', 'ON')
-
-        # Start BLE scan and measure power
-        self.scan_ble_measure_power(ble_scan_settings_modes['low_latency'])
+    def test_screen_ON_bt_OFF_ble_ON_background_scan_lowlatency(self):
+        self.ble_scan_base_func()
 
     @test_tracker_info(uuid='00a53dc3-2c33-43c4-b356-dba93249b823')
-    def test_ble_screen_ON_backgnd_scan_low_power(self):
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'OFF', 'ON', 'ON')
-
-        # Start BLE scan and measure power
-        self.scan_ble_measure_power(ble_scan_settings_modes['low_power'])
+    def test_screen_ON_bt_OFF_ble_ON_background_scan_lowpower(self):
+        self.ble_scan_base_func()
 
     @test_tracker_info(uuid='b7185d64-631f-4b18-8d0b-4e14b80db375')
-    def test_ble_screen_OFF_filter_backgnd_scan_low_lat(self):
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'OFF', 'ON', 'OFF')
-
-        # Start BLE scan and measure power
-        self.scan_ble_measure_power(ble_scan_settings_modes['low_latency'])
+    def test_screen_OFF_bt_OFF_ble_ON_background_scan_lowlatency(self):
+        self.ble_scan_base_func()
 
     @test_tracker_info(uuid='93eb05da-a577-409c-8208-6af1899a10c2')
-    def test_ble_screen_OFF_filter_backgnd_scan_low_power(self):
-        # Set the phone in the desired state
-        btutils.phone_setup_for_BT(self.dut, 'OFF', 'ON', 'OFF')
-
-        # Start BLE scan and measure power
-        self.scan_ble_measure_power(ble_scan_settings_modes['low_power'])
+    def test_screen_OFF_bt_OFF_ble_ON_background_scan_lowpower(self):
+        self.ble_scan_base_func()
diff --git a/acts/tests/google/power/coex/PowerCoexBaseTest.py b/acts/tests/google/power/coex/PowerCoexBaseTest.py
deleted file mode 100644
index d4cae36..0000000
--- a/acts/tests/google/power/coex/PowerCoexBaseTest.py
+++ /dev/null
@@ -1,224 +0,0 @@
-#!/usr/bin/env python3.4
-#
-#   Copyright 2017 - 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 logging
-import os
-
-from acts import base_test
-from acts import utils
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-from acts.controllers.ap_lib import hostapd_constants as hc
-from acts.test_decorators import test_tracker_info
-
-
-class PowerCoexBaseTest(base_test.BaseTestClass):
-    def __init__(self, controllers):
-
-        base_test.BaseTestClass.__init__(self, controllers)
-
-    def setup_class(self):
-
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        self.access_point = self.access_points[0]
-        req_params = ['coexbaseline_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.coexbaseline_params)
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(wputils.MONSOON_MAX_CURRENT)
-        self.mon.set_voltage(wputils.PHONE_BATTERY_VOLTAGE)
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        self.num_atten = self.attenuators[0].instrument.num_atten
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-            elif 'attenuator_setting' in file:
-                self.attenuation_file = file
-            elif 'network_config' in file:
-                self.network_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-        self.atten_level = wputils.unpack_custom_file(self.attenuation_file,
-                                                      self.TAG)
-        self.networks = wputils.unpack_custom_file(self.network_file)
-        self.main_network = self.networks['main_network']
-
-    def teardown_class(self):
-        """Clean up the test class after all tests finish running
-
-        """
-        self.mon.usb('on')
-        self.access_point.close()  # Just as a precaution
-
-    def teardown_test(self):
-        """Tear down necessary objects/settings after test finishes
-
-        """
-        if self.brconfigs:
-            self.access_point.bridge.teardown(self.brconfigs)
-        self.access_point.close()
-
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters.
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    def measure_power(self):
-        """Measures current consumption and evaluates pass/fail criteria
-
-        """
-        # Measure current and plot
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-
-        # Compute pass or fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    @test_tracker_info(uuid='f3fc6667-73d8-4fb5-bdf3-0253e52043b1')
-    def test_wifi_discon_bt_on_screen_off(self):
-        """Measure power when WiFi is ON (disconnected) and BT is toggled ON
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. Turns ON BT and WiFi (disconnected)
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self, bt_on='ON', wifi_on='ON', screen_status='OFF')
-        self.measure_power()
-
-    @test_tracker_info(uuid='1bec36d1-f7b2-4a4b-9f5d-dfb5ed985649')
-    def test_wifi_2G_bt_on_screen_off(self):
-        """Measure power when WiFi is connected to 2G and BT is ON
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. Turns ON BT and WiFi is connected to 2.4 GHz
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_2G],
-            screen_status='OFF')
-        self.measure_power()
-
-    @test_tracker_info(uuid='88170cad-8336-4dff-8e53-3cc693d01b72')
-    def test_wifi_5G_bt_on_screen_off(self):
-        """Measure power when WiFi is connected to 5G and BT is ON
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. Turns ON BT and WiFi is connected to 5 GHz
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_5G],
-            screen_status='OFF')
-        self.measure_power()
-
-    @test_tracker_info(uuid='b82e59a9-9b27-4ba2-88f6-48d7917066f4')
-    def test_bt_on_cellular_verizon_on_screen_off(self):
-        """Measure power when BT and cellular (Verizon) are ON
-
-        Steps:
-        1. Disables gestures and location
-        2. Turns ON BT and cellular (Verizon)
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='OFF',
-            screen_status='OFF',
-            regular_mode=True)
-        self.measure_power()
-
-    @test_tracker_info(uuid='6409a02e-d63a-4c46-a210-1d5f1b006556')
-    def test_cellular_verizon_on_wifi_5G_screen_off(self):
-        """Measure power when WiFi is connected to 5G and cellular is ON
-
-        Steps:
-        1. Disables gestures and location
-        2. Connect Wifi to 5 GHz and have cellular idle (Verizon)
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='OFF',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_5G],
-            screen_status='OFF',
-            regular_mode=True)
-        self.measure_power()
-
-    @test_tracker_info(uuid='6f22792f-b304-4804-853d-e41484d442ab')
-    def test_cellular_verizon_on_wifi_2G_screen_off(self):
-        """Measure power when WiFi is connected to 2G and cellular is ON
-
-        Steps:
-        1. Disables gestures and location
-        2. Connect Wifi to 2.4 GHz and have cellular idle (Verizon)
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='OFF',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_2G],
-            screen_status='OFF',
-            regular_mode=True)
-        self.measure_power()
-
-    @test_tracker_info(uuid='11bb1683-4544-46b4-ad4a-875e31323729')
-    def test_cellular_verizon_on_bt_on_wifi_5G_screen_off(self):
-        """Measure power when WiFi is connected to 5G, BT and cellular are ON
-
-        Steps:
-        1. Disables gestures and location
-        2. Connect Wifi to 5 GHz and turn BT and cellular ON
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_5G],
-            screen_status='OFF',
-            regular_mode=True)
-        self.measure_power()
diff --git a/acts/tests/google/power/coex/PowerCoexScanTest.py b/acts/tests/google/power/coex/PowerCoexScanTest.py
deleted file mode 100644
index 210b5a9..0000000
--- a/acts/tests/google/power/coex/PowerCoexScanTest.py
+++ /dev/null
@@ -1,431 +0,0 @@
-#!/usr/bin/env python3.4
-#
-#   Copyright 2017 - 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 logging
-import math
-import os
-import time
-
-from acts import base_test
-from acts import utils
-from acts.controllers.ap_lib import hostapd_constants as hc
-from acts.test_decorators import test_tracker_info
-from acts.test_utils.bt import bt_power_test_utils as btutils
-from acts.test_utils.bt.bt_constants import ble_scan_settings_modes
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-
-
-class PowerCoexScanTest(base_test.BaseTestClass):
-    def __init__(self, controllers):
-
-        base_test.BaseTestClass.__init__(self, controllers)
-
-    def setup_class(self):
-
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        self.access_point = self.access_points[0]
-        req_params = ['coexscan_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.coexscan_params)
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(wputils.MONSOON_MAX_CURRENT)
-        self.mon.set_voltage(wputils.PHONE_BATTERY_VOLTAGE)
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        self.num_atten = self.attenuators[0].instrument.num_atten
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-            elif 'attenuator_setting' in file:
-                self.attenuation_file = file
-            elif 'network_config' in file:
-                self.network_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-        self.atten_level = wputils.unpack_custom_file(self.attenuation_file,
-                                                      self.TAG)
-        self.networks = wputils.unpack_custom_file(self.network_file)
-        self.main_network = self.networks['main_network']
-
-        # Start PMC app.
-        self.log.info('Start PMC app...')
-        self.dut.adb.shell(btutils.START_PMC_CMD)
-        self.dut.adb.shell(btutils.PMC_VERBOSE_CMD)
-
-    def setup_test(self):
-
-        iterations = math.floor((self.mon_duration + self.mon_offset + 10) /
-                                self.wifi_scan_interval)
-
-        self.PERIODIC_WIFI_SCAN = (
-            'am instrument -w -r -e scan-interval \"%d\" -e scan-iterations'
-            ' \"%d\" -e class com.google.android.platform.powertests.'
-            'WifiTests#testGScanAllChannels com.google.android.platform.'
-            'powertests/android.test.InstrumentationTestRunner > /dev/null &' %
-            (self.wifi_scan_interval, iterations))
-
-    def teardown_class(self):
-        """Clean up the test class after all tests finish running
-
-        """
-        self.mon.usb('on')
-        self.access_point.close()  # Just as a precaution
-
-    def teardown_test(self):
-        """Tear down necessary objects/settings after test finishes
-
-        """
-        self.dut.adb.shell(btutils.BLE_LOCATION_SCAN_DISABLE)
-        if self.brconfigs:
-            self.access_point.bridge.teardown(self.brconfigs)
-        self.access_point.close()
-
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    def measure_power(self):
-        """Measures current consumption and evaluates pass/fail criteria
-
-        """
-        # Measure current and plot
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-
-        # Compute pass or fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    @test_tracker_info(uuid='a998dd2b-f5f1-4361-b5da-83e42a69e80b')
-    def test_ble_scan_balan_wifi_2G_screen_on(self):
-        """Measure power when WiFi is connected to 2.4 GHz and BLE is scanning
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. BLE starts a balanced scan and WiFi is connected to 2.4 GHz
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_2G],
-            screen_status='ON')
-
-        # Start BLE scan
-        btutils.start_pmc_ble_scan(
-            self.dut, ble_scan_settings_modes['opportunistic'],
-            self.mon_info['offset'], self.mon_info['duration'])
-
-        # Measure power
-        self.measure_power()
-
-    @test_tracker_info(uuid='87146825-787a-4ea7-9622-30e9286c8a76')
-    def test_filter_ble_scan_low_power_wifi_2G_screen_off(self):
-        """Measure power when WiFi is connected to 2.4 GHz and BLE is scanning
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. BLE starts a filtered low power scan and WiFi is connected to 2G
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_2G],
-            screen_status='OFF')
-
-        # Start BLE scan
-        btutils.start_pmc_ble_scan(
-            self.dut, ble_scan_settings_modes['low_power'],
-            self.mon_info['offset'], self.mon_info['duration'])
-
-        # Measure power
-        self.measure_power()
-
-    @test_tracker_info(uuid='2e645deb-b744-4272-8578-5d4cb159d5aa')
-    def test_filter_ble_scan_low_power_wifi_5G_screen_off(self):
-        """Measure power when WiFi is connected to 5 GHz and BLE is scanning
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. BLE starts a filtered low power scan and WiFi is connected to 5G
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_5G],
-            screen_status='OFF')
-
-        # Start BLE scan
-        btutils.start_pmc_ble_scan(
-            self.dut, ble_scan_settings_modes['low_power'],
-            self.mon_info['offset'], self.mon_info['duration'])
-
-        # Measure power
-        self.measure_power()
-
-    @test_tracker_info(uuid='d458bc41-f1c8-4ed6-a7b5-0bec34780dda')
-    def test_wifi_scan_bt_on_screen_off(self):
-        """Measure power when WiFi is scanning and BT is doing a page scan
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. WiFi is scanning and BT is doing a page scan
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_2G],
-            screen_status='OFF')
-
-        # Start WiFi connectivity scans
-        self.dut.adb.shell_nb(self.PERIODIC_WIFI_SCAN)
-        self.log.info('Started connectivity scans:')
-        self.log.info(self.PERIODIC_WIFI_SCAN)
-
-        # Measure power
-        self.measure_power()
-
-    @test_tracker_info(uuid='6d9c0e8e-6a0f-458b-84d2-7d60fc254170')
-    def test_wifi_scan_ble_filter_low_power_scan_screen_off(self):
-        """Measure power when WiFi is scanning and BLE is scanning
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. WiFi is scanning and BLE is doing a low power filtered scan
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_2G],
-            screen_status='OFF')
-
-        # Start BLE scan
-        btutils.start_pmc_ble_scan(
-            self.dut, ble_scan_settings_modes['low_power'],
-            self.mon_info['offset'], self.mon_info['duration'])
-        time.sleep(2)
-
-        # Start WiFi connectivity scans
-        self.dut.adb.shell_nb(self.PERIODIC_WIFI_SCAN)
-        self.log.info('Started connectivity scans:')
-        self.log.info(self.PERIODIC_WIFI_SCAN)
-
-        # Measure power
-        self.measure_power()
-
-    @test_tracker_info(uuid='ba52317f-426a-4688-a0a5-1394bcc7b092')
-    def test_wifi_scan_ble_filter_low_lat_scan_screen_off(self):
-        """Measure power when WiFi is scanning and BLE is scanning
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. WiFi is scanning and BLE is doing a low latency filtered scan
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_2G],
-            screen_status='OFF')
-
-        # Start BLE scan
-        btutils.start_pmc_ble_scan(
-            self.dut, ble_scan_settings_modes['low_latency'],
-            self.mon_info['offset'], self.mon_info['duration'])
-        time.sleep(2)
-
-        # Start WiFi connectivity scans
-        self.dut.adb.shell_nb(self.PERIODIC_WIFI_SCAN)
-        self.log.info('Started connectivity scans:')
-        self.log.info(self.PERIODIC_WIFI_SCAN)
-
-        # Measure power
-        self.measure_power()
-
-    @test_tracker_info(uuid='b4c63eac-bc77-4e76-afff-ade98dde4411')
-    def test_wifi_pno_scan_ble_filter_low_lat_scan_screen_off(self):
-        """Measure power when WiFi disconnected (PNO scan) and BLE is scanning
-
-        Steps:
-        1. Sets the phone in airplane mode, disables gestures and location
-        2. WiFi is disconnected (PNOsscan) and BLE is doing a low latency
-           filtered scan
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='ON',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_2G],
-            screen_status='OFF')
-
-        # Start BLE scan
-        btutils.start_pmc_ble_scan(
-            self.dut, ble_scan_settings_modes['low_latency'],
-            self.mon_info['offset'], self.mon_info['duration'])
-        time.sleep(1)
-
-        # Set attenuator to make WiFi disconnect and start PNO scans
-        self.log.info('Set attenuation so device loses connection')
-        [
-            self.attenuators[i].set_atten(
-                self.atten_level[self.current_test_name][i])
-            for i in range(self.num_atten)
-        ]
-
-        # Measure power
-        self.measure_power()
-
-    @test_tracker_info(uuid='798796dc-960c-42b2-a835-2b2aefa028d5')
-    def test_cellular_verizon_on_wifi_scan_screen_off(self):
-        """Measure power when cellular is ON, WiFi is scanning and BT is OFF
-
-        Steps:
-        1. Disables gestures and location
-        2. WiFi is scanning and cellular is idle (Verizon)
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='OFF',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_5G],
-            screen_status='OFF',
-            regular_mode=True)
-
-        # Start WiFi connectivity scans
-        self.dut.adb.shell_nb(self.PERIODIC_WIFI_SCAN)
-        self.log.info('Started connectivity scans:')
-        self.log.info(self.PERIODIC_WIFI_SCAN)
-
-        # Measure power
-        self.measure_power()
-
-    @test_tracker_info(uuid='6ae44d84-0e68-4524-99b2-d3bfbd2253b8')
-    def test_cellular_on_wifi_scan_ble_backgnd_scan_low_power_screen_off(self):
-        """Measure power when cellular is ON, WiFi and BLE are scanning
-
-        Steps:
-        1. Disables gestures and location
-        2. WiFi is scanning and cellular is idle (Verizon) and BLE is doing
-           a low power background scan
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='OFF',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_5G],
-            screen_status='OFF',
-            regular_mode=True)
-
-        # Start BLE background scans
-        self.dut.adb.shell(btutils.BLE_LOCATION_SCAN_ENABLE)
-        time.sleep(1)
-        self.dut.droid.bluetoothEnableBLE()
-        time.sleep(2)
-        self.dut.log.info('BLE is ON')
-        btutils.start_pmc_ble_scan(
-            self.dut, ble_scan_settings_modes['low_power'],
-            self.mon_info['offset'], self.mon_info['duration'])
-        time.sleep(2)
-
-        # Start WiFi connectivity scans
-        self.dut.adb.shell_nb(self.PERIODIC_WIFI_SCAN)
-        self.log.info('Started connectivity scans:')
-        self.log.info(self.PERIODIC_WIFI_SCAN)
-
-        # Measure power
-        self.measure_power()
-
-    @test_tracker_info(uuid='2cb915a3-6319-4ac4-9e4d-9325b3b731c8')
-    def test_cellular_on_wifi_scan_ble_backgnd_scan_low_lat_screen_off(self):
-        """Measure power when cellular is ON, WiFi and BLE are scanning
-
-        Steps:
-        1. Disables gestures and location
-        2. WiFi is scanning and cellular is idle (Verizon) and BLE is doing
-           a low latency background scan
-        3. Measures the power consumption
-        4. Asserts pass/fail criteria based on measured power
-        """
-        # Set phone in the desired wireless mode
-        self.brconfigs = wputils.setup_phone_wireless(
-            test_class=self,
-            bt_on='OFF',
-            wifi_on='ON',
-            network=self.main_network[hc.BAND_2G],
-            screen_status='OFF',
-            regular_mode=True)
-
-        # Start BLE background scans
-        self.dut.adb.shell(btutils.BLE_LOCATION_SCAN_ENABLE)
-        time.sleep(1)
-        self.dut.droid.bluetoothEnableBLE()
-        time.sleep(2)
-        self.dut.log.info('BLE is ON')
-        btutils.start_pmc_ble_scan(
-            self.dut, ble_scan_settings_modes['low_latency'],
-            self.mon_info['offset'], self.mon_info['duration'])
-        time.sleep(2)
-
-        # Start WiFi connectivity scans
-        self.dut.adb.shell_nb(self.PERIODIC_WIFI_SCAN)
-        self.log.info('Started connectivity scans:')
-        self.log.info(self.PERIODIC_WIFI_SCAN)
-
-        # Measure power
-        self.measure_power()
diff --git a/acts/tests/google/power/coex/PowerCoexbaselineTest.py b/acts/tests/google/power/coex/PowerCoexbaselineTest.py
new file mode 100644
index 0000000..19d7763
--- /dev/null
+++ b/acts/tests/google/power/coex/PowerCoexbaselineTest.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 acts.test_utils.power.PowerCoexBaseTest as PCoBT
+from acts.test_decorators import test_tracker_info
+
+
+class PowerCoexbaselineTest(PCoBT.PowerCoexBaseTest):
+    def coex_baseline_test_func(self):
+        """Base function to do coex baseline tests.
+
+        Steps:
+        1. Set the phone into desired state (WiFi, BT/BLE, cellular)
+        2. Measures the power consumption
+        3. Asserts pass/fail criteria based on measured power
+        """
+        attrs = [
+            'screen_status', 'wifi_status', 'wifi_band', 'bt_status',
+            'ble_status', 'cellular_status', 'cellular_band'
+        ]
+        indices = [2, 4, 6, 8, 10, 12, 14]
+        self.decode_test_configs(attrs, indices)
+        self.coex_test_phone_setup(
+            self.test_configs.screen_status, self.test_configs.wifi_status,
+            self.test_configs.wifi_band, self.test_configs.bt_status,
+            self.test_configs.ble_status, self.test_configs.cellular_status,
+            self.test_configs.cellular_band)
+        self.measure_power_and_validate()
+
+    @test_tracker_info(uuid='f3fc6667-73d8-4fb5-bdf3-0253e52043b1')
+    def test_screen_OFF_WiFi_ON_band_None_bt_ON_ble_ON_cellular_OFF_band_None(
+            self):
+        self.coex_baseline_test_func()
+
+    @test_tracker_info(uuid='1bec36d1-f7b2-4a4b-9f5d-dfb5ed985649')
+    def test_screen_OFF_WiFi_Connected_band_2g_bt_ON_ble_ON_cellular_OFF_band_None(
+            self):
+        self.coex_baseline_test_func()
+
+    @test_tracker_info(uuid='88170cad-8336-4dff-8e53-3cc693d01b72')
+    def test_screen_OFF_WiFi_Connected_band_5g_bt_ON_ble_ON_cellular_OFF_band_None(
+            self):
+        self.coex_baseline_test_func()
+
+    @test_tracker_info(uuid='b82e59a9-9b27-4ba2-88f6-48d7917066f4')
+    def test_screen_OFF_WiFi_OFF_band_None_bt_ON_ble_ON_cellular_ON_band_Verizon(
+            self):
+        self.coex_baseline_test_func()
+
+    @test_tracker_info(uuid='6409a02e-d63a-4c46-a210-1d5f1b006556')
+    def test_screen_OFF_WiFi_Connected_band_5g_bt_OFF_ble_OFF_cellular_ON_band_Verizon(
+            self):
+        self.coex_baseline_test_func()
+
+    @test_tracker_info(uuid='6f22792f-b304-4804-853d-e41484d442ab')
+    def test_screen_OFF_WiFi_Connected_band_2g_bt_OFF_ble_OFF_cellular_ON_band_Verizon(
+            self):
+        self.coex_baseline_test_func()
+
+    @test_tracker_info(uuid='11bb1683-4544-46b4-ad4a-875e31323729')
+    def test_screen_OFF_WiFi_Connected_band_5g_bt_ON_ble_ON_cellular_ON_band_Verizon(
+            self):
+        self.coex_baseline_test_func()
diff --git a/acts/tests/google/power/coex/PowerCoexscanTest.py b/acts/tests/google/power/coex/PowerCoexscanTest.py
new file mode 100644
index 0000000..3d1f1e3
--- /dev/null
+++ b/acts/tests/google/power/coex/PowerCoexscanTest.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 math
+import acts.test_utils.power.PowerCoexBaseTest as PCoBT
+from acts.test_decorators import test_tracker_info
+
+
+class PowerCoexscanTest(PCoBT.PowerCoexBaseTest):
+    def setup_class(self):
+
+        super().setup_class()
+        iterations = math.floor((self.mon_duration + self.mon_offset + 10) /
+                                self.wifi_scan_interval)
+
+        self.PERIODIC_WIFI_SCAN = (
+            'am instrument -w -r -e scan-interval \"%d\" -e scan-iterations'
+            ' \"%d\" -e class com.google.android.platform.powertests.'
+            'WifiTests#testGScanAllChannels com.google.android.platform.'
+            'powertests/android.test.InstrumentationTestRunner > /dev/null &' %
+            (self.wifi_scan_interval, iterations))
+
+    def coex_scan_test_func(self):
+        """Base test function for coex scan tests.
+
+        Steps:
+        1. Setup phone in correct state
+        2. Start desired scans
+        3. Measure power and validate result
+        """
+        attrs = [
+            'screen_status', 'wifi_status', 'wifi_band', 'wifi_scan',
+            'bt_status', 'ble_status', 'ble_scan_mode', 'cellular_status',
+            'cellular_band'
+        ]
+        indices = [2, 4, 6, 8, 10, 12, 15, 17, 19]
+        self.decode_test_configs(attrs, indices)
+        if self.test_configs.ble_scan_mode == 'lowpower':
+            ble_scan_mode = 'low_power'
+        elif self.test_configs.ble_scan_mode == 'lowlatency':
+            ble_scan_mode = 'low_latency'
+        else:
+            ble_scan_mode = self.test_configs.ble_scan_mode
+        self.phone_setup_for_BT(self.test_configs.bt_status,
+                                self.test_configs.ble_status,
+                                self.test_configs.screen_status)
+        self.coex_scan_setup(self.test_configs.wifi_scan, ble_scan_mode,
+                             self.PERIODIC_WIFI_SCAN)
+        self.measure_power_and_validate()
+
+    @test_tracker_info(uuid='a998dd2b-f5f1-4361-b5da-83e42a69e80b')
+    def test_screen_ON_WiFi_Connected_band_2g_scan_OFF_bt_ON_ble_ON_default_scan_balanced_cellular_OFF_band_None(
+            self):
+        self.coex_scan_test_func()
+
+    @test_tracker_info(uuid='87146825-787a-4ea7-9622-30e9286c8a76')
+    def test_screen_OFF_WiFi_Connected_band_2g_scan_OFF_bt_ON_ble_ON_filtered_scan_lowpower_cellular_OFF_band_None(
+            self):
+        self.coex_scan_test_func()
+
+    @test_tracker_info(uuid='2e645deb-b744-4272-8578-5d4cb159d5aa')
+    def test_screen_OFF_WiFi_Connected_band_5g_scan_OFF_bt_ON_ble_ON_filtered_scan_lowpower_cellular_OFF_band_None(
+            self):
+        self.coex_scan_test_func()
+
+    @test_tracker_info(uuid='d458bc41-f1c8-4ed6-a7b5-0bec34780dda')
+    def test_screen_OFF_WiFi_Disconnected_band_2g_scan_ON_bt_ON_ble_ON_page_scan_None_cellular_OFF_band_None(
+            self):
+        self.coex_scan_test_func()
+
+    @test_tracker_info(uuid='6d9c0e8e-6a0f-458b-84d2-7d60fc254170')
+    def test_screen_OFF_WiFi_Disconnected_band_2g_scan_ON_bt_ON_ble_ON_filtered_scan_lowpower_cellular_OFF_band_None(
+            self):
+        self.coex_scan_test_func()
+
+    @test_tracker_info(uuid='ba52317f-426a-4688-a0a5-1394bcc7b092')
+    def test_screen_OFF_WiFi_Disconnected_band_2g_scan_ON_bt_ON_ble_ON_filtered_scan_lowlatency_cellular_OFF_band_None(
+            self):
+        self.coex_scan_test_func()
+
+    @test_tracker_info(uuid='b4c63eac-bc77-4e76-afff-ade98dde4411')
+    def test_screen_OFF_WiFi_Connected_band_2g_scan_PNO_bt_ON_ble_ON_filtered_scan_lowlatency_cellular_OFF_band_None(
+            self):
+        self.coex_scan_test_func()
+
+    @test_tracker_info(uuid='798796dc-960c-42b2-a835-2b2aefa028d5')
+    def test_screen_OFF_WiFi_Disconnected_band_5g_scan_ON_bt_OFF_ble_OFF_no_scan_None_cellular_ON_band_Verizon(
+            self):
+        self.coex_scan_test_func()
+
+    @test_tracker_info(uuid='6ae44d84-0e68-4524-99b2-d3bfbd2253b8')
+    def test_screen_OFF_WiFi_Disconnected_band_5g_scan_ON_bt_OFF_ble_ON_background_scan_lowpower_cellular_ON_band_Verizon(
+            self):
+        self.coex_scan_test_func()
+
+    @test_tracker_info(uuid='2cb915a3-6319-4ac4-9e4d-9325b3b731c8')
+    def test_screen_OFF_WiFi_Disconnected_band_2g_scan_ON_bt_OFF_ble_ON_background_scan_lowlatency_cellular_ON_band_Verizon(
+            self):
+        self.coex_scan_test_func()
diff --git a/acts/tests/google/power/wifi/PowerWiFibaselineTest.py b/acts/tests/google/power/wifi/PowerWiFibaselineTest.py
new file mode 100644
index 0000000..213c81a
--- /dev/null
+++ b/acts/tests/google/power/wifi/PowerWiFibaselineTest.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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.test_utils.power import PowerWiFiBaseTest as PWBT
+from acts.test_utils.wifi import wifi_test_utils as wutils
+from acts.test_decorators import test_tracker_info
+
+
+class PowerWiFibaselineTest(PWBT.PowerWiFiBaseTest):
+    """Power baseline tests for rockbottom state.
+    Rockbottom for wifi on/off, screen on/off, everything else turned off
+
+    """
+
+    def rockbottom_test_func(self):
+        """Test function for baseline rockbottom tests.
+
+        Decode the test config from the test name, set device to desired state.
+        Measure power and validate results.
+        """
+
+        attrs = ['screen_status', 'wifi_status']
+        indices = [3, 5]
+        self.decode_test_configs(attrs, indices)
+        if self.test_configs.wifi_status == 'ON':
+            wutils.wifi_toggle_state(self.dut, True)
+        if self.test_configs.screen_status == 'OFF':
+            self.dut.droid.goToSleepNow()
+            self.dut.log.info('Screen is OFF')
+        self.measure_power_and_validate()
+
+    # Test cases
+    @test_tracker_info(uuid='e7ab71f4-1e14-40d2-baec-cde19a3ac859')
+    def test_rockbottom_screen_OFF_wifi_OFF(self):
+
+        self.rockbottom_test_func()
+
+    @test_tracker_info(uuid='167c847d-448f-4c7c-900f-82c552d7d9bb')
+    def test_rockbottom_screen_OFF_wifi_ON(self):
+
+        self.rockbottom_test_func()
+
+    @test_tracker_info(uuid='2cd25820-8548-4e60-b0e3-63727b3c952c')
+    def test_rockbottom_screen_ON_wifi_OFF(self):
+
+        self.rockbottom_test_func()
+
+    @test_tracker_info(uuid='d7d90a1b-231a-47c7-8181-23814c8ff9b6')
+    def test_rockbottom_screen_ON_wifi_ON(self):
+
+        self.rockbottom_test_func()
diff --git a/acts/tests/google/power/wifi/PowerWiFidtimTest.py b/acts/tests/google/power/wifi/PowerWiFidtimTest.py
new file mode 100644
index 0000000..28a340a
--- /dev/null
+++ b/acts/tests/google/power/wifi/PowerWiFidtimTest.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 time
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.power import PowerWiFiBaseTest as PWBT
+from acts.test_utils.wifi import wifi_power_test_utils as wputils
+
+
+class PowerWiFidtimTest(PWBT.PowerWiFiBaseTest):
+    def dtim_test_func(self, dtim_max=10):
+        """A reusable function for DTIM test.
+        Covering different DTIM value, with screen ON or OFF and 2g/5g network
+
+        Args:
+            dtim: the value for DTIM set on the phone
+            screen_status: screen on or off
+            network: a dict of information for the network to connect
+        """
+        attrs = ['screen_status', 'wifi_band', 'dtim']
+        indices = [2, 4, 6]
+        self.decode_test_configs(attrs, indices)
+        # Initialize the dut to rock-bottom state
+        wputils.change_dtim(
+            self.dut,
+            gEnableModulatedDTIM=int(self.test_configs.dtim),
+            gMaxLIModulatedDTIM=dtim_max)
+        self.dut.log.info('DTIM value of the phone is now {}'.format(
+            self.test_configs.dtim))
+        self.setup_ap_connection(
+            self.main_network[self.test_configs.wifi_band])
+        if self.test_configs.screen_status == 'OFF':
+            self.dut.droid.goToSleepNow()
+            self.dut.log.info('Screen is OFF')
+        time.sleep(5)
+        self.measure_power_and_validate()
+
+    # Test cases
+    @test_tracker_info(uuid='2a70a78b-93a8-46a6-a829-e1624b8239d2')
+    def test_screen_OFF_band_2g_dtim_1(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='b6c4114d-984a-4269-9e77-2bec0e4b6e6f')
+    def test_screen_OFF_band_2g_dtim_2(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='2ae5bc29-3d5f-4fbb-9ff6-f5bd499a9d6e')
+    def test_screen_OFF_band_2g_dtim_4(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='b37fa75f-6166-4247-b15c-adcda8c7038e')
+    def test_screen_OFF_band_2g_dtim_5(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='384d3b0f-4335-4b00-8363-308ec27a150c')
+    def test_screen_ON_band_2g_dtim_1(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='79d0f065-2c46-4400-b02c-5ad60e79afea')
+    def test_screen_ON_band_2g_dtim_4(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='5e2f73cb-7e4e-4a25-8fd5-c85adfdf466e')
+    def test_screen_OFF_band_5g_dtim_1(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='017f57c3-e133-461d-80be-d025d1491d8a')
+    def test_screen_OFF_band_5g_dtim_2(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='b84a1cb3-9573-4bfd-9875-0f33cb171cc5')
+    def test_screen_OFF_band_5g_dtim_4(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='75644df4-2cc8-4bbd-8985-0656a4f9d056')
+    def test_screen_OFF_band_5g_dtim_5(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='327af44d-d9e7-49e0-9bda-accad6241dc7')
+    def test_screen_ON_band_5g_dtim_1(self):
+        self.dtim_test_func()
+
+    @test_tracker_info(uuid='8b32585f-2517-426b-a2c9-8087093cf991')
+    def test_screen_ON_band_5g_dtim_4(self):
+        self.dtim_test_func()
diff --git a/acts/tests/google/power/wifi/PowerWiFimulticastTest.py b/acts/tests/google/power/wifi/PowerWiFimulticastTest.py
new file mode 100644
index 0000000..6b9896c
--- /dev/null
+++ b/acts/tests/google/power/wifi/PowerWiFimulticastTest.py
@@ -0,0 +1,326 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 time
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.power import PowerWiFiBaseTest as PWBT
+from acts.test_utils.wifi import wifi_power_test_utils as wputils
+from acts.controllers import packet_sender as pkt_utils
+
+RA_SHORT_LIFETIME = 3
+RA_LONG_LIFETIME = 1000
+DNS_LONG_LIFETIME = 300
+DNS_SHORT_LIFETIME = 3
+
+
+class PowerWiFimulticastTest(PWBT.PowerWiFiBaseTest):
+    def set_connection(self):
+        """Setup connection between AP and client.
+
+        Setup connection between AP and phone, change DTIMx1 and get information
+        such as IP addresses to prepare packet construction.
+
+        """
+        attrs = ['screen_status', 'wifi_band']
+        indices = [2, 4]
+        self.decode_test_configs(attrs, indices)
+        # Change DTIMx1 on the phone to receive all Multicast packets
+        wputils.change_dtim(
+            self.dut, gEnableModulatedDTIM=1, gMaxLIModulatedDTIM=10)
+        self.dut.log.info('DTIM value of the phone is now DTIMx1')
+
+        self.setup_ap_connection(
+            self.main_network[self.test_configs.wifi_band])
+        # Wait for DHCP with timeout of 60 seconds
+        wputils.wait_for_dhcp(self.pkt_sender.interface)
+
+        # Set the desired screen status
+        if self.test_configs.screen_status == 'OFF':
+            self.dut.droid.goToSleepNow()
+            self.dut.log.info('Screen is OFF')
+        time.sleep(5)
+
+    def sendPacketAndMeasure(self, packet):
+        """Packet injection template function
+
+        Args:
+            packet: packet to be sent/inject
+        """
+        # Start sending packets and measure power
+        self.pkt_sender.start_sending(packet, self.interval)
+        self.measure_power_and_validate()
+
+    # Test cases - screen OFF
+    @test_tracker_info(uuid='b5378aaf-7949-48ac-95fb-ee94c85d49c3')
+    def test_screen_OFF_band_5g_directed_arp(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='3b5d348d-70bf-483d-8736-13da569473aa')
+    def test_screen_OFF_band_5g_misdirected_arp(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.ipv4_dst_fake)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='8e534d3b-5a25-429a-a1bb-8119d7d28b5a')
+    def test_screen_OFF_band_5g_directed_ns(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.NsGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='536d716d-f30b-4d20-9976-e2cbc36c3415')
+    def test_screen_OFF_band_5g_misdirected_ns(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.NsGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.ipv6_dst_fake)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='5eed3174-8e94-428e-8527-19a9b5a90322')
+    def test_screen_OFF_band_5g_ra_short(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(RA_SHORT_LIFETIME)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='67867bae-f1c5-44a4-9bd0-2b832ac8059c')
+    def test_screen_OFF_band_5g_ra_long(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(RA_LONG_LIFETIME)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='db19bc94-3513-45c4-b3a5-d6219649d0bb')
+    def test_screen_OFF_band_5g_directed_dhcp_offer(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.DhcpOfferGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='a8059869-40ee-4cf3-a957-4b7aed03fcf9')
+    def test_screen_OFF_band_5g_misdirected_dhcp_offer(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.DhcpOfferGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.mac_dst_fake, self.ipv4_dst_fake)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='6e663f0a-3eb5-46f6-a79e-311baebd5d2a')
+    def test_screen_OFF_band_5g_ra_rnds_short(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(
+            RA_LONG_LIFETIME, enableDNS=True, dns_lifetime=DNS_SHORT_LIFETIME)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='84d2f1ff-bd4f-46c6-9b06-826d9b14909c')
+    def test_screen_OFF_band_5g_ra_rnds_long(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(
+            RA_LONG_LIFETIME, enableDNS=True, dns_lifetime=DNS_LONG_LIFETIME)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='4a17e74f-3e7f-4e90-ac9e-884a7c13cede')
+    def test_screen_OFF_band_5g_directed_ping6(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Ping6Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='ab249e0d-58ba-4b55-8a81-e1e4fb04780a')
+    def test_screen_OFF_band_5g_misdirected_ping6(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Ping6Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.ipv6_dst_fake, pkt_utils.MAC_BROADCAST)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='e37112e6-5c35-4c89-8d15-f5a44e69be0b')
+    def test_screen_OFF_band_5g_directed_ping4(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Ping4Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='afd4a011-63a9-46c3-8a75-13f515ba8475')
+    def test_screen_OFF_band_5g_misdirected_ping4(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Ping4Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.ipv4_dst_fake, pkt_utils.MAC_BROADCAST)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='03f0e845-fd66-4120-a79d-5eb64d49b6cd')
+    def test_screen_OFF_band_5g_mdns6(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Mdns6Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='dcbb0aec-512d-48bd-b743-024697ce511b')
+    def test_screen_OFF_band_5g_mdns4(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Mdns4Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    # Test cases: screen ON
+    @test_tracker_info(uuid='b9550149-bf36-4f86-9b4b-6e900756a90e')
+    def test_screen_ON_band_5g_directed_arp(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='406dffae-104e-46cb-9ec2-910aac7aca39')
+    def test_screen_ON_band_5g_misdirected_arp(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.ipv4_dst_fake)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='be4cb543-c710-4041-a770-819e82a6d164')
+    def test_screen_ON_band_5g_directed_ns(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.NsGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='de21d24f-e03e-47a1-8bbb-11953200e870')
+    def test_screen_ON_band_5g_misdirected_ns(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.NsGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.ipv6_dst_fake)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='b424a170-5095-4b47-82eb-50f7b7fdf35d')
+    def test_screen_ON_band_5g_ra_short(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(RA_SHORT_LIFETIME)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='ab627e59-2ee8-4c0d-970b-eeb1d1cecdc1')
+    def test_screen_ON_band_5g_ra_long(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(RA_LONG_LIFETIME)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='ee6514ab-1814-44b9-ba01-63f77ba77c34')
+    def test_screen_ON_band_5g_directed_dhcp_offer(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.DhcpOfferGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='eaebfe98-32da-4ebc-bca7-3b7026d99a4f')
+    def test_screen_ON_band_5g_misdirected_dhcp_offer(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.DhcpOfferGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.mac_dst_fake, self.ipv4_dst_fake)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='f0e2193f-bf6a-441b-b9c1-bb7b65787cd5')
+    def test_screen_ON_band_5g_ra_rnds_short(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(
+            RA_LONG_LIFETIME, enableDNS=True, dns_lifetime=DNS_SHORT_LIFETIME)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='62b99cd7-75bf-45be-b93f-bb037a13b3e2')
+    def test_screen_ON_band_5g_ra_rnds_long(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(
+            RA_LONG_LIFETIME, enableDNS=True, dns_lifetime=DNS_LONG_LIFETIME)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='4088af4c-a64b-4fc1-848c-688936cc6c12')
+    def test_screen_ON_band_5g_directed_ping6(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Ping6Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='3179e327-e6ac-4dae-bb8a-f3940f21094d')
+    def test_screen_ON_band_5g_misdirected_ping6(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Ping6Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.ipv6_dst_fake, pkt_utils.MAC_BROADCAST)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='90c70e8a-74fd-4878-89c6-5e15c3ede318')
+    def test_screen_ON_band_5g_directed_ping4(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Ping4Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='dcfabbc7-a7e1-4a92-a38d-8ebe7aa2e063')
+    def test_screen_ON_band_5g_misdirected_ping4(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Ping4Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate(self.ipv4_dst_fake, pkt_utils.MAC_BROADCAST)
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='117814db-f94d-4239-a7ab-033482b1da52')
+    def test_screen_ON_band_5g_mdns6(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Mdns6Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
+
+    @test_tracker_info(uuid='ce6ad7e2-21f3-4e68-9c0d-d0e14e0a7c53')
+    def test_screen_ON_band_5g_mdns4(self):
+        self.set_connection()
+        self.pkt_gen_config = wputils.create_pkt_config(self)
+        pkt_gen = pkt_utils.Mdns4Generator(**self.pkt_gen_config)
+        packet = pkt_gen.generate()
+        self.sendPacketAndMeasure(packet)
diff --git a/acts/tests/google/power/wifi/PowerWiFiroamingTest.py b/acts/tests/google/power/wifi/PowerWiFiroamingTest.py
new file mode 100644
index 0000000..6f9dcdd
--- /dev/null
+++ b/acts/tests/google/power/wifi/PowerWiFiroamingTest.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 time
+from acts import utils
+from acts.controllers.ap_lib import hostapd_constants as hc
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.power import PowerWiFiBaseTest as PWBT
+from acts.test_utils.wifi import wifi_constants as wc
+from acts.test_utils.wifi import wifi_test_utils as wutils
+from acts.test_utils.wifi import wifi_power_test_utils as wputils
+
+
+class PowerWiFiroamingTest(PWBT.PowerWiFiBaseTest):
+
+    # Test cases
+    @test_tracker_info(uuid='392622d3-0c5c-4767-afa2-abfb2058b0b8')
+    def test_screenoff_roaming(self):
+        """Test roaming power consumption with screen off.
+        Change the attenuation level to trigger roaming between two APs
+
+        """
+        self.log.info('Set attenuation to connect device to both APs')
+        self.set_attenuation(self.atten_level['zero_atten'])
+        # Setup both APs
+        network_main = self.main_network[hc.BAND_2G]
+        network_aux = self.aux_network[hc.BAND_2G]
+        self.brconfigs_aux = self.setup_ap_connection(network_aux)
+        self.brconfigs_main = self.setup_ap_connection(network_main)
+        self.dut.droid.goToSleepNow()
+        time.sleep(5)
+        # Set attenuator to trigger roaming
+        self.dut.log.info('Trigger roaming now')
+        self.set_attenuation(self.atten_level[self.current_test_name])
+        self.measure_power_and_validate()
+
+    @test_tracker_info(uuid='2fec5208-043a-410a-8fd2-6784d70a3587')
+    def test_screenoff_fastroaming(self):
+
+        # Setup the aux AP
+        network_main = self.main_network[hc.BAND_2G]
+        network_aux = self.aux_network[hc.BAND_2G]
+        # Set the same SSID for the AUX AP for fastroaming purpose
+        network_aux[wc.SSID] = network_main[wc.SSID]
+        # Set attenuator to connect the phone to the aux AP
+        self.log.info('Set attenuation to connect device to the aux AP')
+        self.set_attenuation(self.atten_level[wc.AP_AUX])
+        self.brconfigs_aux = self.setup_ap_connection(network_aux)
+        # Set attenuator to connect the phone to main AP
+        self.log.info('Set attenuation to connect device to the main AP')
+        self.set_attenuation(self.atten_level[wc.AP_MAIN])
+        self.brconfigs_main = self.setup_ap_connection(network_main)
+        time.sleep(5)
+        self.dut.droid.goToSleepNow()
+        # Trigger fastroaming
+        self.dut.log.info('Trigger fastroaming now')
+        self.set_attenuation(self.atten_level[wc.AP_AUX])
+        self.measure_power_and_validate()
+
+    @test_tracker_info(uuid='a0459b7c-74ce-4adb-8e55-c5365bc625eb')
+    def test_screenoff_toggle_between_AP(self):
+
+        # Set attenuator to connect phone to both networks
+        self.log.info('Set attenuation to connect device to both APs')
+        self.set_attenuation(self.atten_level[self.current_test_name])
+        # Connect to both APs
+        network_main = self.main_network[hc.BAND_2G]
+        network_aux = self.aux_network[hc.BAND_2G]
+        self.brconfigs_main = self.setup_ap_connection(network_main)
+        self.brconfigs_aux = self.setup_ap_connection(network_aux)
+        self.mon_info.duration = self.toggle_interval
+        self.dut.droid.goToSleepNow()
+        time.sleep(5)
+        # Toggle between two networks
+        begin_time = utils.get_current_epoch_time()
+        for i in range(self.toggle_times):
+            self.dut.log.info('Connecting to %s' % network_main[wc.SSID])
+            self.dut.droid.wifiConnect(network_main)
+            file_path, avg_current = wputils.monsoon_data_collect_save(
+                self.dut, self.mon_info, self.current_test_name)
+            self.dut.log.info('Connecting to %s' % network_aux[wc.SSID])
+            self.dut.droid.wifiConnect(network_aux)
+            file_path, avg_current = wputils.monsoon_data_collect_save(
+                self.dut, self.mon_info, self.current_test_name)
+        [plot, dt] = wputils.monsoon_data_plot(self.mon_info, file_path)
+        avg_current = dt.source.data['y0'][0]
+        # Take Bugreport
+        if self.bug_report:
+            self.dut.take_bug_report(self.test_name, begin_time)
+        # Path fail check
+        wputils.pass_fail_check(self, avg_current)
+
+    @test_tracker_info(uuid='e5ff95c0-b17e-425c-a903-821ba555a9b9')
+    def test_screenon_toggle_between_AP(self):
+
+        # Set attenuator to connect phone to both networks
+        self.log.info('Set attenuation to connect device to both APs')
+        self.set_attenuation(self.atten_level[self.current_test_name])
+        # Connect to both APs
+        network_main = self.main_network[hc.BAND_2G]
+        network_aux = self.aux_network[hc.BAND_2G]
+        self.brconfigs_main = self.setup_ap_connection(network_main)
+        self.brconfigs_aux = self.setup_ap_connection(network_aux)
+        self.mon_info.duration = self.toggle_interval
+        time.sleep(5)
+        # Toggle between two networks
+        begin_time = utils.get_current_epoch_time()
+        for i in range(self.toggle_times):
+            self.dut.log.info('Connecting to %s' % network_main[wc.SSID])
+            self.dut.droid.wifiConnect(network_main)
+            file_path, avg_current = wputils.monsoon_data_collect_save(
+                self.dut, self.mon_info, self.current_test_name)
+            self.dut.log.info('Connecting to %s' % network_aux[wc.SSID])
+            self.dut.droid.wifiConnect(network_aux)
+            file_path, avg_current = wputils.monsoon_data_collect_save(
+                self.dut, self.mon_info, self.current_test_name)
+        [plot, dt] = wputils.monsoon_data_plot(self.mon_info, file_path)
+        avg_current = dt.source.data['y0'][0]
+        # Take Bugreport
+        if self.bug_report:
+            self.dut.take_bug_report(self.test_name, begin_time)
+        # Path fail check
+        wputils.pass_fail_check(self, avg_current)
+
+    @test_tracker_info(uuid='a16ae337-326f-4d09-990f-42232c3c0dc4')
+    def test_screenoff_wifi_wedge(self):
+
+        # Set attenuator to connect phone to both networks
+        self.log.info('Set attenuation to connect device to both APs')
+        self.set_attenuation(self.atten_level['zero_atten'])
+        # Connect to both APs
+        network_main = self.main_network[hc.BAND_2G]
+        network_aux = self.aux_network[hc.BAND_2G]
+        self.brconfigs_main = self.setup_ap_connection(network_main)
+        self.brconfigs_aux = self.setup_ap_connection(network_aux)
+        self.log.info('Forget network {}'.format(network_aux[wc.SSID]))
+        wutils.wifi_forget_network(self.dut, network_aux[wc.SSID])
+        self.log.info('Set attenuation to trigger wedge condition')
+        self.set_attenuation(self.atten_level[self.current_test_name])
+        self.dut.droid.goToSleepNow()
+        self.measure_power_and_validate()
diff --git a/acts/tests/google/power/wifi/PowerWiFiscanTest.py b/acts/tests/google/power/wifi/PowerWiFiscanTest.py
new file mode 100644
index 0000000..5b8de6c
--- /dev/null
+++ b/acts/tests/google/power/wifi/PowerWiFiscanTest.py
@@ -0,0 +1,181 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 time
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.power import PowerWiFiBaseTest as PWBT
+from acts.test_utils.wifi import wifi_test_utils as wutils
+
+UNLOCK_SCREEN = 'input keyevent 82'
+
+
+class PowerWiFiscanTest(PWBT.PowerWiFiBaseTest):
+    def setup_class(self):
+        super().setup_class()
+        # Setup scan command
+        SINGLE_SHOT_SCAN = (
+            'am instrument -w -r  -e min_scan_count \"700\"'
+            ' -e WifiScanTest-testWifiSingleShotScan %d'
+            ' -e class com.google.android.platform.powertests.'
+            'WifiScanTest#testWifiSingleShotScan'
+            ' com.google.android.platform.powertests/'
+            'android.test.InstrumentationTestRunner > /dev/null &' %
+            (self.mon_duration + self.mon_offset + 10))
+        BACKGROUND_SCAN = ('am instrument -w -r -e min_scan_count \"1\" -e '
+                           'WifiScanTest-testWifiBackgroundScan %d -e class '
+                           'com.google.android.platform.powertests.WifiScan'
+                           'Test#testWifiBackgroundScan com.google.android.'
+                           'platform.powertests/android.test.Instrumentation'
+                           'TestRunner > /dev/null &' %
+                           (self.mon_duration + self.mon_offset + 10))
+        WIFI_SCAN = ('am instrument -w -r -e min_scan_count \"1\" -e '
+                     'WifiScanTest-testWifiScan %d -e class '
+                     'com.google.android.platform.powertests.WifiScanTest#'
+                     'testWifiScan com.google.android.platform.powertests/'
+                     'android.test.InstrumentationTestRunner > /dev/null &' %
+                     (self.mon_duration + self.mon_offset + 10))
+        self.APK_SCAN_CMDS = {
+            'singleshot': SINGLE_SHOT_SCAN,
+            'background': BACKGROUND_SCAN,
+            'wifi': WIFI_SCAN
+        }
+
+    def scan_setup(self):
+        """Setup for scan based on the type of scan.
+
+        Trigger the desired scan.
+        """
+        self.log.info('Trigger {} scans'.format(self.test_configs.scan_mode))
+        if self.test_configs.scan_type == 'apk':
+            atten_setting = self.test_configs.wifi_band + '_' + self.test_configs.rssi
+            self.set_attenuation(self.atten_level[atten_setting])
+            self.dut.adb.shell_nb(
+                self.APK_SCAN_CMDS[self.test_configs.scan_mode])
+        else:
+            self.mon_info.offset = 0
+            if self.test_configs.scan_mode == 'pno':
+                self.log.info('Set attenuation to trigger PNO scan')
+                self.set_attenuation(self.atten_level['max_atten'])
+            elif self.test_configs.scan_mode == 'connectivity':
+                self.dut.droid.wakeUpNow()
+                self.log.info(
+                    'Now turn on screen to trigger connectivity scans')
+                self.dut.adb.shell(UNLOCK_SCREEN)
+            elif self.test_configs.scan_mode == 'roaming':
+                atten_setting = self.test_configs.wifi_band + '_roaming'
+                self.set_attenuation(self.atten_level[atten_setting])
+
+    def wifi_scan_test_func(self):
+
+        attrs = [
+            'screen_status', 'wifi_status', 'wifi_band', 'rssi', 'scan_type',
+            'scan_mode'
+        ]
+        indices = [2, 4, 6, 8, 10, 11]
+        self.decode_test_configs(attrs, indices)
+        if self.test_configs.wifi_status == 'Disconnected':
+            self.setup_ap_connection(
+                self.main_network[self.test_configs.wifi_band], connect=False)
+        elif self.test_configs.wifi_status == 'Connected':
+            self.setup_ap_connection(
+                self.main_network[self.test_configs.wifi_band])
+        else:
+            wutils.wifi_toggle_state(self.dut, True)
+        if self.test_configs.screen_status == 'OFF':
+            self.dut.droid.goToSleepNow()
+            self.dut.log.info('Screen is OFF')
+        time.sleep(2)
+        self.scan_setup()
+        self.measure_power_and_validate()
+
+    # Test cases
+    # Power.apk triggered scans
+    @test_tracker_info(uuid='e5539b01-e208-43c6-bebf-6f1e73d8d8cb')
+    def test_screen_OFF_WiFi_Disconnected_band_2g_RSSI_high_scan_apk_singleshot(
+            self):
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='14c5a762-95bc-40ea-9fd4-27126df7d86c')
+    def test_screen_OFF_WiFi_Disconnected_band_2g_RSSI_low_scan_apk_singleshot(
+            self):
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='a6506600-c567-43b5-9c25-86b505099b97')
+    def test_screen_OFF_WiFi_Disconnected_band_2g_RSSI_none_scan_apk_singleshot(
+            self):
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='1a458248-1159-4c8e-a39f-92fc9e69c4dd')
+    def test_screen_OFF_WiFi_Disconnected_band_5g_RSSI_high_scan_apk_singleshot(
+            self):
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='bd4da426-a621-4131-9f89-6e5a77f321d2')
+    def test_screen_OFF_WiFi_Disconnected_band_5g_RSSI_low_scan_apk_singleshot(
+            self):
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='288b3add-8925-4803-81c0-53debf157ffc')
+    def test_screen_OFF_WiFi_Disconnected_band_5g_RSSI_none_scan_apk_singleshot(
+            self):
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='f401c66c-e515-4f51-8ef2-2a03470d8ff2')
+    def test_screen_OFF_WiFi_Disconnected_band_5g_RSSI_high_scan_apk_background(
+            self):
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='fe38c1c7-937c-42c0-9381-98356639df8f')
+    def test_screen_OFF_WiFi_Disconnected_band_2g_RSSI_high_scan_apk_wifi(
+            self):
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='8eedefd1-3a08-4ac2-ba55-5eb438def3d4')
+    def test_screen_OFF_WiFi_Disconnected_band_5g_RSSI_high_scan_apk_wifi(
+            self):
+        self.wifi_scan_test_func()
+
+    # Firmware/framework scans
+    @test_tracker_info(uuid='ff5ea952-ee31-4968-a190-82935ce7a8cb')
+    def test_screen_OFF_WiFi_ON_band_5g_RSSI_high_scan_system_connectivity(
+            self):
+        """WiFi disconected, turn on Screen to trigger connectivity scans.
+
+        """
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='9a836e5b-8128-4dd2-8e96-e79177810bdd')
+    def test_screen_OFF_WiFi_Connected_band_2g_RSSI_high_scan_system_connectivity(
+            self):
+        """WiFi connected to 2g, turn on screen to trigger connectivity scans.
+
+        """
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='51e3c4f1-742b-45af-afd5-ae3552a03272')
+    def test_screen_OFF_WiFi_Connected_band_2g_RSSI_high_scan_system_roaming(
+            self):
+        """WiFi connected to 2g, low RSSI to be below roaming threshold.
+
+        """
+        self.wifi_scan_test_func()
+
+    @test_tracker_info(uuid='a16ae337-326f-4d09-990f-42232c3c0dc4')
+    def test_screen_OFF_WiFi_Connected_band_2g_RSSI_high_scan_system_pno(self):
+        """WiFi connected to 2g, trigger pno scan.
+
+        """
+        self.wifi_scan_test_func()
diff --git a/acts/tests/google/power/wifi/PowerWiFitrafficTest.py b/acts/tests/google/power/wifi/PowerWiFitrafficTest.py
new file mode 100644
index 0000000..05a7f8a
--- /dev/null
+++ b/acts/tests/google/power/wifi/PowerWiFitrafficTest.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python3.4
+#
+#   Copyright 2018 - 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 time
+from acts.test_decorators import test_tracker_info
+from acts.test_utils.power import PowerWiFiBaseTest as PWBT
+from acts.test_utils.wifi import wifi_power_test_utils as wputils
+
+TEMP_FILE = '/sdcard/Download/tmp.log'
+
+
+class PowerWiFitrafficTest(PWBT.PowerWiFiBaseTest):
+    def iperf_power_test_func(self):
+        """Test function for iperf power measurement at different RSSI level.
+
+        """
+        # Decode the test configs from test name
+        attrs = [
+            'screen_status', 'band', 'traffic_direction', 'traffic_type',
+            'signal_level', 'oper_mode', 'bandwidth'
+        ]
+        indices = [3, 4, 5, 6, 7, 9, 10]
+        self.decode_test_configs(attrs, indices)
+
+        # Set attenuator to desired level
+        self.log.info('Set attenuation to desired RSSI level')
+        atten_setting = self.test_configs.band + '_' + self.test_configs.signal_level
+        self.set_attenuation(self.atten_level[atten_setting])
+
+        # Setup AP and connect dut to the network
+        self.setup_ap_connection(
+            network=self.main_network[self.test_configs.band],
+            bandwidth=int(self.test_configs.bandwidth))
+        # Wait for DHCP on the ethernet port and get IP as Iperf server address
+        # Time out in 60 seconds if not getting DHCP address
+        self.iperf_server_address = wputils.wait_for_dhcp(
+            self.pkt_sender.interface)
+
+        time.sleep(5)
+        if self.test_configs.screen_status == 'OFF':
+            self.dut.droid.goToSleepNow()
+        self.RSSI = wputils.get_wifi_rssi(self.dut)
+
+        # Run IPERF
+        self.setup_iperf()
+        self.iperf_server.start()
+        wputils.run_iperf_client_nonblocking(
+            self.dut, self.iperf_server_address, self.iperf_args)
+
+        self.measure_power_and_validate()
+
+    def setup_iperf(self):
+        """Setup iperf command and arguments.
+
+        """
+        # Construct the iperf command based on the test params
+        iperf_args = '-i 1 -t {} -p {} -J'.format(self.iperf_duration,
+                                                  self.iperf_server.port)
+        if self.test_configs.traffic_type == "UDP":
+            iperf_args = iperf_args + "-u -b 2g"
+        if self.test_configs.traffic_direction == "DL":
+            iperf_args = iperf_args + ' -R'
+            self.use_client_output = True
+        else:
+            self.use_client_output = False
+        # Parse the client side data to a file saved on the phone
+        self.iperf_args = iperf_args + ' > %s' % TEMP_FILE
+
+    # Screen off TCP test cases
+    @test_tracker_info(uuid='93f79f74-88d9-4781-bff0-8899bed1c336')
+    def test_traffic_screen_OFF_2g_DL_TCP_high_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='147eff45-97d7-47c0-b306-f84d9adecd9b')
+    def test_traffic_screen_OFF_2g_DL_TCP_medium_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='5982268b-57e4-40bf-848e-fee80fabf9d7')
+    def test_traffic_screen_OFF_2g_DL_TCP_low_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='c71a8c77-d355-4a82-b9f1-7cc8b888abd8')
+    def test_traffic_screen_OFF_5g_DL_TCP_high_RSSI_VHT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='307945a6-32b7-42d0-a26c-d439f1599963')
+    def test_traffic_screen_OFF_5g_DL_TCP_medium_RSSI_VHT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='e9a900a1-e263-45ad-bdf3-9c463f761d3c')
+    def test_traffic_screen_OFF_5g_DL_TCP_low_RSSI_VHT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='1d1d9a06-98e1-486e-a1db-2102708161ec')
+    def test_traffic_screen_OFF_5g_DL_TCP_high_RSSI_VHT_40(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='feeaad15-6893-4d49-aaf6-bf9802780f5d')
+    def test_traffic_screen_OFF_5g_DL_TCP_medium_RSSI_VHT_40(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='f378679a-1c20-43a1-bff6-a6a5482a8e3d')
+    def test_traffic_screen_OFF_5g_DL_TCP_low_RSSI_VHT_40(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='6a05f133-49e5-4436-ba84-0746f04021ef')
+    def test_traffic_screen_OFF_5g_DL_TCP_high_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='750bf1c3-2099-4b89-97dd-18f8e72df462')
+    def test_traffic_screen_OFF_5g_DL_TCP_medium_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='1ea458af-1ae0-40ee-853d-ac57b51d3eda')
+    def test_traffic_screen_OFF_5g_DL_TCP_low_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='43d9b146-3547-4a27-9d79-c9341c32ccda')
+    def test_traffic_screen_OFF_2g_UL_TCP_high_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='f00a868b-c8b1-4b36-8136-b39b5c2396a7')
+    def test_traffic_screen_OFF_2g_UL_TCP_medium_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='cd0c37ac-23fe-4dd1-9130-ccb2dfa71020')
+    def test_traffic_screen_OFF_2g_UL_TCP_low_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='f9173d39-b46d-4d80-a5a5-7966f5eed9de')
+    def test_traffic_screen_OFF_5g_UL_TCP_high_RSSI_VHT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='cf77e1dc-30bc-4df9-88be-408f1fddc24f')
+    def test_traffic_screen_OFF_5g_UL_TCP_medium_RSSI_VHT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='48f91745-22dc-47c9-ace6-c2719df651d6')
+    def test_traffic_screen_OFF_5g_UL_TCP_low_RSSI_VHT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='18456aa7-62f0-4560-a7dc-4d7e01f6aca5')
+    def test_traffic_screen_OFF_5g_UL_TCP_high_RSSI_VHT_40(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='8ad237d7-f5e1-45e1-a4a2-a010628a4db9')
+    def test_traffic_screen_OFF_5g_UL_TCP_medium_RSSI_VHT_40(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='3e29173f-b950-4a41-a7f6-6cc0731bf477')
+    def test_traffic_screen_OFF_5g_UL_TCP_low_RSSI_VHT_40(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='3d4cdb21-a1b0-4011-9956-ca0b7a9f3bec')
+    def test_traffic_screen_OFF_5g_UL_TCP_high_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='8427d3f0-9418-4b5c-aea9-7509e5959ce6')
+    def test_traffic_screen_OFF_5g_UL_TCP_medium_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='5ac91734-0323-464b-b04a-c7d3d7ff8cdf')
+    def test_traffic_screen_OFF_5g_UL_TCP_low_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    # Screen off UDP tests - only check 5g VHT 80
+    @test_tracker_info(uuid='1ab4a4e2-bce2-4ff8-be9d-f8ed2bb617cd')
+    def test_traffic_screen_OFF_5g_DL_UDP_high_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='a2c66d63-e93f-42aa-a021-0c6cdfdc87b8')
+    def test_traffic_screen_OFF_5g_DL_UDP_medium_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='68e6f92a-ae15-4e76-81e7-a7b491e181fe')
+    def test_traffic_screen_OFF_5g_DL_UDP_low_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='258500f4-f177-43df-82a7-a64d66e90720')
+    def test_traffic_screen_OFF_5g_UL_UDP_high_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='3d2d3d45-575d-4080-86f9-b32a96963032')
+    def test_traffic_screen_OFF_5g_UL_UDP_medium_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='a17c7d0b-58ca-47b5-9f32-0b7a3d7d3d9d')
+    def test_traffic_screen_OFF_5g_UL_UDP_low_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    # Screen on point check
+    @test_tracker_info(uuid='c1c71639-4463-4999-8f5d-7d9153402c79')
+    def test_traffic_screen_ON_2g_DL_TCP_high_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='40daebc4-45a2-4299-b724-e8cb917b86e8')
+    def test_traffic_screen_ON_5g_DL_TCP_high_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='2e286f36-1a47-4895-a0e8-a161d6a9fd9f')
+    def test_traffic_screen_ON_2g_UL_TCP_high_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='9f6b52cb-b48a-4382-8061-3d3a511a261a')
+    def test_traffic_screen_ON_5g_UL_TCP_high_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='59d79274-15cf-446b-a567-655c07f8a778')
+    def test_traffic_screen_ON_2g_DL_UDP_high_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='02891671-48cc-4186-9a95-3e02671477d0')
+    def test_traffic_screen_ON_5g_DL_UDP_high_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='02821540-7b08-4e4f-a1f1-b455fd4cec6e')
+    def test_traffic_screen_ON_2g_UL_UDP_high_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='59ea06ac-3ac8-4ecc-abb1-bcde34f47358')
+    def test_traffic_screen_ON_2g_UL_UDP_medium_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='0cbbd849-7b59-4143-95e7-92cf1fd955dc')
+    def test_traffic_screen_ON_2g_UL_UDP_low_RSSI_HT_20(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='d84f11d8-41a9-4ce8-a351-ebb0379d56c1')
+    def test_traffic_screen_ON_5g_UL_UDP_high_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='01b6087c-b39a-441d-90e9-da659aa0db7f')
+    def test_traffic_screen_ON_5g_UL_UDP_medium_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
+
+    @test_tracker_info(uuid='7e16dcaa-128f-4874-ab52-2f43e25e6da8')
+    def test_traffic_screen_ON_5g_UL_UDP_low_RSSI_VHT_80(self):
+
+        self.iperf_power_test_func()
diff --git a/acts/tests/google/power/wifi/PowerbaselineTest.py b/acts/tests/google/power/wifi/PowerbaselineTest.py
deleted file mode 100644
index f74f639..0000000
--- a/acts/tests/google/power/wifi/PowerbaselineTest.py
+++ /dev/null
@@ -1,121 +0,0 @@
-#!/usr/bin/env python3.4
-#
-#   Copyright 2017 - 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 logging
-import os
-from acts import base_test
-from acts import utils
-from acts.test_utils.wifi import wifi_test_utils as wutils
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-from acts.test_decorators import test_tracker_info
-
-
-class PowerbaselineTest(base_test.BaseTestClass):
-    """Power baseline tests for rockbottom state.
-    Rockbottom for wifi on/off, screen on/off, everything else turned off
-
-    """
-
-    def __init__(self, controllers):
-
-        base_test.BaseTestClass.__init__(self, controllers)
-
-    def setup_class(self):
-
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        req_params = ['baselinetest_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.baselinetest_params)
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(8.0)
-        self.mon.set_voltage(4.2)
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-
-    def teardown_class(self):
-        """Tearing down the entire test class.
-
-        """
-        self.log.info('Tearing down the test class')
-        self.mon.usb('on')
-
-    def teardown_test(self):
-        """Tearing down the test case.
-
-        """
-        self.log.info('Tearing down the test')
-        self.mon.usb('on')
-
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters.
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    def rockbottom_test_func(self, screen_status, wifi_status):
-        """Test function for baseline rockbottom tests.
-
-        Args:
-            screen_status: screen on or off
-            wifi_status: wifi enable or disable, on/off, not connected even on
-        """
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        if wifi_status == 'ON':
-            wutils.wifi_toggle_state(self.dut, True)
-        if screen_status == 'OFF':
-            self.dut.droid.goToSleepNow()
-            self.dut.log.info('Screen is OFF')
-        # Collecting current measurement data and plot
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        wputils.pass_fail_check(self, avg_current)
-
-    # Test cases
-    @test_tracker_info(uuid='e7ab71f4-1e14-40d2-baec-cde19a3ac859')
-    def test_rockbottom_screenoff_wifidisabled(self):
-
-        self.rockbottom_test_func('OFF', 'OFF')
-
-    @test_tracker_info(uuid='167c847d-448f-4c7c-900f-82c552d7d9bb')
-    def test_rockbottom_screenoff_wifidisconnected(self):
-
-        self.rockbottom_test_func('OFF', 'ON')
-
-    @test_tracker_info(uuid='2cd25820-8548-4e60-b0e3-63727b3c952c')
-    def test_rockbottom_screenon_wifidisabled(self):
-
-        self.rockbottom_test_func('ON', 'OFF')
-
-    @test_tracker_info(uuid='d7d90a1b-231a-47c7-8181-23814c8ff9b6')
-    def test_rockbottom_screenon_wifidisconnected(self):
-
-        self.rockbottom_test_func('ON', 'ON')
diff --git a/acts/tests/google/power/wifi/PowerdtimTest.py b/acts/tests/google/power/wifi/PowerdtimTest.py
deleted file mode 100644
index 1a91e95..0000000
--- a/acts/tests/google/power/wifi/PowerdtimTest.py
+++ /dev/null
@@ -1,200 +0,0 @@
-#!/usr/bin/env python3.4
-#
-#   Copyright 2017 - 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 logging
-import os
-import time
-from acts import base_test
-from acts import utils
-from acts.controllers.ap_lib import hostapd_constants as hc
-from acts.test_decorators import test_tracker_info
-from acts.test_utils.wifi import wifi_test_utils as wutils
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-
-
-class PowerdtimTest(base_test.BaseTestClass):
-    def __init__(self, controllers):
-
-        base_test.BaseTestClass.__init__(self, controllers)
-
-    def setup_class(self):
-
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        self.access_point = self.access_points[0]
-        req_params = ['dtimtest_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.dtimtest_params)
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(8.0)
-        self.mon.set_voltage(4.2)
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        self.num_atten = self.attenuators[0].instrument.num_atten
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-            elif 'attenuator_setting' in file:
-                self.attenuation_file = file
-            elif 'network_config' in file:
-                self.network_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-        self.atten_level = wputils.unpack_custom_file(self.attenuation_file,
-                                                      self.TAG)
-        self.networks = wputils.unpack_custom_file(self.network_file)
-        self.main_network = self.networks['main_network']
-
-    def teardown_test(self):
-        """Tear down necessary objects after test case is finished.
-
-        Bring down the AP interface and connect device back on.
-        """
-        self.log.info('Tearing down the test case')
-        self.access_point.bridge.teardown(self.brconfigs)
-        self.access_point.close()
-        self.mon.usb('on')
-
-    def teardown_class(self):
-
-        self.log.info('Tearing down the test class')
-        self.access_point.close()
-        self.mon.usb('on')
-
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters.
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    def dtim_test_func(self, dtim, screen_status, network, dtim_max=10):
-        """A reusable function for DTIM test.
-        Covering different DTIM value, with screen ON or OFF and 2g/5g network
-
-        Args:
-            dtim: the value for DTIM set on the phone
-            screen_status: screen on or off
-            network: a dict of information for the network to connect
-        """
-        # Initialize the dut to rock-bottom state
-        wputils.change_dtim(
-            self.dut, gEnableModulatedDTIM=dtim, gMaxLIModulatedDTIM=dtim_max)
-        self.dut.log.info('DTIM value of the phone is now {}'.format(dtim))
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        [
-            self.attenuators[i].set_atten(self.atten_level['zero_atten'][i])
-            for i in range(self.num_atten)
-        ]
-        self.log.info('Set attenuation level to connect to the AP')
-        # Set up the AP
-        self.brconfigs = wputils.ap_setup(self.access_point, network, 20)
-        wutils.wifi_connect(self.dut, network)
-        if screen_status == 'OFF':
-            self.dut.droid.goToSleepNow()
-            self.dut.log.info('Screen is OFF')
-        time.sleep(5)
-        # Collect power data and plot
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Pass and fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    # Test cases
-    @test_tracker_info(uuid='2a70a78b-93a8-46a6-a829-e1624b8239d2')
-    def test_2g_screenoff_dtimx1(self):
-        network = self.main_network[hc.BAND_2G]
-        self.dtim_test_func(1, 'OFF', network)
-
-    @test_tracker_info(uuid='b6c4114d-984a-4269-9e77-2bec0e4b6e6f')
-    def test_2g_screenoff_dtimx2(self):
-        network = self.main_network[hc.BAND_2G]
-        self.dtim_test_func(2, 'OFF', network)
-
-    @test_tracker_info(uuid='2ae5bc29-3d5f-4fbb-9ff6-f5bd499a9d6e')
-    def test_2g_screenoff_dtimx4(self):
-        network = self.main_network[hc.BAND_2G]
-        self.dtim_test_func(4, 'OFF', network)
-
-    @test_tracker_info(uuid='b37fa75f-6166-4247-b15c-adcda8c7038e')
-    def test_2g_screenoff_dtimx5(self):
-        network = self.main_network[hc.BAND_2G]
-        self.dtim_test_func(5, 'OFF', network)
-
-    @test_tracker_info(uuid='384d3b0f-4335-4b00-8363-308ec27a150c')
-    def test_2g_screenon_dtimx1(self):
-        """With screen on, modulated dtim isn't wokring, always DTIMx1.
-        So not running through all DTIM cases
-
-        """
-        network = self.main_network[hc.BAND_2G]
-        self.dtim_test_func(1, 'ON', network)
-
-    @test_tracker_info(uuid='79d0f065-2c46-4400-b02c-5ad60e79afea')
-    def test_2g_screenon_dtimx4(self):
-        """Run only extra DTIMx4 for screen on to compare with DTIMx1.
-        They should be the same if everything is correct.
-
-        """
-        network = self.main_network[hc.BAND_2G]
-        self.dtim_test_func(4, 'ON', network)
-
-    @test_tracker_info(uuid='5e2f73cb-7e4e-4a25-8fd5-c85adfdf466e')
-    def test_5g_screenoff_dtimx1(self):
-        network = self.main_network[hc.BAND_5G]
-        self.dtim_test_func(1, 'OFF', network)
-
-    @test_tracker_info(uuid='017f57c3-e133-461d-80be-d025d1491d8a')
-    def test_5g_screenoff_dtimx2(self):
-        network = self.main_network[hc.BAND_5G]
-        self.dtim_test_func(2, 'OFF', network)
-
-    @test_tracker_info(uuid='b84a1cb3-9573-4bfd-9875-0f33cb171cc5')
-    def test_5g_screenoff_dtimx4(self):
-        network = self.main_network[hc.BAND_5G]
-        self.dtim_test_func(4, 'OFF', network)
-
-    @test_tracker_info(uuid='75644df4-2cc8-4bbd-8985-0656a4f9d056')
-    def test_5g_screenoff_dtimx5(self):
-        network = self.main_network[hc.BAND_5G]
-        self.dtim_test_func(5, 'OFF', network)
-
-    @test_tracker_info(uuid='327af44d-d9e7-49e0-9bda-accad6241dc7')
-    def test_5g_screenon_dtimx1(self):
-        """With screen on, modulated dtim isn't wokring, always DTIMx1.
-        So not running through all DTIM cases
-
-        """
-        network = self.main_network[hc.BAND_5G]
-        self.dtim_test_func(1, 'ON', network)
-
-    @test_tracker_info(uuid='8b32585f-2517-426b-a2c9-8087093cf991')
-    def test_5g_screenon_dtimx4(self):
-        """Run only extra DTIMx4 for screen on to compare with DTIMx1.
-        They should be the same if everything is correct.
-
-        """
-        network = self.main_network[hc.BAND_5G]
-        self.dtim_test_func(4, 'ON', network)
diff --git a/acts/tests/google/power/wifi/PowermulticastTest.py b/acts/tests/google/power/wifi/PowermulticastTest.py
deleted file mode 100644
index 52dea86..0000000
--- a/acts/tests/google/power/wifi/PowermulticastTest.py
+++ /dev/null
@@ -1,451 +0,0 @@
-#!/usr/bin/env python3.4
-#
-#   Copyright 2017 - 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 logging
-import os
-import time
-
-from acts import base_test
-from acts import utils
-from acts.controllers.ap_lib import hostapd_constants as hc
-from acts.test_decorators import test_tracker_info
-from acts.test_utils.wifi import wifi_test_utils as wutils
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-from acts.controllers import packet_sender as pkt_utils
-
-RA_SHORT_LIFETIME = 3
-RA_LONG_LIFETIME = 1000
-DNS_LONG_LIFETIME = 300
-DNS_SHORT_LIFETIME = 3
-
-
-class PowermulticastTest(base_test.BaseTestClass):
-    def __init__(self, controllers):
-
-        base_test.BaseTestClass.__init__(self, controllers)
-
-    def setup_class(self):
-
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        self.access_point = self.access_points[0]
-        req_params = ['multicast_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.multicast_params)
-        self.num_atten = self.attenuators[0].instrument.num_atten
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(8.0)
-        self.mon.set_voltage(4.2)
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        self.pkt_sender = self.packet_senders[0]
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-            elif 'attenuator_setting' in file:
-                self.attenuation_file = file
-            elif 'network_config' in file:
-                self.network_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-        self.atten_level = wputils.unpack_custom_file(self.attenuation_file,
-                                                      self.TAG)
-        self.networks = wputils.unpack_custom_file(self.network_file)
-        self.main_network = self.networks['main_network']
-
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters.
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    def teardown_test(self):
-        """Tear down necessary objects after test case is finished.
-
-        Bring down the AP interface, delete the bridge interface, stop the
-        packet sender, and reset the ethernet interface for the packet sender
-        """
-        self.log.info('Tearing down the test case')
-        self.pkt_sender.stop_sending(ignore_status=True)
-        self.access_point.bridge.teardown(self.brconfigs)
-        self.access_point.close()
-        wputils.reset_host_interface(self.pkt_sender.interface)
-        self.mon.usb('on')
-
-    def teardown_class(self):
-        """Clean up the test class after tests finish running
-
-        """
-        self.log.info('Tearing down the test class')
-        self.mon.usb('on')
-        self.pkt_sender.stop_sending(ignore_status=True)
-        self.access_point.close()
-
-    def set_connection(self, screen_status, network):
-        """Setup connection between AP and client.
-
-        Setup connection between AP and phone, change DTIMx1 and get information
-        such as IP addresses to prepare packet construction.
-
-        Args:
-            screen_status: screen on or off
-            network: network selection, 2g/5g
-        """
-        # Change DTIMx1 on the phone to receive all Multicast packets
-        wputils.change_dtim(
-            self.dut, gEnableModulatedDTIM=1, gMaxLIModulatedDTIM=10)
-        self.dut.log.info('DTIM value of the phone is now DTIMx1')
-
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-
-        # Set attenuation and connect to AP
-        for attn in range(self.num_atten):
-            self.attenuators[attn].set_atten(
-                self.atten_level['zero_atten'][attn])
-        self.log.info('Set attenuation level to all zero')
-        iface_eth = self.pkt_sender.interface
-        self.brconfigs = wputils.ap_setup(self.access_point, network)
-        wutils.wifi_connect(self.dut, network)
-
-        # Wait for DHCP with timeout of 60 seconds
-        wputils.wait_for_dhcp(iface_eth)
-
-        # Set the desired screen status
-        if screen_status == 'OFF':
-            self.dut.droid.goToSleepNow()
-            self.dut.log.info('Screen is OFF')
-        time.sleep(5)
-
-    def sendPacketAndMeasure(self, packet):
-        """Packet injection template function
-
-        Args:
-            packet: packet to be sent/inject
-        """
-        # Start sending packets
-        self.pkt_sender.start_sending(packet, self.interval)
-
-        # Measure current and plot
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-
-        # Compute pass or fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    # Test cases - screen OFF
-    @test_tracker_info(uuid='b5378aaf-7949-48ac-95fb-ee94c85d49c3')
-    def test_screenoff_directed_arp(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='3b5d348d-70bf-483d-8736-13da569473aa')
-    def test_screenoff_misdirected_arp(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.ipv4_dst_fake)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='8e534d3b-5a25-429a-a1bb-8119d7d28b5a')
-    def test_screenoff_directed_ns(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.NsGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='536d716d-f30b-4d20-9976-e2cbc36c3415')
-    def test_screenoff_misdirected_ns(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.NsGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.ipv6_dst_fake)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='5eed3174-8e94-428e-8527-19a9b5a90322')
-    def test_screenoff_ra_short(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(RA_SHORT_LIFETIME)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='67867bae-f1c5-44a4-9bd0-2b832ac8059c')
-    def test_screenoff_ra_long(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(RA_LONG_LIFETIME)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='db19bc94-3513-45c4-b3a5-d6219649d0bb')
-    def test_screenoff_directed_dhcp_offer(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.DhcpOfferGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='a8059869-40ee-4cf3-a957-4b7aed03fcf9')
-    def test_screenoff_misdirected_dhcp_offer(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.DhcpOfferGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.mac_dst_fake, self.ipv4_dst_fake)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='6e663f0a-3eb5-46f6-a79e-311baebd5d2a')
-    def test_screenoff_ra_rnds_short(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(
-            RA_LONG_LIFETIME, enableDNS=True, dns_lifetime=DNS_SHORT_LIFETIME)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='84d2f1ff-bd4f-46c6-9b06-826d9b14909c')
-    def test_screenoff_ra_rnds_long(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(
-            RA_LONG_LIFETIME, enableDNS=True, dns_lifetime=DNS_LONG_LIFETIME)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='4a17e74f-3e7f-4e90-ac9e-884a7c13cede')
-    def test_screenoff_directed_ping6(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Ping6Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='ab249e0d-58ba-4b55-8a81-e1e4fb04780a')
-    def test_screenoff_misdirected_ping6(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Ping6Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.ipv6_dst_fake, pkt_utils.MAC_BROADCAST)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='e37112e6-5c35-4c89-8d15-f5a44e69be0b')
-    def test_screenoff_directed_ping4(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Ping4Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='afd4a011-63a9-46c3-8a75-13f515ba8475')
-    def test_screenoff_misdirected_ping4(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Ping4Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.ipv4_dst_fake, pkt_utils.MAC_BROADCAST)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='03f0e845-fd66-4120-a79d-5eb64d49b6cd')
-    def test_screenoff_mdns6(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Mdns6Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='dcbb0aec-512d-48bd-b743-024697ce511b')
-    def test_screenoff_mdns4(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('OFF', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Mdns4Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    # Test cases: screen ON
-    @test_tracker_info(uuid='b9550149-bf36-4f86-9b4b-6e900756a90e')
-    def test_screenon_directed_arp(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='406dffae-104e-46cb-9ec2-910aac7aca39')
-    def test_screenon_misdirected_arp(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.ArpGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.ipv4_dst_fake)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='be4cb543-c710-4041-a770-819e82a6d164')
-    def test_screenon_directed_ns(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.NsGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='de21d24f-e03e-47a1-8bbb-11953200e870')
-    def test_screenon_misdirected_ns(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.NsGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.ipv6_dst_fake)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='b424a170-5095-4b47-82eb-50f7b7fdf35d')
-    def test_screenon_ra_short(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(RA_SHORT_LIFETIME)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='ab627e59-2ee8-4c0d-970b-eeb1d1cecdc1')
-    def test_screenon_ra_long(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(RA_LONG_LIFETIME)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='ee6514ab-1814-44b9-ba01-63f77ba77c34')
-    def test_screenon_directed_dhcp_offer(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.DhcpOfferGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='eaebfe98-32da-4ebc-bca7-3b7026d99a4f')
-    def test_screenon_misdirected_dhcp_offer(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.DhcpOfferGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.mac_dst_fake, self.ipv4_dst_fake)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='f0e2193f-bf6a-441b-b9c1-bb7b65787cd5')
-    def test_screenon_ra_rnds_short(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(
-            RA_LONG_LIFETIME, enableDNS=True, dns_lifetime=DNS_SHORT_LIFETIME)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='62b99cd7-75bf-45be-b93f-bb037a13b3e2')
-    def test_screenon_ra_rnds_long(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.RaGenerator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(
-            RA_LONG_LIFETIME, enableDNS=True, dns_lifetime=DNS_LONG_LIFETIME)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='4088af4c-a64b-4fc1-848c-688936cc6c12')
-    def test_screenon_directed_ping6(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Ping6Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='3179e327-e6ac-4dae-bb8a-f3940f21094d')
-    def test_screenon_misdirected_ping6(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Ping6Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.ipv6_dst_fake, pkt_utils.MAC_BROADCAST)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='90c70e8a-74fd-4878-89c6-5e15c3ede318')
-    def test_screenon_directed_ping4(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Ping4Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='dcfabbc7-a7e1-4a92-a38d-8ebe7aa2e063')
-    def test_screenon_misdirected_ping4(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Ping4Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate(self.ipv4_dst_fake, pkt_utils.MAC_BROADCAST)
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='117814db-f94d-4239-a7ab-033482b1da52')
-    def test_screenon_mdns6(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Mdns6Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
-
-    @test_tracker_info(uuid='ce6ad7e2-21f3-4e68-9c0d-d0e14e0a7c53')
-    def test_screenon_mdns4(self):
-        network = self.main_network[hc.BAND_5G]
-        self.set_connection('ON', network)
-        self.pkt_gen_config = wputils.create_pkt_config(self)
-        pkt_gen = pkt_utils.Mdns4Generator(**self.pkt_gen_config)
-        packet = pkt_gen.generate()
-        self.sendPacketAndMeasure(packet)
diff --git a/acts/tests/google/power/wifi/PowerroamingTest.py b/acts/tests/google/power/wifi/PowerroamingTest.py
deleted file mode 100644
index 1b71583..0000000
--- a/acts/tests/google/power/wifi/PowerroamingTest.py
+++ /dev/null
@@ -1,304 +0,0 @@
-#!/usr/bin/env python3.4
-#
-#   Copyright 2017 - 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 logging
-import os
-import time
-from acts import base_test
-from acts import utils
-from acts.controllers.ap_lib import hostapd_constants as hc
-from acts.test_decorators import test_tracker_info
-from acts.test_utils.wifi import wifi_constants as wc
-from acts.test_utils.wifi import wifi_test_utils as wutils
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-
-
-class PowerroamingTest(base_test.BaseTestClass):
-    def __init__(self, controllers):
-
-        base_test.BaseTestClass.__init__(self, controllers)
-
-    def setup_class(self):
-
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        self.access_point_main = self.access_points[0]
-        self.access_point_aux = self.access_points[1]
-        req_params = ['roamingtest_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.roamingtest_params)
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(8.0)
-        self.mon.set_voltage(4.2)
-        self.mon_duration_all = self.mon_duration
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        self.num_atten = self.attenuators[0].instrument.num_atten
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-            elif 'attenuator_setting' in file:
-                self.attenuation_file = file
-            elif 'network_config' in file:
-                self.network_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-        self.atten_level = wputils.unpack_custom_file(self.attenuation_file,
-                                                      self.TAG)
-        self.networks = wputils.unpack_custom_file(self.network_file)
-        self.main_network = self.networks['main_network']
-        self.aux_network = self.networks['aux_network']
-
-    def teardown_test(self):
-        """Tear down necessary objects after test case is finished.
-
-        Bring down all AP interfaces
-        """
-        self.log.info('Tearing down the test case')
-        self.mon.usb('on')
-        self.access_point_main.bridge.teardown(self.brconfigs_main)
-        self.access_point_aux.bridge.teardown(self.brconfigs_aux)
-        for ap in self.access_points:
-            ap.close()
-
-    def teardown_class(self):
-
-        self.log.info('Tearing down the test class')
-        self.mon.usb('on')
-
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters.
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    # Test cases
-    @test_tracker_info(uuid='392622d3-0c5c-4767-afa2-abfb2058b0b8')
-    def test_screenoff_roaming(self):
-        """Test roaming power consumption with screen off.
-        Change the attenuation level to trigger roaming between two APs
-
-        """
-        # Setup both APs
-        network_main = self.main_network[hc.BAND_2G]
-        self.brconfigs_main = wputils.ap_setup(self.access_point_main,
-                                               network_main)
-        network_aux = self.aux_network[hc.BAND_2G]
-        self.brconfigs_aux = wputils.ap_setup(self.access_point_aux,
-                                              network_aux)
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        # Set attenuator and add two networks to the phone
-        self.log.info('Set attenuation to connect device to both APs')
-        [
-            self.attenuators[i].set_atten(self.atten_level['zero_atten'][i])
-            for i in range(self.num_atten)
-        ]
-        wutils.wifi_connect(self.dut, network_aux)
-        time.sleep(5)
-        wutils.wifi_connect(self.dut, network_main)
-        self.dut.droid.goToSleepNow()
-        time.sleep(5)
-        # Set attenuator to trigger roaming
-        self.dut.log.info('Trigger roaming now')
-        [
-            self.attenuators[i].set_atten(
-                self.atten_level[self.current_test_name][i])
-            for i in range(self.num_atten)
-        ]
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Path fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    @test_tracker_info(uuid='2fec5208-043a-410a-8fd2-6784d70a3587')
-    def test_screenoff_fastroaming(self):
-
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        # Setup the aux AP
-        network_main = self.main_network[hc.BAND_2G]
-        network_aux = self.aux_network[hc.BAND_2G]
-        # Set the same SSID for the AUX AP for fastroaming purpose
-        network_aux[wc.SSID] = network_main[wc.SSID]
-        self.brconfigs_aux = wputils.ap_setup(self.access_point_aux,
-                                              network_aux)
-        # Set attenuator and add two networks to the phone
-        self.log.info('Set attenuation to connect device to the aux AP')
-        [
-            self.attenuators[i].set_atten(self.atten_level[wc.AP_AUX][i])
-            for i in range(self.num_atten)
-        ]
-        wutils.wifi_connect(self.dut, network_aux)
-        time.sleep(5)
-        # Setup the main AP
-        self.brconfigs_main = wputils.ap_setup(self.access_point_main,
-                                               network_main)
-        # Set attenuator to connect the phone to main AP
-        self.log.info('Set attenuation to connect device to the main AP')
-        [
-            self.attenuators[i].set_atten(self.atten_level[wc.AP_MAIN][i])
-            for i in range(self.num_atten)
-        ]
-        wutils.wifi_connect(self.dut, network_main)
-        time.sleep(5)
-        self.dut.droid.goToSleepNow()
-        # Trigger fastroaming
-        self.dut.log.info('Trigger fastroaming now')
-        [
-            self.attenuators[i].set_atten(self.atten_level[wc.AP_AUX][i])
-            for i in range(self.num_atten)
-        ]
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Path fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    @test_tracker_info(uuid='a0459b7c-74ce-4adb-8e55-c5365bc625eb')
-    def test_screenoff_toggle_between_AP(self):
-
-        # Setup both APs
-        network_main = self.main_network[hc.BAND_2G]
-        self.brconfigs_main = wputils.ap_setup(self.access_point_main,
-                                               network_main)
-        network_aux = self.aux_network[hc.BAND_2G]
-        self.brconfigs_aux = wputils.ap_setup(self.access_point_aux,
-                                              network_aux)
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        self.mon_info['duration'] = self.toggle_interval
-        self.dut.droid.goToSleepNow()
-        time.sleep(5)
-        self.log.info('Set attenuation to connect device to both APs')
-        [
-            self.attenuators[i].set_atten(
-                self.atten_level[self.current_test_name][i])
-            for i in range(self.num_atten)
-        ]
-        # Toggle between two networks
-        begin_time = utils.get_current_epoch_time()
-        for i in range(self.toggle_times):
-            self.dut.log.info('Connecting to %s' % network_main[wc.SSID])
-            self.dut.droid.wifiConnect(network_main)
-            file_path, avg_current = wputils.monsoon_data_collect_save(
-                self.dut, self.mon_info, self.current_test_name)
-            self.dut.log.info('Connecting to %s' % network_aux[wc.SSID])
-            self.dut.droid.wifiConnect(network_aux)
-            file_path, avg_current = wputils.monsoon_data_collect_save(
-                self.dut, self.mon_info, self.current_test_name)
-        [plot, dt] = wputils.monsoon_data_plot(self.mon_info, file_path)
-        avg_current = dt.source.data['y0'][0]
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Path fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    @test_tracker_info(uuid='e5ff95c0-b17e-425c-a903-821ba555a9b9')
-    def test_screenon_toggle_between_AP(self):
-
-        # Setup both APs
-        network_main = self.main_network[hc.BAND_5G]
-        self.brconfigs_main = wputils.ap_setup(self.access_point_main,
-                                               network_main)
-        network_aux = self.aux_network[hc.BAND_5G]
-        self.brconfigs_aux = wputils.ap_setup(self.access_point_aux,
-                                              network_aux)
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        self.mon_info['duration'] = self.toggle_interval
-        self.log.info('Set attenuation to connect device to both APs')
-        [
-            self.attenuators[i].set_atten(
-                self.atten_level[self.current_test_name][i])
-            for i in range(self.num_atten)
-        ]
-        # Toggle between two networks
-        begin_time = utils.get_current_epoch_time()
-        for i in range(self.toggle_times):
-            self.dut.log.info('Connecting to %s' % network_main[wc.SSID])
-            self.dut.droid.wifiConnect(network_main)
-            file_path, avg_current = wputils.monsoon_data_collect_save(
-                self.dut, self.mon_info, self.current_test_name)
-            self.dut.log.info('Connecting to %s' % network_aux[wc.SSID])
-            self.dut.droid.wifiConnect(network_aux)
-            file_path, avg_current = wputils.monsoon_data_collect_save(
-                self.dut, self.mon_info, self.current_test_name)
-        [plot, dt] = wputils.monsoon_data_plot(self.mon_info, file_path)
-        avg_current = dt.source.data['y0'][0]
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Path fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    @test_tracker_info(uuid='a16ae337-326f-4d09-990f-42232c3c0dc4')
-    def test_screenoff_wifi_wedge(self):
-
-        # Setup both APs
-        network_main = self.main_network[hc.BAND_2G]
-        self.brconfigs_main = wputils.ap_setup(self.access_point_main,
-                                               network_main)
-        network_aux = self.aux_network[hc.BAND_2G]
-        self.brconfigs_aux = wputils.ap_setup(self.access_point_aux,
-                                              network_aux)
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        # Set attenuator to connect phone to both networks
-        self.log.info('Set attenuation to connect device to both APs')
-        [
-            self.attenuators[i].set_atten(self.atten_level['zero_atten'][i])
-            for i in range(self.num_atten)
-        ]
-        wutils.wifi_connect(self.dut, network_main)
-        wutils.wifi_connect(self.dut, network_aux)
-        self.log.info('Forget network {}'.format(network_aux[wc.SSID]))
-        wutils.wifi_forget_network(self.dut, network_aux[wc.SSID])
-        self.log.info('Set attenuation to trigger wedge condition')
-        [
-            self.attenuators[i].set_atten(
-                self.atten_level[self.current_test_name][i])
-            for i in range(self.num_atten)
-        ]
-        self.dut.droid.goToSleepNow()
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Path fail check
-        wputils.pass_fail_check(self, avg_current)
diff --git a/acts/tests/google/power/wifi/PowerscanTest.py b/acts/tests/google/power/wifi/PowerscanTest.py
deleted file mode 100644
index 1c26a90..0000000
--- a/acts/tests/google/power/wifi/PowerscanTest.py
+++ /dev/null
@@ -1,314 +0,0 @@
-#!/usr/bin/env python3.4
-#
-#   Copyright 2017 - 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 logging
-import os
-import time
-from acts import base_test
-from acts import utils
-from acts.controllers.ap_lib import hostapd_constants as hc
-from acts.test_decorators import test_tracker_info
-from acts.test_utils.wifi import wifi_test_utils as wutils
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-
-UNLOCK_SCREEN = 'input keyevent 82'
-
-
-class PowerscanTest(base_test.BaseTestClass):
-    def __init__(self, controllers):
-
-        base_test.BaseTestClass.__init__(self, controllers)
-
-    def setup_class(self):
-
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        self.access_point = self.access_points[0]
-        req_params = ['scantest_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.scantest_params)
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(8.0)
-        self.mon.set_voltage(4.2)
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        self.num_atten = self.attenuators[0].instrument.num_atten
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-            elif 'attenuator_setting' in file:
-                self.attenuation_file = file
-            elif 'network_config' in file:
-                self.network_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-        self.atten_level = wputils.unpack_custom_file(self.attenuation_file,
-                                                      self.TAG)
-        self.networks = wputils.unpack_custom_file(self.network_file)
-        self.main_network = self.networks['main_network']
-
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters.
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    def setup_test(self):
-
-        self.SINGLE_SHOT_SCAN = (
-            'am instrument -w -r  -e min_scan_count \"700\"'
-            ' -e WifiScanTest-testWifiSingleShotScan %d'
-            ' -e class com.google.android.platform.powertests.'
-            'WifiScanTest#testWifiSingleShotScan'
-            ' com.google.android.platform.powertests/'
-            'android.test.InstrumentationTestRunner > /dev/null &' %
-            (self.mon_duration + self.mon_offset + 10))
-        self.BACKGROUND_SCAN = (
-            'am instrument -w -r -e min_scan_count \"1\" -e '
-            'WifiScanTest-testWifiBackgroundScan %d -e class '
-            'com.google.android.platform.powertests.WifiScan'
-            'Test#testWifiBackgroundScan com.google.android.'
-            'platform.powertests/android.test.Instrumentation'
-            'TestRunner > /dev/null &' %
-            (self.mon_duration + self.mon_offset + 10))
-        self.WIFI_SCAN = (
-            'am instrument -w -r -e min_scan_count \"1\" -e '
-            'WifiScanTest-testWifiScan %d -e class '
-            'com.google.android.platform.powertests.WifiScanTest#'
-            'testWifiScan com.google.android.platform.powertests/'
-            'android.test.InstrumentationTestRunner > /dev/null &' %
-            (self.mon_duration + self.mon_offset + 10))
-
-    def teardown_test(self):
-        """Tear down necessary objects after test case is finished.
-
-        Bring down the AP interface and connect device back online
-        """
-        self.log.info('Tearing down the test case')
-        self.access_point.bridge.teardown(self.brconfigs)
-        self.access_point.close()
-        self.mon.usb('on')
-
-    def teardown_class(self):
-
-        self.log.info('Tearing down the test class')
-        self.access_point.close()
-        self.mon.usb('on')
-
-    def powrapk_scan_test_func(self, scan_command, band):
-        """Test function for power.apk triggered scans.
-        Args:
-            scan_command: the adb shell command to trigger scans
-
-        """
-        network = self.main_network[band]
-        self.brconfigs = wputils.ap_setup(self.access_point, network)
-        self.log.info('Set attenuation to get high RSSI at {}'.format(band))
-        [
-            self.attenuators[i].set_atten(
-                self.atten_level[self.current_test_name][i])
-            for i in range(self.num_atten)
-        ]
-        self.mon_info['offset'] == 0
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        self.log.info('Wait for {} seconds'.format(self.settle_wait_time))
-        time.sleep(self.settle_wait_time)
-        self.log.info('Running power apk command to trigger scans')
-        self.dut.adb.shell_nb(scan_command)
-        self.dut.droid.goToSleepNow()
-        # Collect power data and plot
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Path fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    # Test cases
-    @test_tracker_info(uuid='e5539b01-e208-43c6-bebf-6f1e73d8d8cb')
-    def test_single_shot_scan_2g_highRSSI(self):
-
-        self.powrapk_scan_test_func(self.SINGLE_SHOT_SCAN, hc.BAND_2G)
-
-    @test_tracker_info(uuid='14c5a762-95bc-40ea-9fd4-27126df7d86c')
-    def test_single_shot_scan_2g_lowRSSI(self):
-
-        self.powrapk_scan_test_func(self.SINGLE_SHOT_SCAN, hc.BAND_2G)
-
-    @test_tracker_info(uuid='a6506600-c567-43b5-9c25-86b505099b97')
-    def test_single_shot_scan_2g_noAP(self):
-
-        self.powrapk_scan_test_func(self.SINGLE_SHOT_SCAN, hc.BAND_2G)
-
-    @test_tracker_info(uuid='1a458248-1159-4c8e-a39f-92fc9e69c4dd')
-    def test_single_shot_scan_5g_highRSSI(self):
-
-        self.powrapk_scan_test_func(self.SINGLE_SHOT_SCAN, hc.BAND_5G)
-
-    @test_tracker_info(uuid='bd4da426-a621-4131-9f89-6e5a77f321d2')
-    def test_single_shot_scan_5g_lowRSSI(self):
-
-        self.powrapk_scan_test_func(self.SINGLE_SHOT_SCAN, hc.BAND_5G)
-
-    @test_tracker_info(uuid='288b3add-8925-4803-81c0-53debf157ffc')
-    def test_single_shot_scan_5g_noAP(self):
-
-        self.powrapk_scan_test_func(self.SINGLE_SHOT_SCAN, hc.BAND_5G)
-
-    @test_tracker_info(uuid='f401c66c-e515-4f51-8ef2-2a03470d8ff2')
-    def test_background_scan(self):
-
-        self.powrapk_scan_test_func(self.BACKGROUND_SCAN, hc.BAND_5G)
-
-    @test_tracker_info(uuid='fe38c1c7-937c-42c0-9381-98356639df8f')
-    def test_wifi_scan_2g(self):
-
-        self.powrapk_scan_test_func(self.WIFI_SCAN, hc.BAND_2G)
-
-    @test_tracker_info(uuid='8eedefd1-3a08-4ac2-ba55-5eb438def3d4')
-    def test_wifi_scan_5g(self):
-
-        self.powrapk_scan_test_func(self.WIFI_SCAN, hc.BAND_5G)
-
-    @test_tracker_info(uuid='ff5ea952-ee31-4968-a190-82935ce7a8cb')
-    def test_scan_wifidisconnected_turnonscreen(self):
-
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        self.dut.droid.goToSleepNow()
-        self.log.info('Screen is OFF')
-        time.sleep(5)
-        self.dut.droid.wakeUpNow()
-        self.log.info('Now turn on screen to trigger scans')
-        self.dut.adb.shell(UNLOCK_SCREEN)
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        wputils.pass_fail_check(self, avg_current)
-
-    @test_tracker_info(uuid='9a836e5b-8128-4dd2-8e96-e79177810bdd')
-    def test_scan_wificonnected_turnonscreen(self):
-
-        network = self.main_network[hc.BAND_2G]
-        self.brconfigs = wputils.ap_setup(self.access_point, network)
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        # Set attenuators to connect main AP
-        [
-            self.attenuators[i].set_atten(
-                self.atten_level[self.current_test_name][i])
-            for i in range(self.num_atten)
-        ]
-        wutils.wifi_connect(self.dut, network)
-        time.sleep(10)
-        self.dut.droid.goToSleepNow()
-        self.log.info('Screen is OFF')
-        time.sleep(5)
-        self.dut.droid.wakeUpNow()
-        self.log.info('Now turn on screen to trigger scans')
-        self.dut.adb.shell(UNLOCK_SCREEN)
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Path fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    @test_tracker_info(uuid='51e3c4f1-742b-45af-afd5-ae3552a03272')
-    def test_scan_screenoff_below_rssi_threshold(self):
-
-        network = self.main_network[hc.BAND_2G]
-        self.brconfigs = wputils.ap_setup(self.access_point, network)
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        # Set attenuator and add main network to the phone
-        self.log.info('Set attenuation so device connection has medium RSSI')
-        [
-            self.attenuators[i].set_atten(self.atten_level['zero_atten'][i])
-            for i in range(self.num_atten)
-        ]
-        wutils.wifi_connect(self.dut, network)
-        self.dut.droid.goToSleepNow()
-        time.sleep(20)
-        # Set attenuator to make RSSI below threshold
-        self.log.info('Set attenuation to drop RSSI below threhold')
-        [
-            self.attenuators[i].set_atten(
-                self.atten_level[self.current_test_name][i])
-            for i in range(self.num_atten)
-        ]
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Path fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    @test_tracker_info(uuid='a16ae337-326f-4d09-990f-42232c3c0dc4')
-    def test_scan_screenoff_lost_wificonnection(self):
-
-        network = self.main_network[hc.BAND_5G]
-        self.brconfigs = wputils.ap_setup(self.access_point, network)
-        # Initialize the dut to rock-bottom state
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-        # Set attenuator and add main network to the phone
-        self.log.info('Set attenuation so device connection has medium RSSI')
-        [
-            self.attenuators[i].set_atten(self.atten_level['zero_atten'][i])
-            for i in range(self.num_atten)
-        ]
-        wutils.wifi_connect(self.dut, network)
-        self.dut.droid.goToSleepNow()
-        time.sleep(5)
-        # Set attenuator to make RSSI below threshold
-        self.log.info('Set attenuation so device loses connection')
-        [
-            self.attenuators[i].set_atten(
-                self.atten_level[self.current_test_name][i])
-            for i in range(self.num_atten)
-        ]
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-        wputils.monsoon_data_plot(self.mon_info, file_path)
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Path fail check
-        wputils.pass_fail_check(self, avg_current)
diff --git a/acts/tests/google/power/wifi/PowertrafficTest.py b/acts/tests/google/power/wifi/PowertrafficTest.py
deleted file mode 100644
index 83f99dd..0000000
--- a/acts/tests/google/power/wifi/PowertrafficTest.py
+++ /dev/null
@@ -1,409 +0,0 @@
-#!/usr/bin/env python3.4
-#
-#   Copyright 2017 - 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 logging
-import math
-import os
-import time
-from acts import base_test
-from acts import utils
-from acts.test_decorators import test_tracker_info
-from acts.test_utils.wifi import wifi_test_utils as wutils
-from acts.test_utils.wifi import wifi_power_test_utils as wputils
-from acts.test_utils.wifi.WifiBaseTest import WifiBaseTest
-import acts.controllers.iperf_server as ipf
-
-TEMP_FILE = '/sdcard/Download/tmp.log'
-
-
-class PowertrafficTest(base_test.BaseTestClass):
-    def __init__(self, controllers):
-
-        WifiBaseTest.__init__(self, controllers)
-
-    def setup_class(self):
-
-        self.log = logging.getLogger()
-        self.dut = self.android_devices[0]
-        req_params = ['traffictest_params', 'custom_files']
-        self.unpack_userparams(req_params)
-        self.unpack_testparams(self.traffictest_params)
-        self.num_atten = self.attenuators[0].instrument.num_atten
-        self.mon_data_path = os.path.join(self.log_path, 'Monsoon')
-        self.mon_duration = self.iperf_duration - 10
-        self.mon = self.monsoons[0]
-        self.mon.set_max_current(8.0)
-        self.mon.set_voltage(4.2)
-        self.mon.attach_device(self.dut)
-        self.mon_info = wputils.create_monsoon_info(self)
-        self.iperf_server = self.iperf_servers[0]
-        self.access_point = self.access_points[0]
-        self.pkt_sender = self.packet_senders[0]
-        for file in self.custom_files:
-            if 'pass_fail_threshold' in file:
-                self.threshold_file = file
-            elif 'attenuator_setting' in file:
-                self.attenuation_file = file
-            elif 'network_config' in file:
-                self.network_file = file
-        self.threshold = wputils.unpack_custom_file(self.threshold_file,
-                                                    self.TAG)
-        self.atten_level = wputils.unpack_custom_file(self.attenuation_file,
-                                                      self.TAG)
-        self.networks = wputils.unpack_custom_file(self.network_file)
-        self.main_network = self.networks['main_network']
-
-    def teardown_test(self):
-        """Tear down necessary objects after test case is finished.
-
-        Bring down the AP interface, delete the bridge interface, stop IPERF
-        server and reset the ethernet interface for iperf traffic
-        """
-        self.log.info('Tearing down the test case')
-        self.iperf_server.stop()
-        self.access_point.bridge.teardown(self.brconfigs)
-        self.access_point.close()
-        wputils.reset_host_interface(self.pkt_sender.interface)
-        self.mon.usb('on')
-
-    def teardown_class(self):
-        """Clean up the test class after tests finish running
-
-        """
-        self.log.info('Tearing down the test class')
-        self.mon.usb('on')
-        self.access_point.close()
-
-    def unpack_testparams(self, bulk_params):
-        """Unpack all the test specific parameters.
-
-        Args:
-            bulk_params: dict with all test specific params in the config file
-        """
-        for key in bulk_params.keys():
-            setattr(self, key, bulk_params[key])
-
-    def iperf_power_test_func(self):
-        """Test function for iperf power measurement at different RSSI level.
-
-        Args:
-            screen_status: screen ON or OFF
-            band: desired band for AP to operate on
-        """
-        # Decode test parameters for the current test
-        test_params = self.current_test_name.split('_')
-        screen_status = test_params[2][6:]
-        band = test_params[3]
-        traffic_direction = test_params[4]
-        traffic_type = test_params[5]
-        signal_level = test_params[6][:-4]
-        oper_mode = test_params[7]
-        bandwidth = int(test_params[8])
-
-        # Set device to rockbottom first
-        wputils.dut_rockbottom(self.dut)
-        wutils.wifi_toggle_state(self.dut, True)
-
-        # Set up the AP
-        network = self.main_network[band]
-        self.brconfigs = wputils.ap_setup(self.access_point, network,
-                                          bandwidth)
-
-        # Wait for DHCP on the ethernet port and get IP as Iperf server address
-        # Time out in 60 seconds if not getting DHCP address
-        iface_eth = self.pkt_sender.interface
-        self.iperf_server_address = wputils.wait_for_dhcp(iface_eth)
-
-        # Set attenuator to desired level
-        self.log.info('Set attenuation to desired RSSI level')
-        atten_setting = band + '_' + signal_level
-        for i in range(self.num_atten):
-            attenuation = self.atten_level[atten_setting][i]
-            self.attenuators[i].set_atten(attenuation)
-
-        # Connect the phone to the AP
-        wutils.wifi_connect(self.dut, network)
-        time.sleep(5)
-        if screen_status == 'off':
-            self.dut.droid.goToSleepNow()
-        RSSI = wputils.get_wifi_rssi(self.dut)
-
-        # Construct the iperf command based on the test params
-        iperf_args = '-i 1 -t {} -p {} -J'.format(self.iperf_duration,
-                                                  self.iperf_server.port)
-        if traffic_type == "UDP":
-            iperf_args = iperf_args + "-u -b 2g"
-        if traffic_direction == "DL":
-            iperf_args = iperf_args + ' -R'
-            use_client_output = True
-        else:
-            use_client_output = False
-        # Parse the client side data to a file saved on the phone
-        iperf_args = iperf_args + ' > %s' % TEMP_FILE
-
-        # Run IPERF
-        self.iperf_server.start()
-        wputils.run_iperf_client_nonblocking(
-            self.dut, self.iperf_server_address, iperf_args)
-
-        # Collect power data and plot
-        begin_time = utils.get_current_epoch_time()
-        file_path, avg_current = wputils.monsoon_data_collect_save(
-            self.dut, self.mon_info, self.current_test_name)
-
-        # Get IPERF results
-        RESULTS_DESTINATION = os.path.join(self.iperf_server.log_path,
-                                           "iperf_client_output_{}.log".format(
-                                               self.current_test_name))
-        PULL_FILE = '{} {}'.format(TEMP_FILE, RESULTS_DESTINATION)
-        self.dut.adb.pull(PULL_FILE)
-        # Calculate the average throughput
-        if use_client_output:
-            iperf_file = RESULTS_DESTINATION
-        else:
-            iperf_file = self.iperf_server.log_files[-1]
-        try:
-            iperf_result = ipf.IPerfResult(iperf_file)
-            throughput = (math.fsum(iperf_result.instantaneous_rates[:-1]) /
-                          len(iperf_result.instantaneous_rates[:-1])) * 8
-            self.log.info("The average throughput is {}".format(throughput))
-        except:
-            self.log.warning(
-                "ValueError: Cannot get iperf result. Setting to 0")
-            throughput = 0
-
-        # Monsoon Power data plot with IPerf throughput information
-        tag = '_RSSI_{0:d}dBm_Throughput_{1:.2f}Mbps'.format(RSSI, throughput)
-        wputils.monsoon_data_plot(self.mon_info, file_path, tag)
-
-        # Take Bugreport
-        if bool(self.bug_report) == True:
-            self.dut.take_bug_report(self.test_name, begin_time)
-        # Pass and fail check
-        wputils.pass_fail_check(self, avg_current)
-
-    # Screen off TCP test cases
-    @test_tracker_info(uuid='93f79f74-88d9-4781-bff0-8899bed1c336')
-    def test_traffic_screenoff_2g_DL_TCP_highRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='147eff45-97d7-47c0-b306-f84d9adecd9b')
-    def test_traffic_screenoff_2g_DL_TCP_mediumRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='5982268b-57e4-40bf-848e-fee80fabf9d7')
-    def test_traffic_screenoff_2g_DL_TCP_lowRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='c71a8c77-d355-4a82-b9f1-7cc8b888abd8')
-    def test_traffic_screenoff_5g_DL_TCP_highRSSI_VHT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='307945a6-32b7-42d0-a26c-d439f1599963')
-    def test_traffic_screenoff_5g_DL_TCP_mediumRSSI_VHT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='e9a900a1-e263-45ad-bdf3-9c463f761d3c')
-    def test_traffic_screenoff_5g_DL_TCP_lowRSSI_VHT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='1d1d9a06-98e1-486e-a1db-2102708161ec')
-    def test_traffic_screenoff_5g_DL_TCP_highRSSI_VHT_40(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='feeaad15-6893-4d49-aaf6-bf9802780f5d')
-    def test_traffic_screenoff_5g_DL_TCP_mediumRSSI_VHT_40(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='f378679a-1c20-43a1-bff6-a6a5482a8e3d')
-    def test_traffic_screenoff_5g_DL_TCP_lowRSSI_VHT_40(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='6a05f133-49e5-4436-ba84-0746f04021ef')
-    def test_traffic_screenoff_5g_DL_TCP_highRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='750bf1c3-2099-4b89-97dd-18f8e72df462')
-    def test_traffic_screenoff_5g_DL_TCP_mediumRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='1ea458af-1ae0-40ee-853d-ac57b51d3eda')
-    def test_traffic_screenoff_5g_DL_TCP_lowRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='43d9b146-3547-4a27-9d79-c9341c32ccda')
-    def test_traffic_screenoff_2g_UL_TCP_highRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='f00a868b-c8b1-4b36-8136-b39b5c2396a7')
-    def test_traffic_screenoff_2g_UL_TCP_mediumRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='cd0c37ac-23fe-4dd1-9130-ccb2dfa71020')
-    def test_traffic_screenoff_2g_UL_TCP_lowRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='f9173d39-b46d-4d80-a5a5-7966f5eed9de')
-    def test_traffic_screenoff_5g_UL_TCP_highRSSI_VHT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='cf77e1dc-30bc-4df9-88be-408f1fddc24f')
-    def test_traffic_screenoff_5g_UL_TCP_mediumRSSI_VHT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='48f91745-22dc-47c9-ace6-c2719df651d6')
-    def test_traffic_screenoff_5g_UL_TCP_lowRSSI_VHT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='18456aa7-62f0-4560-a7dc-4d7e01f6aca5')
-    def test_traffic_screenoff_5g_UL_TCP_highRSSI_VHT_40(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='8ad237d7-f5e1-45e1-a4a2-a010628a4db9')
-    def test_traffic_screenoff_5g_UL_TCP_mediumRSSI_VHT_40(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='3e29173f-b950-4a41-a7f6-6cc0731bf477')
-    def test_traffic_screenoff_5g_UL_TCP_lowRSSI_VHT_40(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='3d4cdb21-a1b0-4011-9956-ca0b7a9f3bec')
-    def test_traffic_screenoff_5g_UL_TCP_highRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='8427d3f0-9418-4b5c-aea9-7509e5959ce6')
-    def test_traffic_screenoff_5g_UL_TCP_mediumRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='5ac91734-0323-464b-b04a-c7d3d7ff8cdf')
-    def test_traffic_screenoff_5g_UL_TCP_lowRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    # Screen off UDP tests - only check 5g VHT 80
-    @test_tracker_info(uuid='1ab4a4e2-bce2-4ff8-be9d-f8ed2bb617cd')
-    def test_traffic_screenoff_5g_DL_UDP_highRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='a2c66d63-e93f-42aa-a021-0c6cdfdc87b8')
-    def test_traffic_screenoff_5g_DL_UDP_mediumRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='68e6f92a-ae15-4e76-81e7-a7b491e181fe')
-    def test_traffic_screenoff_5g_DL_UDP_lowRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='258500f4-f177-43df-82a7-a64d66e90720')
-    def test_traffic_screenoff_5g_UL_UDP_highRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='3d2d3d45-575d-4080-86f9-b32a96963032')
-    def test_traffic_screenoff_5g_UL_UDP_mediumRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='a17c7d0b-58ca-47b5-9f32-0b7a3d7d3d9d')
-    def test_traffic_screenoff_5g_UL_UDP_lowRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    # Screen on point check
-    @test_tracker_info(uuid='c1c71639-4463-4999-8f5d-7d9153402c79')
-    def test_traffic_screenon_2g_DL_TCP_highRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='40daebc4-45a2-4299-b724-e8cb917b86e8')
-    def test_traffic_screenon_5g_DL_TCP_highRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='2e286f36-1a47-4895-a0e8-a161d6a9fd9f')
-    def test_traffic_screenon_2g_UL_TCP_highRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='9f6b52cb-b48a-4382-8061-3d3a511a261a')
-    def test_traffic_screenon_5g_UL_TCP_highRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='59d79274-15cf-446b-a567-655c07f8a778')
-    def test_traffic_screenon_2g_DL_UDP_highRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='02891671-48cc-4186-9a95-3e02671477d0')
-    def test_traffic_screenon_5g_DL_UDP_highRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='02821540-7b08-4e4f-a1f1-b455fd4cec6e')
-    def test_traffic_screenon_2g_UL_UDP_highRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='59ea06ac-3ac8-4ecc-abb1-bcde34f47358')
-    def test_traffic_screenon_2g_UL_UDP_mediumRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='0cbbd849-7b59-4143-95e7-92cf1fd955dc')
-    def test_traffic_screenon_2g_UL_UDP_lowRSSI_HT_20(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='d84f11d8-41a9-4ce8-a351-ebb0379d56c1')
-    def test_traffic_screenon_5g_UL_UDP_highRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='01b6087c-b39a-441d-90e9-da659aa0db7f')
-    def test_traffic_screenon_5g_UL_UDP_mediumRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
-
-    @test_tracker_info(uuid='7e16dcaa-128f-4874-ab52-2f43e25e6da8')
-    def test_traffic_screenon_5g_UL_UDP_lowRSSI_VHT_80(self):
-
-        self.iperf_power_test_func()
diff --git a/acts/tests/google/wifi/WifiStaApConcurrencyTest.py b/acts/tests/google/wifi/WifiStaApConcurrencyTest.py
index ff55819..6f0beba 100755
--- a/acts/tests/google/wifi/WifiStaApConcurrencyTest.py
+++ b/acts/tests/google/wifi/WifiStaApConcurrencyTest.py
@@ -53,10 +53,6 @@
         self.dut_client = self.android_devices[1]
         wutils.wifi_test_device_init(self.dut)
         wutils.wifi_test_device_init(self.dut_client)
-        if self.dut.model not in self.dbs_supported_models:
-            asserts.skip(
-                ("Device %s does not support dual interfaces.")
-                % self.dut.model)
         # Do a simple version of init - mainly just sync the time and enable
         # verbose logging.  This test will fail if the DUT has a sim and cell
         # data is disabled.  We would also like to test with phones in less
@@ -76,11 +72,16 @@
         asserts.assert_equal(self.dut_client.droid.wifiGetVerboseLoggingLevel(), 1,
             "Failed to enable WiFi verbose logging on the client dut.")
 
-        req_params = ["AccessPoint"]
+        req_params = ["AccessPoint", "dbs_supported_models"]
         opt_param = ["iperf_server_address"]
         self.unpack_userparams(
             req_param_names=req_params, opt_param_names=opt_param)
 
+        if self.dut.model not in self.dbs_supported_models:
+            asserts.skip(
+                ("Device %s does not support dual interfaces.")
+                % self.dut.model)
+
         if "iperf_server_address" in self.user_params:
             self.iperf_server = self.iperf_servers[0]
         if hasattr(self, 'iperf_server'):
diff --git a/acts/tests/google/wifi/rtt/functional/AwareDiscoveryWithRangingTest.py b/acts/tests/google/wifi/rtt/functional/AwareDiscoveryWithRangingTest.py
index 8c073b9..b2120f9 100644
--- a/acts/tests/google/wifi/rtt/functional/AwareDiscoveryWithRangingTest.py
+++ b/acts/tests/google/wifi/rtt/functional/AwareDiscoveryWithRangingTest.py
@@ -23,6 +23,8 @@
 from acts.test_utils.wifi.aware import aware_const as aconsts
 from acts.test_utils.wifi.aware import aware_test_utils as autils
 from acts.test_utils.wifi.aware.AwareBaseTest import AwareBaseTest
+from acts.test_utils.wifi.rtt import rtt_const as rconsts
+from acts.test_utils.wifi.rtt import rtt_test_utils as rutils
 from acts.test_utils.wifi.rtt.RttBaseTest import RttBaseTest
 
 
@@ -1459,4 +1461,106 @@
     event = autils.wait_for_event(dut1, autils.decorate_event(
         aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, ff_s_id))
     asserts.assert_true(aconsts.SESSION_CB_KEY_DISTANCE_MM in event["data"],
-                        "Discovery with ranging for FF expected!")
\ No newline at end of file
+                        "Discovery with ranging for FF expected!")
+
+
+  def test_discovery_direct_concurrency(self):
+    """Verify the behavior of Wi-Fi Aware Ranging used as part of discovery and
+    as direct ranging to a peer device.
+
+    Process:
+    - Start YYY service with ranging in-range
+    - Start XXX service with ranging out-of-range
+    - Start performing direct Ranging
+    - While above going on update XXX to be in-range
+    - Keep performing direct Ranging in context of YYY
+    - Stop direct Ranging and look for XXX to discover
+    """
+    dut1 = self.android_devices[0]
+    dut1.pretty_name = "DUT1"
+    dut2 = self.android_devices[1]
+    dut2.pretty_name = "DUT2"
+
+    # DUTs: attach and wait for confirmation
+    dut1_id = dut1.droid.wifiAwareAttach(False)
+    autils.wait_for_event(dut1, aconsts.EVENT_CB_ON_ATTACHED)
+    time.sleep(self.device_startup_offset)
+    dut2_id = dut2.droid.wifiAwareAttach(True)
+    event = autils.wait_for_event(dut2, aconsts.EVENT_CB_ON_IDENTITY_CHANGED)
+    dut2_mac = event['data']['mac']
+
+    # DUT1: publishers bring-up
+    xxx_p_id = dut1.droid.wifiAwarePublish(dut1_id, autils.add_ranging_to_pub(
+      autils.create_discovery_config("XXX", aconsts.PUBLISH_TYPE_UNSOLICITED),
+      enable_ranging=True), True)
+    autils.wait_for_event(dut1, autils.decorate_event(
+      aconsts.SESSION_CB_ON_PUBLISH_STARTED, xxx_p_id))
+    yyy_p_id = dut1.droid.wifiAwarePublish(dut1_id, autils.add_ranging_to_pub(
+        autils.create_discovery_config("YYY", aconsts.PUBLISH_TYPE_UNSOLICITED),
+        enable_ranging=True), True)
+    autils.wait_for_event(dut1, autils.decorate_event(
+        aconsts.SESSION_CB_ON_PUBLISH_STARTED, yyy_p_id))
+
+    # DUT2: subscribers bring-up
+    xxx_s_id = dut2.droid.wifiAwareSubscribe(dut2_id, autils.add_ranging_to_sub(
+      autils.create_discovery_config("XXX", aconsts.SUBSCRIBE_TYPE_PASSIVE),
+      min_distance_mm=1000000, max_distance_mm=1000001), True)
+    autils.wait_for_event(dut2, autils.decorate_event(
+      aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED, xxx_s_id))
+    yyy_s_id = dut2.droid.wifiAwareSubscribe(dut2_id, autils.add_ranging_to_sub(
+        autils.create_discovery_config("YYY", aconsts.SUBSCRIBE_TYPE_PASSIVE),
+        min_distance_mm=None, max_distance_mm=1000000), True)
+    autils.wait_for_event(dut2, autils.decorate_event(
+        aconsts.SESSION_CB_ON_SUBSCRIBE_STARTED, yyy_s_id))
+
+    # Service discovery: YYY (with range info), but no XXX
+    event = autils.wait_for_event(dut2, autils.decorate_event(
+      aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, yyy_s_id))
+    asserts.assert_true(aconsts.SESSION_CB_KEY_DISTANCE_MM in event["data"],
+                        "Discovery with ranging for YYY expected!")
+    yyy_peer_id_on_sub = event['data'][aconsts.SESSION_CB_KEY_PEER_ID]
+
+    autils.fail_on_event(dut2, autils.decorate_event(
+      aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, xxx_s_id))
+
+    # Direct ranging
+    results21 = []
+    for iter in range(10):
+      id = dut2.droid.wifiRttStartRangingToAwarePeerId(yyy_peer_id_on_sub)
+      event = autils.wait_for_event(dut2, rutils.decorate_event(
+        rconsts.EVENT_CB_RANGING_ON_RESULT, id))
+      results21.append(event["data"][rconsts.EVENT_CB_RANGING_KEY_RESULTS][0])
+
+    time.sleep(5) # while switching roles
+
+    results12 = []
+    for iter in range(10):
+      id = dut1.droid.wifiRttStartRangingToAwarePeerMac(dut2_mac)
+      event = autils.wait_for_event(dut1, rutils.decorate_event(
+        rconsts.EVENT_CB_RANGING_ON_RESULT, id))
+      results12.append(event["data"][rconsts.EVENT_CB_RANGING_KEY_RESULTS][0])
+
+    stats = [rutils.extract_stats(results12, 0, 0, 0),
+             rutils.extract_stats(results21, 0, 0, 0)]
+
+    # Update XXX to be within range
+    dut2.droid.wifiAwareUpdateSubscribe(xxx_s_id, autils.add_ranging_to_sub(
+      autils.create_discovery_config("XXX", aconsts.SUBSCRIBE_TYPE_PASSIVE),
+      min_distance_mm=None, max_distance_mm=1000000))
+    autils.wait_for_event(dut2, autils.decorate_event(
+      aconsts.SESSION_CB_ON_SESSION_CONFIG_UPDATED, xxx_s_id))
+
+    # Expect discovery on XXX - wait until discovery with ranging:
+    # - 0 or more: without ranging info (due to concurrency limitations)
+    # - 1 or more: with ranging (once concurrency limitation relieved)
+    num_events = 0
+    while True:
+      event = autils.wait_for_event(dut2, autils.decorate_event(
+          aconsts.SESSION_CB_ON_SERVICE_DISCOVERED, xxx_s_id))
+      if aconsts.SESSION_CB_KEY_DISTANCE_MM in event["data"]:
+        break
+      num_events = num_events + 1
+      asserts.assert_true(num_events < 10, # arbitrary safety valve
+                          "Way too many discovery events without ranging!")
+
+    asserts.explicit_pass("Discovery/Direct RTT Concurrency Pass", extras=stats)
\ No newline at end of file