Chromium Code Reviews| Index: build/android/pylib/device/wifi_manager.py |
| diff --git a/build/android/pylib/device/wifi_manager.py b/build/android/pylib/device/wifi_manager.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4ab4e64db2ebe5db805eff3de7544bb1e0f19b3b |
| --- /dev/null |
| +++ b/build/android/pylib/device/wifi_manager.py |
| @@ -0,0 +1,210 @@ |
| +# Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
| + |
| +"""Manages WiFi connection""" |
| + |
| +import logging |
| +import os |
| +import sys |
| +import time |
| + |
| +sys.path.append(os.path.join(sys.path[0], '..', '..', 'build','android')) |
| +from pylib import constants |
| +from pylib.device import device_utils |
| +from pylib.device import device_errors |
| +from pylib.utils import logging_utils |
| +from pylib.utils import timeout_retry |
| + |
| +_ACTIVITY_RESULT_OK = -1 |
| +_STR_TO_BOOL = {'true': True, 'false': False} |
| + |
| + |
| +class WiFiManager(object): |
| + """A wrapper around WifiUtil.apk to manage wifi settings. |
| + |
| + WifiUtil is available at build/android/apks/WifiUtil.apk, for more |
|
navabi
2015/06/18 01:04:57
changed this.
|
| + information, see the README in build/android/apks/ |
| + """ |
| + |
| + def __init__(self, device): |
| + """ |
| + Args: |
| + device: A DeviceUtils object to work with. |
| + """ |
| + self._device = device |
| + self._apk_installed = False |
| + |
| + def IsWifiEnabled(self): |
| + """Checks whether or not wifi is enabled on the device.""" |
| + return self._WifiUtilMethod('isWifiEnabled') |
| + |
| + def IsInternetReachable(self, destination='www.google.com', count=2, |
| + timeout=5): |
| + """Checks whether or not internet is reachable from the device. |
| + |
| + Args: |
| + destination: A string with a destination to check for connectivity. |
| + count: Number of ping packets to send. |
| + timeout: Number of seconds to wait for packets to return. |
| + |
| + Return: |
| + True if pings to the destination succeeded, False otherwise. |
| + """ |
| + try: |
| + self._device.RunShellCommand( |
| + ['ping', '-w', str(timeout), '-c', str(count), destination], |
| + check_return=True) |
| + return True |
| + except device_errors.AdbShellCommandFailedError: |
| + return False |
| + |
| + def EnableWifi(self): |
| + """Enables wifi on the device.""" |
| + if not self._WifiUtilMethod('enableWifi'): |
| + raise device_errors.CommandFailedError( |
| + 'Failed to enable wifi on the device') |
| + |
| + def DisableWifi(self): |
| + """Disables wifi on the device.""" |
| + if not self._WifiUtilMethod('disableWifi'): |
| + raise device_errors.CommandFailedError( |
| + 'Failed to disable wifi on the device') |
| + |
| + def AddOpenNetwork(self, ssid): |
| + """Adds an open wifi network configuarion. |
| + |
| + Args: |
| + ssid: A string with the SSID of a wifi network. |
| + |
| + Return: |
| + The network ID of the new network configuarion as an integer. |
| + """ |
| + return self._WifiUtilMethod('addOpenNetwork', {'ssid': ssid}, type_fn=int) |
| + |
| + def AddSecureNetwork(self, ssid, password_file): |
| + """Adds an wpa/psk wifi network configuarion. |
| + |
| + Args: |
| + ssid: A string with the SSID of a wifi network. |
| + password_file: A file containing the password for the wifi |
| + |
| + Return: |
| + The network ID of the new network configuarion as an integer. |
| + """ |
| + with open(password_file) as f: |
| + password = f.read().rstrip() |
| + with logging_utils.SuppressLogging(): |
| + result = self._WifiUtilMethod('addWpaPskNetwork', |
| + {'ssid': ssid, 'psk': password}, type_fn=int) |
| + return result |
| + |
| + def AssociateNetwork(self, net_id): |
| + """Associates (connects) to a previously configured network. |
| + |
| + Args: |
| + net_id: An integer with the network ID to associate with. |
| + """ |
| + if not self._WifiUtilMethod('associateNetwork', {'id': net_id}): |
| + raise device_errors.CommandFailedError( |
| + 'Failed to connect to network id %d.' % net_id) |
| + |
| + def SaveConfiguration(self): |
| + """Persists the current configured networks. |
| + |
| + Note: It is possible for this method to change the network IDs of existing |
| + networks. |
| + """ |
| + if not self._WifiUtilMethod('saveConfiguration'): |
| + raise device_errors.CommandFailedError( |
| + 'Failed to save the current network configuration.') |
| + |
| + def ConnectToGoogleGuest(self): |
| + self.ConnectToWifi('GoogleGuest') |
| + |
| + def ConnectToWifi(self, ssid, password_file=None): |
| + """Enables wifi on the device and connects to specified ssid.""" |
| + def wifi_enabled(): |
| + return self.IsWifiEnabled() |
| + |
| + def internet_reachable(): |
| + return self.IsInternetReachable() |
| + |
| + logging.info('Enabling wifi') |
| + self.EnableWifi() |
| + if not timeout_retry.WaitFor(wifi_enabled, max_tries=6): |
| + raise device_errors.CommandFailedError( |
| + 'Timed out waiting for wifi to be enabled') |
| + |
| + logging.info('Adding %s', ssid) |
| + if password_file: |
| + net_id = self.AddSecureNetwork(ssid, password_file) |
| + else: |
| + net_id = self.AddOpenNetwork(ssid) |
| + logging.info('Connecting to %s', ssid) |
| + self.AssociateNetwork(net_id) |
| + logging.info('Saving wifi configuration') |
| + self.SaveConfiguration() |
| + |
| + if not timeout_retry.WaitFor(internet_reachable, max_tries=6): |
| + raise device_errors.CommandFailedError( |
| + 'Timed out waiting for Internet connectivity: www.google.com is not' |
| + ' responding.') |
| + |
| + def _WifiUtilMethod(self, method, args=None, type_fn=None): |
|
navabi
2015/06/18 01:04:57
and I changed the name of the type_fn argument. It
perezju
2015/06/18 09:53:33
nit: maybe call it "return_as"? looks a bit nicer
|
| + """Run a WifiUtil.apk instrumentation and return its result. |
| + |
| + Maps each invocation to an instrumentation command of the form: |
| + |
| + am instrument -e method <METHOD> -e <KEY1> <VAL1> ... \ |
| + -w com.android.tradefed.utils.wifi/.WifiUtil |
| + |
| + Args: |
| + method: A string with the name of the WifiUtil.apk method to invoke. |
| + args: A dictionary with extra arguments for the method, values will be |
| + implicitly casted to strings. |
| + type_fn: A function called to interpret the result of the method. The |
| + default expects and returns a boolean value. |
| + |
| + Return: |
| + The result obtained from INSTRUMENTATION_RESULT: result=[value], as |
| + interpreted by the type_fn function. |
| + |
| + Raises: |
| + AssertionError if the instrumentation call is not successful, or the |
| + instrumentation result is missing. |
| + """ |
| + if not self._apk_installed: |
| + self._InstallWifiUtilApk() |
| + |
| + extras = {'method': method} |
| + if args is not None: |
| + extras.update((k, str(v)) for k, v in args.iteritems()) |
| + if type_fn is None: |
| + type_fn = lambda r: _STR_TO_BOOL[r] |
| + |
| + output = self._device.StartInstrumentation( |
| + 'com.android.tradefed.utils.wifi/.WifiUtil', |
| + extras=extras) |
| + results = {} |
| + code = None |
| + for line in output: |
| + section, content = line.split(': ', 1) |
| + if section == 'INSTRUMENTATION_RESULT': |
| + key, value = content.split('=', 1) |
| + results[key] = value |
| + elif section == 'INSTRUMENTATION_CODE': |
| + code = int(content) |
| + if code != _ACTIVITY_RESULT_OK or 'result' not in results: |
| + raise device_errors.CommandFailedError('WifiUtil method %s failed (%s): ' |
| + '%s' % (method, code, results)) |
| + |
| + return type_fn(results['result']) |
| + |
| + def _InstallWifiUtilApk(self): |
| + """Install or update the WifiUtil.apk on the device.""" |
| + logging.info('Installing WifiUtil APK') |
| + wifi_util_apk_file_path = os.path.join( |
| + constants.DIR_SOURCE_ROOT, 'build', 'android', 'apks', 'WifiUtil.apk') |
| + self._device.Install(wifi_util_apk_file_path) |
| + self._apk_installed = True |