1#!/usr/bin/env python3
2#
3#   Copyright 2016 - Google
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17import time
18import random
19import re
20
21from acts.utils import rand_ascii_str
22from acts.test_utils.tel.tel_subscription_utils import \
23    get_subid_from_slot_index
24from acts.test_utils.tel.tel_subscription_utils import set_subid_for_data
25from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
26from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
27from acts.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
28from acts.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
29from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
30from acts.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
31from acts.test_utils.tel.tel_test_utils import start_youtube_video
32from acts.test_utils.tel.tel_test_utils import start_wifi_tethering
33from acts.test_utils.tel.tel_test_utils import stop_wifi_tethering
34from acts.test_utils.tel.tel_test_utils import ensure_network_generation_for_subscription
35from acts.test_utils.tel.tel_test_utils import ensure_phones_idle
36from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
37from acts.test_utils.tel.tel_test_utils import get_network_rat_for_subscription
38from acts.test_utils.tel.tel_test_utils import is_droid_in_network_generation_for_subscription
39from acts.test_utils.tel.tel_test_utils import rat_generation_from_rat
40from acts.test_utils.tel.tel_test_utils import set_wifi_to_default
41from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
42from acts.test_utils.tel.tel_test_utils import verify_internet_connection
43from acts.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
44from acts.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
45from acts.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
46from acts.test_utils.tel.tel_test_utils import wifi_toggle_state
47from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
48from acts.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
49from acts.test_utils.tel.tel_test_utils import get_service_state_by_adb
50from acts.test_utils.tel.tel_test_utils import wait_for_state
51from acts.test_utils.tel.tel_test_utils import get_mobile_data_usage
52from acts.test_utils.tel.tel_test_utils import get_wifi_usage
53from acts.test_utils.tel.tel_test_utils import check_is_wifi_connected
54
55def wifi_tethering_cleanup(log, provider, client_list):
56    """Clean up steps for WiFi Tethering.
57
58    Make sure provider turn off tethering.
59    Make sure clients reset WiFi and turn on cellular data.
60
61    Args:
62        log: log object.
63        provider: android object provide WiFi tethering.
64        client_list: a list of clients using tethered WiFi.
65
66    Returns:
67        True if no error happened. False otherwise.
68    """
69    for client in client_list:
70        client.droid.telephonyToggleDataConnection(True)
71        set_wifi_to_default(log, client)
72    if not stop_wifi_tethering(log, provider):
73        provider.log.error("Provider stop WiFi tethering failed.")
74        return False
75    if provider.droid.wifiIsApEnabled():
76        provider.log.error("Provider WiFi tethering is still enabled.")
77        return False
78    return True
79
80
81def wifi_tethering_setup_teardown(log,
82                                  provider,
83                                  client_list,
84                                  ap_band=WIFI_CONFIG_APBAND_2G,
85                                  check_interval=30,
86                                  check_iteration=4,
87                                  do_cleanup=True,
88                                  ssid=None,
89                                  password=None):
90    """Test WiFi Tethering.
91
92    Turn off WiFi on clients.
93    Turn off data and reset WiFi on clients.
94    Verify no Internet access on clients.
95    Turn on WiFi tethering on provider.
96    Clients connect to provider's WiFI.
97    Verify Internet on provider and clients.
98    Tear down WiFi tethering setup and clean up.
99
100    Args:
101        log: log object.
102        provider: android object provide WiFi tethering.
103        client_list: a list of clients using tethered WiFi.
104        ap_band: setup WiFi tethering on 2G or 5G.
105            This is optional, default value is WIFI_CONFIG_APBAND_2G
106        check_interval: delay time between each around of Internet connection check.
107            This is optional, default value is 30 (seconds).
108        check_iteration: check Internet connection for how many times in total.
109            This is optional, default value is 4 (4 times).
110        do_cleanup: after WiFi tethering test, do clean up to tear down tethering
111            setup or not. This is optional, default value is True.
112        ssid: use this string as WiFi SSID to setup tethered WiFi network.
113            This is optional. Default value is None.
114            If it's None, a random string will be generated.
115        password: use this string as WiFi password to setup tethered WiFi network.
116            This is optional. Default value is None.
117            If it's None, a random string will be generated.
118
119    Returns:
120        True if no error happened. False otherwise.
121    """
122    log.info("--->Start wifi_tethering_setup_teardown<---")
123    log.info("Provider: {}".format(provider.serial))
124    if not provider.droid.connectivityIsTetheringSupported():
125        provider.log.error(
126            "Provider does not support tethering. Stop tethering test.")
127        return False
128
129    if ssid is None:
130        ssid = rand_ascii_str(10)
131    if password is None:
132        password = rand_ascii_str(8)
133
134    # No password
135    if password == "":
136        password = None
137
138    try:
139        for client in client_list:
140            log.info("Client: {}".format(client.serial))
141            wifi_toggle_state(log, client, False)
142            client.droid.telephonyToggleDataConnection(False)
143        log.info("WiFI Tethering: Verify client have no Internet access.")
144        for client in client_list:
145            if not verify_internet_connection(
146                    log, client, expected_state=False):
147                client.log.error("Turn off Data on client fail")
148                return False
149
150        provider.log.info(
151            "Provider turn on WiFi tethering. SSID: %s, password: %s", ssid,
152            password)
153
154        if not start_wifi_tethering(log, provider, ssid, password, ap_band):
155            provider.log.error("Provider start WiFi tethering failed.")
156            return False
157        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
158
159        provider.log.info("Provider check Internet connection.")
160        if not verify_internet_connection(log, provider):
161            return False
162        for client in client_list:
163            client.log.info(
164                "Client connect to WiFi and verify AP band correct.")
165            if not ensure_wifi_connected(log, client, ssid, password):
166                client.log.error("Client connect to WiFi failed.")
167                return False
168
169            wifi_info = client.droid.wifiGetConnectionInfo()
170            if ap_band == WIFI_CONFIG_APBAND_5G:
171                if wifi_info["is_24ghz"]:
172                    client.log.error("Expected 5g network. WiFi Info: %s",
173                                     wifi_info)
174                    return False
175            else:
176                if wifi_info["is_5ghz"]:
177                    client.log.error("Expected 2g network. WiFi Info: %s",
178                                     wifi_info)
179                    return False
180
181            client.log.info("Client check Internet connection.")
182            if (not wait_for_wifi_data_connection(log, client, True)
183                    or not verify_internet_connection(log, client)):
184                client.log.error("No WiFi Data on client")
185                return False
186
187        if not tethering_check_internet_connection(
188                log, provider, client_list, check_interval, check_iteration):
189            return False
190
191    finally:
192        if (do_cleanup
193                and (not wifi_tethering_cleanup(log, provider, client_list))):
194            return False
195    return True
196
197
198def tethering_check_internet_connection(log, provider, client_list,
199                                        check_interval, check_iteration):
200    """During tethering test, check client(s) and provider Internet connection.
201
202    Do the following for <check_iteration> times:
203        Delay <check_interval> seconds.
204        Check Tethering provider's Internet connection.
205        Check each client's Internet connection.
206
207    Args:
208        log: log object.
209        provider: android object provide WiFi tethering.
210        client_list: a list of clients using tethered WiFi.
211        check_interval: delay time between each around of Internet connection check.
212        check_iteration: check Internet connection for how many times in total.
213
214    Returns:
215        True if no error happened. False otherwise.
216    """
217    for i in range(1, check_iteration + 1):
218        result = True
219        time.sleep(check_interval)
220        provider.log.info(
221            "Provider check Internet connection after %s seconds.",
222            check_interval * i)
223        if not verify_internet_connection(log, provider):
224            result = False
225            continue
226        for client in client_list:
227            client.log.info(
228                "Client check Internet connection after %s seconds.",
229                check_interval * i)
230            if not verify_internet_connection(log, client):
231                result = False
232                break
233        if result: return result
234    return False
235
236
237def wifi_cell_switching(log, ad, wifi_network_ssid, wifi_network_pass, nw_gen):
238    """Test data connection network switching when phone on <nw_gen>.
239
240    Ensure phone is on <nw_gen>
241    Ensure WiFi can connect to live network,
242    Airplane mode is off, data connection is on, WiFi is on.
243    Turn off WiFi, verify data is on cell and browse to google.com is OK.
244    Turn on WiFi, verify data is on WiFi and browse to google.com is OK.
245    Turn off WiFi, verify data is on cell and browse to google.com is OK.
246
247    Args:
248        log: log object.
249        ad: android object.
250        wifi_network_ssid: ssid for live wifi network.
251        wifi_network_pass: password for live wifi network.
252        nw_gen: network generation the phone should be camped on.
253
254    Returns:
255        True if pass.
256    """
257    try:
258
259        if not ensure_network_generation_for_subscription(
260                log, ad, get_default_data_sub_id(ad), nw_gen,
261                MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
262            ad.log.error("Device failed to register in %s", nw_gen)
263            return False
264
265        start_youtube_video(ad)
266        # Ensure WiFi can connect to live network
267        ad.log.info("Make sure phone can connect to live network by WIFI")
268        if not ensure_wifi_connected(log, ad, wifi_network_ssid,
269                                     wifi_network_pass):
270            ad.log.error("WiFi connect fail.")
271            return False
272        log.info("Phone connected to WIFI.")
273
274        log.info("Step1 Airplane Off, WiFi On, Data On.")
275        toggle_airplane_mode(log, ad, False)
276        wifi_toggle_state(log, ad, True)
277        ad.droid.telephonyToggleDataConnection(True)
278        if (not wait_for_wifi_data_connection(log, ad, True)
279                or not verify_internet_connection(log, ad)):
280            ad.log.error("Data is not on WiFi")
281            return False
282
283        log.info("Step2 WiFi is Off, Data is on Cell.")
284        wifi_toggle_state(log, ad, False)
285        if (not wait_for_cell_data_connection(log, ad, True)
286                or not verify_internet_connection(log, ad)):
287            ad.log.error("Data did not return to cell")
288            return False
289
290        log.info("Step3 WiFi is On, Data is on WiFi.")
291        wifi_toggle_state(log, ad, True)
292        if (not wait_for_wifi_data_connection(log, ad, True)
293                or not verify_internet_connection(log, ad)):
294            ad.log.error("Data did not return to WiFi")
295            return False
296
297        log.info("Step4 WiFi is Off, Data is on Cell.")
298        wifi_toggle_state(log, ad, False)
299        if (not wait_for_cell_data_connection(log, ad, True)
300                or not verify_internet_connection(log, ad)):
301            ad.log.error("Data did not return to cell")
302            return False
303        return True
304
305    finally:
306        ad.force_stop_apk("com.google.android.youtube")
307        wifi_toggle_state(log, ad, False)
308
309
310def airplane_mode_test(log, ad, retries=3):
311    """ Test airplane mode basic on Phone and Live SIM.
312
313    Ensure phone attach, data on, WiFi off and verify Internet.
314    Turn on airplane mode to make sure detach.
315    Turn off airplane mode to make sure attach.
316    Verify Internet connection.
317
318    Args:
319        log: log object.
320        ad: android object.
321
322    Returns:
323        True if pass; False if fail.
324    """
325    if not ensure_phones_idle(log, [ad]):
326        log.error("Failed to return phones to idle.")
327        return False
328
329    try:
330        ad.droid.telephonyToggleDataConnection(True)
331        wifi_toggle_state(log, ad, False)
332
333        ad.log.info("Step1: disable airplane mode and ensure attach")
334        if not toggle_airplane_mode(log, ad, False):
335            ad.log.error("Failed initial attach")
336            return False
337
338        if not wait_for_state(
339                get_service_state_by_adb,
340                "IN_SERVICE",
341                MAX_WAIT_TIME_FOR_STATE_CHANGE,
342                WAIT_TIME_BETWEEN_STATE_CHECK,
343                log,
344                ad):
345            ad.log.error("Current service state is not 'IN_SERVICE'.")
346            return False
347
348        time.sleep(30)
349        if not ad.droid.connectivityNetworkIsConnected():
350            ad.log.error("Network is NOT connected!")
351            return False
352
353        if not wait_for_cell_data_connection(log, ad, True):
354            ad.log.error("Failed to enable data connection.")
355            return False
356
357        if not verify_internet_connection(log, ad, retries=3):
358            ad.log.error("Data not available on cell.")
359            return False
360
361        log.info("Step2: enable airplane mode and ensure detach")
362        if not toggle_airplane_mode(log, ad, True):
363            ad.log.error("Failed to enable Airplane Mode")
364            return False
365        if not wait_for_cell_data_connection(log, ad, False):
366            ad.log.error("Failed to disable cell data connection")
367            return False
368
369        if not verify_internet_connection(log, ad, expected_state=False):
370            ad.log.error("Data available in airplane mode.")
371            return False
372
373        log.info("Step3: disable airplane mode and ensure attach")
374        if not toggle_airplane_mode(log, ad, False):
375            ad.log.error("Failed to disable Airplane Mode")
376            return False
377
378        if not wait_for_state(
379                get_service_state_by_adb,
380                "IN_SERVICE",
381                MAX_WAIT_TIME_FOR_STATE_CHANGE,
382                WAIT_TIME_BETWEEN_STATE_CHECK,
383                log,
384                ad):
385            ad.log.error("Current service state is not 'IN_SERVICE'.")
386            return False
387
388        time.sleep(30)
389        if not ad.droid.connectivityNetworkIsConnected():
390            ad.log.warning("Network is NOT connected!")
391
392        if not wait_for_cell_data_connection(log, ad, True):
393            ad.log.error("Failed to enable cell data connection")
394            return False
395
396        if not verify_internet_connection(log, ad, retries=3):
397            ad.log.warning("Data not available on cell")
398            return False
399        return True
400    finally:
401        toggle_airplane_mode(log, ad, False)
402
403
404def data_connectivity_single_bearer(log, ad, nw_gen):
405    """Test data connection: single-bearer (no voice).
406
407    Turn off airplane mode, enable Cellular Data.
408    Ensure phone data generation is expected.
409    Verify Internet.
410    Disable Cellular Data, verify Internet is inaccessible.
411    Enable Cellular Data, verify Internet.
412
413    Args:
414        log: log object.
415        ad: android object.
416        nw_gen: network generation the phone should on.
417
418    Returns:
419        True if success.
420        False if failed.
421    """
422    ensure_phones_idle(log, [ad])
423    wait_time = MAX_WAIT_TIME_NW_SELECTION
424    if getattr(ad, 'roaming', False):
425        wait_time = 2 * wait_time
426    if not ensure_network_generation_for_subscription(
427            log, ad, get_default_data_sub_id(ad), nw_gen,
428            MAX_WAIT_TIME_NW_SELECTION, NETWORK_SERVICE_DATA):
429        ad.log.error("Device failed to connect to %s in %s seconds.", nw_gen,
430                     wait_time)
431        return False
432
433    try:
434        log.info("Step1 Airplane Off, Data On.")
435        toggle_airplane_mode(log, ad, False)
436        ad.droid.telephonyToggleDataConnection(True)
437        if not wait_for_cell_data_connection(log, ad, True, timeout_value=wait_time):
438            ad.log.error("Failed to enable data connection.")
439            return False
440
441        log.info("Step2 Verify internet")
442        if not verify_internet_connection(log, ad, retries=3):
443            ad.log.error("Data not available on cell.")
444            return False
445
446        log.info("Step3 Turn off data and verify not connected.")
447        ad.droid.telephonyToggleDataConnection(False)
448        if not wait_for_cell_data_connection(log, ad, False):
449            ad.log.error("Step3 Failed to disable data connection.")
450            return False
451
452        if not verify_internet_connection(log, ad, expected_state=False):
453            ad.log.error("Step3 Data still available when disabled.")
454            return False
455
456        log.info("Step4 Re-enable data.")
457        ad.droid.telephonyToggleDataConnection(True)
458        if not wait_for_cell_data_connection(log, ad, True, timeout_value=wait_time):
459            ad.log.error("Step4 failed to re-enable data.")
460            return False
461        if not verify_internet_connection(log, ad, retries=3):
462            ad.log.error("Data not available on cell.")
463            return False
464
465        if not is_droid_in_network_generation_for_subscription(
466                log, ad, get_default_data_sub_id(ad), nw_gen,
467                NETWORK_SERVICE_DATA):
468            ad.log.error("Failed: droid is no longer on correct network")
469            ad.log.info("Expected:%s, Current:%s", nw_gen,
470                        rat_generation_from_rat(
471                            get_network_rat_for_subscription(
472                                log, ad, get_default_data_sub_id(ad),
473                                NETWORK_SERVICE_DATA)))
474            return False
475        return True
476    finally:
477        ad.droid.telephonyToggleDataConnection(True)
478
479
480def change_data_sim_and_verify_data(log, ad, sim_slot):
481    """Change Data SIM and verify Data attach and Internet access
482
483    Args:
484        log: log object.
485        ad: android device object.
486        sim_slot: SIM slot index.
487
488    Returns:
489        Data SIM changed successfully, data attached and Internet access is OK.
490    """
491    sub_id = get_subid_from_slot_index(log, ad, sim_slot)
492    ad.log.info("Change Data to subId: %s, SIM slot: %s", sub_id, sim_slot)
493    set_subid_for_data(ad, sub_id)
494    if not wait_for_data_attach_for_subscription(log, ad, sub_id,
495                                                 MAX_WAIT_TIME_NW_SELECTION):
496        ad.log.error("Failed to attach data on subId:%s", sub_id)
497        return False
498    if not verify_internet_connection(log, ad):
499        ad.log.error("No Internet access after changing Data SIM.")
500        return False
501    return True
502
503def browsing_test(log, ad, wifi_ssid=None, pass_threshold_in_mb = 1.0):
504    """ Ramdomly browse 6 among 23 selected web sites. The idle time is used to
505    simulate visit duration and normally distributed with the mean 35 seconds
506    and std dev 15 seconds, which means 95% of visit duration will be between
507    5 and 65 seconds. DUT will enter suspend mode when idle time is greater than
508    35 seconds.
509
510    Args:
511        log: log object.
512        ad: android object.
513        pass_threshold_in_mb: minimum traffic of browsing 6 web sites in MB for
514            test pass
515
516    Returns:
517        True if the total traffic of Chrome for browsing 6 web sites is greater
518        than pass_threshold_in_mb. Otherwise False.
519    """
520    web_sites = [
521        "http://tw.yahoo.com",
522        "http://24h.pchome.com.tw",
523        "http://www.mobile01.com",
524        "https://www.android.com/phones/",
525        "http://www.books.com.tw",
526        "http://www.udn.com.tw",
527        "http://news.baidu.com",
528        "http://www.google.com",
529        "http://www.cnn.com",
530        "http://www.nytimes.com",
531        "http://www.amazon.com",
532        "http://www.wikipedia.com",
533        "http://www.ebay.com",
534        "http://www.youtube.com",
535        "http://espn.go.com",
536        "http://www.sueddeutsche.de",
537        "http://www.bild.de",
538        "http://www.welt.de",
539        "http://www.lefigaro.fr",
540        "http://www.accuweather.com",
541        "https://www.flickr.com",
542        "http://world.taobao.com",
543        "http://www.theguardian.com",
544        "http://www.abc.net.au",
545        "http://www.gumtree.com.au",
546        "http://www.commbank.com.au",
547        "http://www.news.com.au",
548        "http://rakuten.co.jp",
549        "http://livedoor.jp",
550        "http://yahoo.co.jp"]
551
552    wifi_connected = False
553    if wifi_ssid and check_is_wifi_connected(ad.log, ad, wifi_ssid):
554        wifi_connected = True
555        usage_level_at_start = get_wifi_usage(ad, apk="com.android.chrome")
556    else:
557        usage_level_at_start = get_mobile_data_usage(ad, apk="com.android.chrome")
558
559    for web_site in random.sample(web_sites, 6):
560        ad.log.info("Browsing %s..." % web_site)
561        ad.adb.shell(
562            "am start -a android.intent.action.VIEW -d %s --es "
563            "com.android.browser.application_id com.android.browser" % web_site)
564
565        idle_time = round(random.normalvariate(35, 15))
566        if idle_time < 2:
567            idle_time = 2
568        elif idle_time > 90:
569            idle_time = 90
570
571        ad.log.info(
572            "Idle time before browsing next web site: %s sec." % idle_time)
573
574        if idle_time > 35:
575            time.sleep(35)
576            rest_idle_time = idle_time-35
577            if rest_idle_time < 3:
578                rest_idle_time = 3
579            ad.log.info("Let device go to sleep for %s sec." % rest_idle_time)
580            ad.droid.wakeLockRelease()
581            ad.droid.goToSleepNow()
582            time.sleep(rest_idle_time)
583            ad.log.info("Wake up device.")
584            ad.droid.wakeLockAcquireBright()
585            ad.droid.wakeUpNow()
586            time.sleep(3)
587        else:
588            time.sleep(idle_time)
589
590    if wifi_connected:
591        usage_level = get_wifi_usage(ad, apk="com.android.chrome")
592    else:
593        usage_level = get_mobile_data_usage(ad, apk="com.android.chrome")
594
595    try:
596        usage = round((usage_level - usage_level_at_start)/1024/1024, 2)
597        if usage < pass_threshold_in_mb:
598            ad.log.error(
599                "Usage of browsing '%s MB' is smaller than %s " % (
600                    usage, pass_threshold_in_mb))
601            return False
602        else:
603            ad.log.info("Usage of browsing: %s MB" % usage)
604            return True
605    except Exception as e:
606        ad.log.error(e)
607        usage = "unknown"
608        ad.log.info("Usage of browsing: %s MB" % usage)
609        return False
610