OLD | NEW |
---|---|
(Empty) | |
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """Manages WiFi connection""" | |
6 | |
7 import logging | |
8 import os | |
9 import sys | |
10 import time | |
11 | |
12 sys.path.append(os.path.join(sys.path[0], '..', '..', 'build','android')) | |
13 from pylib import constants | |
14 from pylib.device import device_utils | |
15 from pylib.device import device_errors | |
16 from pylib.utils import logging_utils | |
17 from pylib.utils import timeout_retry | |
18 | |
19 _ACTIVITY_RESULT_OK = -1 | |
20 _STR_TO_BOOL = {'true': True, 'false': False} | |
21 | |
22 | |
23 class WiFiManager(object): | |
24 """A wrapper around WifiUtil.apk to manage wifi settings. | |
25 | |
26 WifiUtil is available at build/android/apks/WifiUtil.apk, for more | |
navabi
2015/06/18 01:04:57
changed this.
| |
27 information, see the README in build/android/apks/ | |
28 """ | |
29 | |
30 def __init__(self, device): | |
31 """ | |
32 Args: | |
33 device: A DeviceUtils object to work with. | |
34 """ | |
35 self._device = device | |
36 self._apk_installed = False | |
37 | |
38 def IsWifiEnabled(self): | |
39 """Checks whether or not wifi is enabled on the device.""" | |
40 return self._WifiUtilMethod('isWifiEnabled') | |
41 | |
42 def IsInternetReachable(self, destination='www.google.com', count=2, | |
43 timeout=5): | |
44 """Checks whether or not internet is reachable from the device. | |
45 | |
46 Args: | |
47 destination: A string with a destination to check for connectivity. | |
48 count: Number of ping packets to send. | |
49 timeout: Number of seconds to wait for packets to return. | |
50 | |
51 Return: | |
52 True if pings to the destination succeeded, False otherwise. | |
53 """ | |
54 try: | |
55 self._device.RunShellCommand( | |
56 ['ping', '-w', str(timeout), '-c', str(count), destination], | |
57 check_return=True) | |
58 return True | |
59 except device_errors.AdbShellCommandFailedError: | |
60 return False | |
61 | |
62 def EnableWifi(self): | |
63 """Enables wifi on the device.""" | |
64 if not self._WifiUtilMethod('enableWifi'): | |
65 raise device_errors.CommandFailedError( | |
66 'Failed to enable wifi on the device') | |
67 | |
68 def DisableWifi(self): | |
69 """Disables wifi on the device.""" | |
70 if not self._WifiUtilMethod('disableWifi'): | |
71 raise device_errors.CommandFailedError( | |
72 'Failed to disable wifi on the device') | |
73 | |
74 def AddOpenNetwork(self, ssid): | |
75 """Adds an open wifi network configuarion. | |
76 | |
77 Args: | |
78 ssid: A string with the SSID of a wifi network. | |
79 | |
80 Return: | |
81 The network ID of the new network configuarion as an integer. | |
82 """ | |
83 return self._WifiUtilMethod('addOpenNetwork', {'ssid': ssid}, type_fn=int) | |
84 | |
85 def AddSecureNetwork(self, ssid, password_file): | |
86 """Adds an wpa/psk wifi network configuarion. | |
87 | |
88 Args: | |
89 ssid: A string with the SSID of a wifi network. | |
90 password_file: A file containing the password for the wifi | |
91 | |
92 Return: | |
93 The network ID of the new network configuarion as an integer. | |
94 """ | |
95 with open(password_file) as f: | |
96 password = f.read().rstrip() | |
97 with logging_utils.SuppressLogging(): | |
98 result = self._WifiUtilMethod('addWpaPskNetwork', | |
99 {'ssid': ssid, 'psk': password}, type_fn=int) | |
100 return result | |
101 | |
102 def AssociateNetwork(self, net_id): | |
103 """Associates (connects) to a previously configured network. | |
104 | |
105 Args: | |
106 net_id: An integer with the network ID to associate with. | |
107 """ | |
108 if not self._WifiUtilMethod('associateNetwork', {'id': net_id}): | |
109 raise device_errors.CommandFailedError( | |
110 'Failed to connect to network id %d.' % net_id) | |
111 | |
112 def SaveConfiguration(self): | |
113 """Persists the current configured networks. | |
114 | |
115 Note: It is possible for this method to change the network IDs of existing | |
116 networks. | |
117 """ | |
118 if not self._WifiUtilMethod('saveConfiguration'): | |
119 raise device_errors.CommandFailedError( | |
120 'Failed to save the current network configuration.') | |
121 | |
122 def ConnectToGoogleGuest(self): | |
123 self.ConnectToWifi('GoogleGuest') | |
124 | |
125 def ConnectToWifi(self, ssid, password_file=None): | |
126 """Enables wifi on the device and connects to specified ssid.""" | |
127 def wifi_enabled(): | |
128 return self.IsWifiEnabled() | |
129 | |
130 def internet_reachable(): | |
131 return self.IsInternetReachable() | |
132 | |
133 logging.info('Enabling wifi') | |
134 self.EnableWifi() | |
135 if not timeout_retry.WaitFor(wifi_enabled, max_tries=6): | |
136 raise device_errors.CommandFailedError( | |
137 'Timed out waiting for wifi to be enabled') | |
138 | |
139 logging.info('Adding %s', ssid) | |
140 if password_file: | |
141 net_id = self.AddSecureNetwork(ssid, password_file) | |
142 else: | |
143 net_id = self.AddOpenNetwork(ssid) | |
144 logging.info('Connecting to %s', ssid) | |
145 self.AssociateNetwork(net_id) | |
146 logging.info('Saving wifi configuration') | |
147 self.SaveConfiguration() | |
148 | |
149 if not timeout_retry.WaitFor(internet_reachable, max_tries=6): | |
150 raise device_errors.CommandFailedError( | |
151 'Timed out waiting for Internet connectivity: www.google.com is not' | |
152 ' responding.') | |
153 | |
154 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
| |
155 """Run a WifiUtil.apk instrumentation and return its result. | |
156 | |
157 Maps each invocation to an instrumentation command of the form: | |
158 | |
159 am instrument -e method <METHOD> -e <KEY1> <VAL1> ... \ | |
160 -w com.android.tradefed.utils.wifi/.WifiUtil | |
161 | |
162 Args: | |
163 method: A string with the name of the WifiUtil.apk method to invoke. | |
164 args: A dictionary with extra arguments for the method, values will be | |
165 implicitly casted to strings. | |
166 type_fn: A function called to interpret the result of the method. The | |
167 default expects and returns a boolean value. | |
168 | |
169 Return: | |
170 The result obtained from INSTRUMENTATION_RESULT: result=[value], as | |
171 interpreted by the type_fn function. | |
172 | |
173 Raises: | |
174 AssertionError if the instrumentation call is not successful, or the | |
175 instrumentation result is missing. | |
176 """ | |
177 if not self._apk_installed: | |
178 self._InstallWifiUtilApk() | |
179 | |
180 extras = {'method': method} | |
181 if args is not None: | |
182 extras.update((k, str(v)) for k, v in args.iteritems()) | |
183 if type_fn is None: | |
184 type_fn = lambda r: _STR_TO_BOOL[r] | |
185 | |
186 output = self._device.StartInstrumentation( | |
187 'com.android.tradefed.utils.wifi/.WifiUtil', | |
188 extras=extras) | |
189 results = {} | |
190 code = None | |
191 for line in output: | |
192 section, content = line.split(': ', 1) | |
193 if section == 'INSTRUMENTATION_RESULT': | |
194 key, value = content.split('=', 1) | |
195 results[key] = value | |
196 elif section == 'INSTRUMENTATION_CODE': | |
197 code = int(content) | |
198 if code != _ACTIVITY_RESULT_OK or 'result' not in results: | |
199 raise device_errors.CommandFailedError('WifiUtil method %s failed (%s): ' | |
200 '%s' % (method, code, results)) | |
201 | |
202 return type_fn(results['result']) | |
203 | |
204 def _InstallWifiUtilApk(self): | |
205 """Install or update the WifiUtil.apk on the device.""" | |
206 logging.info('Installing WifiUtil APK') | |
207 wifi_util_apk_file_path = os.path.join( | |
208 constants.DIR_SOURCE_ROOT, 'build', 'android', 'apks', 'WifiUtil.apk') | |
209 self._device.Install(wifi_util_apk_file_path) | |
210 self._apk_installed = True | |
OLD | NEW |