1#!/usr/bin/env python3.4
2#
3#   Copyright 2018 - The Android Open Source Project
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 itertools
18import queue
19import time
20
21import acts.base_test
22import acts.signals as signals
23import acts_contrib.test_utils.wifi.wifi_test_utils as wutils
24import acts.utils
25
26from acts import asserts
27from acts.controllers.android_device import SL4A_APK_NAME
28from acts.test_decorators import test_tracker_info
29from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
30from acts_contrib.test_utils.wifi import wifi_constants
31
32WifiEnums = wutils.WifiEnums
33# EAP Macros
34EAP = WifiEnums.Eap
35EapPhase2 = WifiEnums.EapPhase2
36# Enterprise Config Macros
37Ent = WifiEnums.Enterprise
38BOINGO = 1
39ATT = 2
40# Suggestion network Macros
41Untrusted = "untrusted"
42AutoJoin = "enableAutojoin"
43# Network request Macros
44ClearCapabilities = "ClearCapabilities"
45TransportType = "TransportType"
46
47# Default timeout used for reboot, toggle WiFi and Airplane mode,
48# for the system to settle down after the operation.
49DEFAULT_TIMEOUT = 10
50PASSPOINT_TIMEOUT = 30
51
52
53class WifiNetworkSuggestionTest(WifiBaseTest):
54    """Tests for WifiNetworkSuggestion API surface.
55
56    Test Bed Requirement:
57    * one Android device
58    * Several Wi-Fi networks visible to the device, including an open Wi-Fi
59      network.
60    """
61
62    def __init__(self, configs):
63        super().__init__(configs)
64        self.enable_packet_log = True
65
66    def setup_class(self):
67        super().setup_class()
68
69        self.dut = self.android_devices[0]
70        opt_param = [
71            "open_network", "reference_networks", "hidden_networks",
72            "radius_conf_2g", "radius_conf_5g", "ca_cert", "eap_identity",
73            "eap_password", "passpoint_networks", "domain_suffix_match",
74            "wifi6_models"
75        ]
76        self.unpack_userparams(opt_param_names=opt_param, )
77
78        if "AccessPoint" in self.user_params:
79            self.legacy_configure_ap_and_start(
80                wpa_network=True,
81                ent_network=True,
82                radius_conf_2g=self.radius_conf_2g,
83                radius_conf_5g=self.radius_conf_5g,
84            )
85        elif "OpenWrtAP" in self.user_params:
86            self.configure_openwrt_ap_and_start(
87                open_network=True,
88                wpa_network=True,
89            )
90        if hasattr(self, "reference_networks") and \
91            isinstance(self.reference_networks, list):
92            self.wpa_psk_2g = self.reference_networks[0]["2g"]
93            self.wpa_psk_5g = self.reference_networks[0]["5g"]
94        if hasattr(self, "open_network") and isinstance(
95                self.open_network, list):
96            self.open_2g = self.open_network[0]["2g"]
97            self.open_5g = self.open_network[0]["5g"]
98        if hasattr(self, "hidden_networks") and \
99            isinstance(self.hidden_networks, list):
100            self.hidden_network = self.hidden_networks[0]
101        if hasattr(self, "passpoint_networks"):
102            self.passpoint_network = self.passpoint_networks[BOINGO]
103            self.passpoint_network[WifiEnums.SSID_KEY] = \
104                self.passpoint_networks[BOINGO][WifiEnums.SSID_KEY][0]
105        self.dut.droid.wifiRemoveNetworkSuggestions([])
106        self.dut.adb.shell(
107            "pm disable com.google.android.apps.carrier.carrierwifi",
108            ignore_status=True)
109
110    def setup_test(self):
111        super().setup_test()
112        self.dut.droid.wakeLockAcquireBright()
113        self.dut.droid.wakeUpNow()
114        self.dut.unlock_screen()
115        self.clear_user_disabled_networks()
116        wutils.wifi_toggle_state(self.dut, True)
117        self.dut.ed.clear_all_events()
118        self.clear_carrier_approved(
119            str(self.dut.droid.telephonyGetSimCarrierId()))
120        if "_ent_" in self.test_name:
121            if "OpenWrtAP" in self.user_params:
122                self.access_points[0].close()
123                self.configure_openwrt_ap_and_start(
124                    ent_network=True,
125                    radius_conf_2g=self.radius_conf_2g,
126                    radius_conf_5g=self.radius_conf_5g,
127                )
128            self.ent_network_2g = self.ent_networks[0]["2g"]
129            self.ent_network_5g = self.ent_networks[0]["5g"]
130
131    def teardown_test(self):
132        super().teardown_test()
133        self.dut.droid.wakeLockRelease()
134        self.dut.droid.goToSleepNow()
135        self.dut.droid.wifiRemoveNetworkSuggestions([])
136        self.dut.droid.wifiDisconnect()
137        wutils.reset_wifi(self.dut)
138        wutils.wifi_toggle_state(self.dut, False)
139        self.dut.ed.clear_all_events()
140        self.clear_carrier_approved(
141            str(self.dut.droid.telephonyGetSimCarrierId()))
142
143    def teardown_class(self):
144        self.dut.adb.shell(
145            "pm enable com.google.android.apps.carrier.carrierwifi")
146        if "AccessPoint" in self.user_params:
147            del self.user_params["reference_networks"]
148            del self.user_params["open_network"]
149
150    """Helper Functions"""
151
152    def set_approved(self, approved):
153        self.dut.log.debug("Setting suggestions from sl4a app " +
154                           "approved" if approved else "not approved")
155        self.dut.adb.shell("cmd wifi network-suggestions-set-user-approved" +
156                           " " + SL4A_APK_NAME + " " +
157                           ("yes" if approved else "no"))
158
159    def is_approved(self):
160        is_approved_str = self.dut.adb.shell(
161            "cmd wifi network-suggestions-has-user-approved" + " " +
162            SL4A_APK_NAME)
163        return True if (is_approved_str == "yes") else False
164
165    def set_carrier_approved(self, carrier_id, approved):
166        self.dut.log.debug(
167            ("Setting IMSI protection exemption for carrier: " + carrier_id +
168             "approved" if approved else "not approved"))
169        self.dut.adb.shell(
170            "cmd wifi imsi-protection-exemption-set-user-approved-for-carrier"
171            + " " + carrier_id + " " + ("yes" if approved else "no"))
172
173    def is_carrier_approved(self, carrier_id):
174        is_approved_str = self.dut.adb.shell(
175            "cmd wifi imsi-protection-exemption-has-user-approved-for-carrier"
176            + " " + carrier_id)
177        return True if (is_approved_str == "yes") else False
178
179    def clear_carrier_approved(self, carrier_id):
180        self.dut.adb.shell(
181            "cmd wifi imsi-protection-exemption-clear-user-approved-for-carrier"
182            + " " + carrier_id)
183
184    def clear_user_disabled_networks(self):
185        self.dut.log.debug("Clearing user disabled networks")
186        self.dut.adb.shell("cmd wifi clear-user-disabled-networks")
187
188    def add_suggestions_and_ensure_connection(
189            self, network_suggestions, expected_ssid,
190            expect_post_connection_broadcast):
191        if expect_post_connection_broadcast is not None:
192            self.dut.droid.wifiStartTrackingNetworkSuggestionStateChange()
193
194        self.dut.log.info("Adding network suggestions")
195        asserts.assert_true(
196            self.dut.droid.wifiAddNetworkSuggestions(network_suggestions),
197            "Failed to add suggestions")
198        # Enable suggestions by the app.
199        self.dut.log.debug("Enabling suggestions from test")
200        self.set_approved(True)
201        wutils.start_wifi_connection_scan_and_return_status(self.dut)
202        # if suggestion is passpoint wait longer for connection.
203        if "profile" in network_suggestions:
204            time.sleep(PASSPOINT_TIMEOUT)
205        wutils.wait_for_connect(self.dut, expected_ssid)
206
207        if expect_post_connection_broadcast is None:
208            return
209
210        # Check if we expected to get the broadcast.
211        try:
212            event = self.dut.ed.pop_event(
213                wifi_constants.WIFI_NETWORK_SUGGESTION_POST_CONNECTION, 60)
214        except queue.Empty:
215            if expect_post_connection_broadcast:
216                raise signals.TestFailure(
217                    "Did not receive post connection broadcast")
218        else:
219            if not expect_post_connection_broadcast:
220                raise signals.TestFailure("Received post connection broadcast")
221        finally:
222            self.dut.droid.wifiStopTrackingNetworkSuggestionStateChange()
223        self.dut.ed.clear_all_events()
224
225    def remove_suggestions_disconnect_and_ensure_no_connection_back(
226            self, network_suggestions, expected_ssid):
227        # Remove suggestion trigger disconnect and wait for the disconnect.
228        self.dut.log.info("Removing network suggestions")
229        asserts.assert_true(
230            self.dut.droid.wifiRemoveNetworkSuggestions(network_suggestions),
231            "Failed to remove suggestions")
232        wutils.wait_for_disconnect(self.dut)
233        self.dut.ed.clear_all_events()
234
235        # Now ensure that we didn't connect back.
236        asserts.assert_false(
237            wutils.wait_for_connect(self.dut,
238                                    expected_ssid,
239                                    assert_on_fail=False),
240            "Device should not connect back")
241
242    def _test_connect_to_wifi_network_reboot_config_store(
243            self, network_suggestions, wifi_network):
244        """ Test network suggestion with reboot config store
245
246        Args:
247        1. network_suggestions: network suggestions in list to add to the device.
248        2. wifi_network: expected wifi network to connect to
249        """
250
251        self.add_suggestions_and_ensure_connection(
252            network_suggestions, wifi_network[WifiEnums.SSID_KEY], None)
253        wutils.verify_11ax_wifi_connection(self.dut, self.wifi6_models,
254                                           "wifi6_ap" in self.user_params)
255
256        # Reboot and wait for connection back to the same suggestion.
257        self.dut.reboot()
258        time.sleep(DEFAULT_TIMEOUT)
259
260        wutils.wait_for_connect(self.dut, wifi_network[WifiEnums.SSID_KEY])
261        wutils.verify_11ax_wifi_connection(self.dut, self.wifi6_models,
262                                           "wifi6_ap" in self.user_params)
263
264        self.remove_suggestions_disconnect_and_ensure_no_connection_back(
265            network_suggestions, wifi_network[WifiEnums.SSID_KEY])
266
267        # Reboot with empty suggestion, verify user approval is kept.
268        self.dut.reboot()
269        time.sleep(DEFAULT_TIMEOUT)
270        asserts.assert_true(self.is_approved(), "User approval should be kept")
271
272    @test_tracker_info(uuid="bda8ed20-4382-4380-831a-64cf77eca108")
273    def test_connect_to_wpa_psk_2g(self):
274        """ Adds a network suggestion and ensure that the device connected.
275
276        Steps:
277        1. Send a network suggestion to the device.
278        2. Wait for the device to connect to it.
279        3. Ensure that we did not receive the post connection broadcast
280           (isAppInteractionRequired = False).
281        4. Remove the suggestions and ensure the device does not connect back.
282        """
283        self.add_suggestions_and_ensure_connection(
284            [self.wpa_psk_2g], self.wpa_psk_2g[WifiEnums.SSID_KEY], False)
285
286        self.remove_suggestions_disconnect_and_ensure_no_connection_back(
287            [self.wpa_psk_2g], self.wpa_psk_2g[WifiEnums.SSID_KEY])
288
289    @test_tracker_info(uuid="b2df6ebe-9c5b-4e84-906a-e76f96fcef56")
290    def test_connect_to_wpa_psk_2g_with_screen_off(self):
291        """ Adds a network suggestion and ensure that the device connected
292        when the screen is off.
293
294        Steps:
295        1. Send an invalid suggestion to the device (Needed for PNO scan to start).
296        2. Toggle screen off.
297        3. Send a valid network suggestion to the device.
298        4. Wait for the device to connect to it.
299        5. Ensure that we did not receive the post connection broadcast
300           (isAppInteractionRequired = False).
301        6. Remove the suggestions and ensure the device does not connect back.
302        """
303        invalid_suggestion = self.wpa_psk_5g
304        network_ssid = invalid_suggestion.pop(WifiEnums.SSID_KEY)
305        invalid_suggestion[WifiEnums.SSID_KEY] = network_ssid + "blah"
306
307        self.dut.log.info("Adding invalid suggestions")
308        asserts.assert_true(
309            self.dut.droid.wifiAddNetworkSuggestions([invalid_suggestion]),
310            "Failed to add suggestions")
311
312        # Approve suggestions by the app.
313        self.set_approved(True)
314
315        # Turn screen off to ensure PNO kicks-in.
316        self.dut.droid.wakeLockRelease()
317        self.dut.droid.goToSleepNow()
318        time.sleep(10)
319
320        # Add valid suggestions & ensure we restart PNO and connect to it.
321        self.add_suggestions_and_ensure_connection(
322            [self.wpa_psk_2g], self.wpa_psk_2g[WifiEnums.SSID_KEY], False)
323
324        self.remove_suggestions_disconnect_and_ensure_no_connection_back(
325            [self.wpa_psk_2g], self.wpa_psk_2g[WifiEnums.SSID_KEY])
326
327    @test_tracker_info(uuid="f18bf994-ef3b-45d6-aba0-dd6338b07979")
328    def test_connect_to_wpa_psk_2g_modify_meteredness(self):
329        """ Adds a network suggestion and ensure that the device connected.
330        Change the meteredness of the network after the connection.
331
332        Steps:
333        1. Send a network suggestion to the device.
334        2. Wait for the device to connect to it.
335        3. Ensure that we did not receive the post connection broadcast
336           (isAppInteractionRequired = False).
337        4. Mark the network suggestion metered.
338        5. Ensure that the device disconnected and reconnected back to the
339           suggestion.
340        6. Mark the network suggestion unmetered.
341        7. Ensure that the device did not disconnect.
342        8. Remove the suggestions and ensure the device does not connect back.
343        """
344        self.add_suggestions_and_ensure_connection(
345            [self.wpa_psk_2g], self.wpa_psk_2g[WifiEnums.SSID_KEY], False)
346
347        mod_suggestion = self.wpa_psk_2g
348
349        # Mark the network metered.
350        self.dut.log.debug("Marking suggestion as metered")
351        mod_suggestion[WifiEnums.IS_SUGGESTION_METERED] = True
352        asserts.assert_true(
353            self.dut.droid.wifiAddNetworkSuggestions([mod_suggestion]),
354            "Failed to add suggestions")
355        # Wait for disconnect.
356        wutils.wait_for_disconnect(self.dut)
357        self.dut.log.info("Disconnected from network %s", mod_suggestion)
358        self.dut.ed.clear_all_events()
359        # Wait for reconnect.
360        wutils.wait_for_connect(self.dut, mod_suggestion[WifiEnums.SSID_KEY])
361
362        # Mark the network unmetered.
363        self.dut.log.debug("Marking suggestion as unmetered")
364        mod_suggestion[WifiEnums.IS_SUGGESTION_METERED] = False
365        asserts.assert_true(
366            self.dut.droid.wifiAddNetworkSuggestions([mod_suggestion]),
367            "Failed to add suggestions")
368        # Ensure there is no disconnect.
369        wutils.ensure_no_disconnect(self.dut)
370        self.dut.ed.clear_all_events()
371
372        self.remove_suggestions_disconnect_and_ensure_no_connection_back(
373            [mod_suggestion], mod_suggestion[WifiEnums.SSID_KEY])
374
375    @test_tracker_info(uuid="f54bc250-d9e9-4f00-8b5b-b866e8550b43")
376    def test_connect_to_highest_priority(self):
377        """
378        Adds network suggestions and ensures that device connects to
379        the suggestion with the highest priority.
380
381        Steps:
382        1. Send 2 network suggestions to the device (with different priorities).
383        2. Wait for the device to connect to the network with the highest
384           priority.
385        3. In-place modify network suggestions with priorities reversed
386        4. Restart wifi, wait for the device to connect to the network with the highest
387           priority.
388        5. Re-add the suggestions with the priorities reversed again.
389        6. Again wait for the device to connect to the network with the highest
390           priority.
391        """
392        network_suggestion_2g = self.wpa_psk_2g
393        network_suggestion_5g = self.wpa_psk_5g
394
395        # Add suggestions & wait for the connection event.
396        network_suggestion_2g[WifiEnums.PRIORITY] = 5
397        network_suggestion_5g[WifiEnums.PRIORITY] = 2
398        self.add_suggestions_and_ensure_connection(
399            [network_suggestion_2g, network_suggestion_5g],
400            self.wpa_psk_2g[WifiEnums.SSID_KEY], None)
401
402        # In-place modify Reverse the priority, should be no disconnect
403        network_suggestion_2g[WifiEnums.PRIORITY] = 2
404        network_suggestion_5g[WifiEnums.PRIORITY] = 5
405        self.dut.log.info("Modifying network suggestions")
406        asserts.assert_true(
407            self.dut.droid.wifiAddNetworkSuggestions(
408                [network_suggestion_2g, network_suggestion_5g]),
409            "Failed to add suggestions")
410        wutils.ensure_no_disconnect(self.dut)
411
412        # Disable and re-enable wifi, should connect to higher priority
413        wutils.wifi_toggle_state(self.dut, False)
414        time.sleep(DEFAULT_TIMEOUT)
415        wutils.wifi_toggle_state(self.dut, True)
416        wutils.start_wifi_connection_scan_and_return_status(self.dut)
417        wutils.wait_for_connect(self.dut, self.wpa_psk_5g[WifiEnums.SSID_KEY])
418
419        self.remove_suggestions_disconnect_and_ensure_no_connection_back(
420            [], self.wpa_psk_5g[WifiEnums.SSID_KEY])
421
422        # Reverse the priority.
423        # Add suggestions & wait for the connection event.
424        network_suggestion_2g[WifiEnums.PRIORITY] = 5
425        network_suggestion_5g[WifiEnums.PRIORITY] = 2
426        self.add_suggestions_and_ensure_connection(
427            [network_suggestion_2g, network_suggestion_5g],
428            self.wpa_psk_2g[WifiEnums.SSID_KEY], None)
429
430    @test_tracker_info(uuid="b1d27eea-23c8-4c4f-b944-ef118e4cc35f")
431    def test_connect_to_wpa_psk_2g_with_post_connection_broadcast(self):
432        """ Adds a network suggestion and ensure that the device connected.
433
434        Steps:
435        1. Send a network suggestion to the device with
436           isAppInteractionRequired set.
437        2. Wait for the device to connect to it.
438        3. Ensure that we did receive the post connection broadcast
439           (isAppInteractionRequired = True).
440        4. Remove the suggestions and ensure the device does not connect back.
441        """
442        network_suggestion = self.wpa_psk_2g
443        network_suggestion[WifiEnums.IS_APP_INTERACTION_REQUIRED] = True
444        self.add_suggestions_and_ensure_connection(
445            [network_suggestion], self.wpa_psk_2g[WifiEnums.SSID_KEY], True)
446        self.remove_suggestions_disconnect_and_ensure_no_connection_back(
447            [self.wpa_psk_2g], self.wpa_psk_2g[WifiEnums.SSID_KEY])
448
449    @test_tracker_info(uuid="a036a24d-29c0-456d-ae6a-afdde34da710")
450    def test_connect_to_wpa_psk_5g_reboot_config_store(self):
451        """
452        Adds a network suggestion and ensure that the device connects to it
453        after reboot.
454
455        Steps:
456        1. Send a network suggestion to the device.
457        2. Wait for the device to connect to it.
458        3. Ensure that we did not receive the post connection broadcast
459           (isAppInteractionRequired = False).
460        4. Reboot the device.
461        5. Wait for the device to connect to back to it.
462        6. Remove the suggestions and ensure the device does not connect back.
463        7. Reboot the device again, ensure user approval is kept
464        """
465        self._test_connect_to_wifi_network_reboot_config_store(
466            [self.wpa_psk_5g], self.wpa_psk_5g)
467
468    @test_tracker_info(uuid="61649a2b-0f00-4272-9b9b-40ad5944da31")
469    def test_connect_to_wpa_ent_config_aka_reboot_config_store(self):
470        """
471        Adds a network suggestion and ensure that the device connects to it
472        after reboot.
473
474        Steps:
475        1. Send a Enterprise AKA network suggestion to the device.
476        2. Wait for the device to connect to it.
477        3. Ensure that we did not receive the post connection broadcast.
478        4. Reboot the device.
479        5. Wait for the device to connect to the wifi network.
480        6. Remove suggestions and ensure device doesn't connect back to it.
481        7. Reboot the device again, ensure user approval is kept
482        """
483        self.config_aka = {
484            Ent.EAP: int(EAP.AKA),
485            WifiEnums.SSID_KEY: self.ent_network_2g[WifiEnums.SSID_KEY],
486            "carrierId": str(self.dut.droid.telephonyGetSimCarrierId()),
487        }
488        if "carrierId" in self.config_aka:
489            self.set_carrier_approved(self.config_aka["carrierId"], True)
490        self._test_connect_to_wifi_network_reboot_config_store(
491            [self.config_aka], self.ent_network_2g)
492        if "carrierId" in self.config_aka:
493            self.clear_carrier_approved(self.config_aka["carrierId"])
494
495    @test_tracker_info(uuid="98b2d40a-acb4-4a2f-aba1-b069e2a1d09d")
496    def test_connect_to_wpa_ent_config_ttls_pap_reboot_config_store(self):
497        """
498        Adds a network suggestion and ensure that the device connects to it
499        after reboot.
500
501        Steps:
502        1. Send a Enterprise TTLS PAP network suggestion to the device.
503        2. Wait for the device to connect to it.
504        3. Ensure that we did not receive the post connection broadcast.
505        4. Reboot the device.
506        5. Wait for the device to connect to the wifi network.
507        6. Remove suggestions and ensure device doesn't connect back to it.
508        7. Reboot the device again, ensure user approval is kept
509        """
510        self.config_ttls = {
511            Ent.EAP: int(EAP.TTLS),
512            Ent.CA_CERT: self.ca_cert,
513            Ent.IDENTITY: self.eap_identity,
514            Ent.PASSWORD: self.eap_password,
515            Ent.PHASE2: int(EapPhase2.MSCHAPV2),
516            WifiEnums.SSID_KEY: self.ent_network_2g[WifiEnums.SSID_KEY],
517            Ent.DOM_SUFFIX_MATCH: self.domain_suffix_match,
518        }
519        config = dict(self.config_ttls)
520        config[WifiEnums.Enterprise.PHASE2] = WifiEnums.EapPhase2.PAP.value
521
522        self._test_connect_to_wifi_network_reboot_config_store(
523            [config], self.ent_network_2g)
524
525    @test_tracker_info(uuid="554b5861-22d0-4922-a5f4-712b4cf564eb")
526    def test_fail_to_connect_to_wpa_psk_5g_when_not_approved(self):
527        """
528        Adds a network suggestion and ensure that the device does not
529        connect to it until we approve the app.
530
531        Steps:
532        1. Send a network suggestion to the device with the app not approved.
533        2. Ensure the network is present in scan results, but we don't connect
534           to it.
535        3. Now approve the app.
536        4. Wait for the device to connect to it.
537        """
538        self.dut.log.info("Adding network suggestions")
539        asserts.assert_true(
540            self.dut.droid.wifiAddNetworkSuggestions([self.wpa_psk_5g]),
541            "Failed to add suggestions")
542
543        # Disable suggestions by the app.
544        self.set_approved(False)
545
546        # Ensure the app is not approved.
547        asserts.assert_false(self.is_approved(),
548                             "Suggestions should be disabled")
549
550        # Start a new scan to trigger auto-join.
551        wutils.start_wifi_connection_scan_and_ensure_network_found(
552            self.dut, self.wpa_psk_5g[WifiEnums.SSID_KEY])
553
554        # Ensure we don't connect to the network.
555        asserts.assert_false(
556            wutils.wait_for_connect(self.dut,
557                                    self.wpa_psk_5g[WifiEnums.SSID_KEY],
558                                    assert_on_fail=False),
559            "Should not connect to network suggestions from unapproved app")
560
561        self.dut.log.info("Enabling suggestions from test")
562        # Now Enable suggestions by the app & ensure we connect to the network.
563        self.set_approved(True)
564
565        # Ensure the app is approved.
566        asserts.assert_true(self.is_approved(),
567                            "Suggestions should be enabled")
568
569        # Start a new scan to trigger auto-join.
570        wutils.start_wifi_connection_scan_and_ensure_network_found(
571            self.dut, self.wpa_psk_5g[WifiEnums.SSID_KEY])
572
573        wutils.wait_for_connect(self.dut, self.wpa_psk_5g[WifiEnums.SSID_KEY])
574
575    @test_tracker_info(uuid="98400dea-776e-4a0a-9024-18845b27331c")
576    def test_fail_to_connect_to_wpa_psk_2g_after_user_forgot_network(self):
577        """
578        Adds a network suggestion and ensures that the device does not
579        connect to it after the user forgot the network previously.
580
581        Steps:
582        1. Send a network suggestion to the device with
583           isAppInteractionRequired set.
584        2. Wait for the device to connect to it.
585        3. Ensure that we did receive the post connection broadcast
586           (isAppInteractionRequired = True).
587        4. Simulate user forgetting the network and the device does not
588           connecting back even though the suggestion is active from the app.
589        """
590        network_suggestion = self.wpa_psk_2g
591        network_suggestion[WifiEnums.IS_APP_INTERACTION_REQUIRED] = True
592        self.add_suggestions_and_ensure_connection(
593            [network_suggestion], self.wpa_psk_2g[WifiEnums.SSID_KEY], True)
594
595        # Simulate user disconnect the network.
596        self.dut.droid.wifiUserDisconnectNetwork(
597            self.wpa_psk_2g[WifiEnums.SSID_KEY])
598        wutils.wait_for_disconnect(self.dut)
599        self.dut.log.info("Disconnected from network %s", self.wpa_psk_2g)
600        self.dut.ed.clear_all_events()
601
602        # Now ensure that we don't connect back even though the suggestion
603        # is still active.
604        asserts.assert_false(
605            wutils.wait_for_connect(self.dut,
606                                    self.wpa_psk_2g[WifiEnums.SSID_KEY],
607                                    assert_on_fail=False),
608            "Device should not connect back")
609
610    @test_tracker_info(uuid="93c86b05-fa56-4d79-ad27-009a16f691b1")
611    def test_connect_to_hidden_network(self):
612        """
613        Adds a network suggestion with hidden SSID config, ensure device can scan
614        and connect to this network.
615
616        Steps:
617        1. Send a hidden network suggestion to the device.
618        2. Wait for the device to connect to it.
619        3. Ensure that we did not receive the post connection broadcast
620           (isAppInteractionRequired = False).
621        4. Remove the suggestions and ensure the device does not connect back.
622        """
623        asserts.skip_if(not hasattr(self, "hidden_networks"),
624                        "No hidden networks, skip this test")
625
626        network_suggestion = self.hidden_network
627        self.add_suggestions_and_ensure_connection(
628            [network_suggestion], network_suggestion[WifiEnums.SSID_KEY],
629            False)
630        self.remove_suggestions_disconnect_and_ensure_no_connection_back(
631            [network_suggestion], network_suggestion[WifiEnums.SSID_KEY])
632
633    @test_tracker_info(uuid="806dff14-7543-482b-bd0a-598de59374b3")
634    def test_connect_to_passpoint_network_with_post_connection_broadcast(self):
635        """ Adds a passpoint network suggestion and ensure that the device connected.
636
637        Steps:
638        1. Send a network suggestion to the device.
639        2. Wait for the device to connect to it.
640        3. Ensure that we did receive the post connection broadcast
641               (isAppInteractionRequired = true).
642        4. Remove the suggestions and ensure the device does not connect back.
643        """
644        asserts.skip_if(not hasattr(self, "passpoint_networks"),
645                        "No passpoint networks, skip this test")
646        passpoint_config = self.passpoint_network
647        passpoint_config[WifiEnums.IS_APP_INTERACTION_REQUIRED] = True
648        if "carrierId" in passpoint_config:
649            self.set_carrier_approved(passpoint_config["carrierId"], True)
650        self.add_suggestions_and_ensure_connection(
651            [passpoint_config], passpoint_config[WifiEnums.SSID_KEY], True)
652        self.remove_suggestions_disconnect_and_ensure_no_connection_back(
653            [passpoint_config], passpoint_config[WifiEnums.SSID_KEY])
654        if "carrierId" in passpoint_config:
655            self.clear_carrier_approved(passpoint_config["carrierId"])
656
657    @test_tracker_info(uuid="159b8b8c-fb00-4d4e-a29f-606881dcbf44")
658    def test_connect_to_passpoint_network_reboot_config_store(self):
659        """
660        Adds a passpoint network suggestion and ensure that the device connects to it
661        after reboot.
662
663        Steps:
664        1. Send a network suggestion to the device.
665        2. Wait for the device to connect to it.
666        3. Ensure that we did not receive the post connection broadcast
667           (isAppInteractionRequired = False).
668        4. Reboot the device.
669        5. Wait for the device to connect to back to it.
670        6. Remove the suggestions and ensure the device does not connect back.
671        7. Reboot the device again, ensure user approval is kept
672        """
673        asserts.skip_if(not hasattr(self, "passpoint_networks"),
674                        "No passpoint networks, skip this test")
675        passpoint_config = self.passpoint_network
676        if "carrierId" in passpoint_config:
677            self.set_carrier_approved(passpoint_config["carrierId"], True)
678        self._test_connect_to_wifi_network_reboot_config_store(
679            [passpoint_config], passpoint_config)
680        if "carrierId" in passpoint_config:
681            self.clear_carrier_approved(passpoint_config["carrierId"])
682
683    @test_tracker_info(uuid="34f3d28a-bedf-43fe-a12d-2cfadf6bc6eb")
684    def test_fail_to_connect_to_passpoint_network_when_not_approved(self):
685        """
686        Adds a passpoint network suggestion and ensure that the device does not
687        connect to it until we approve the app.
688
689        Steps:
690        1. Send a network suggestion to the device with the app not approved.
691        2. Ensure the network is present in scan results, but we don't connect
692           to it.
693        3. Now approve the app.
694        4. Wait for the device to connect to it.
695        """
696        asserts.skip_if(not hasattr(self, "passpoint_networks"),
697                        "No passpoint networks, skip this test")
698        passpoint_config = self.passpoint_network
699        if "carrierId" in passpoint_config:
700            self.set_carrier_approved(passpoint_config["carrierId"], True)
701        self.dut.log.info("Adding network suggestions")
702        asserts.assert_true(
703            self.dut.droid.wifiAddNetworkSuggestions([passpoint_config]),
704            "Failed to add suggestions")
705
706        # Disable suggestions by the app.
707        self.set_approved(False)
708
709        # Ensure the app is not approved.
710        asserts.assert_false(self.is_approved(),
711                             "Suggestions should be disabled")
712
713        # Start a new scan to trigger auto-join.
714        wutils.start_wifi_connection_scan_and_ensure_network_found(
715            self.dut, passpoint_config[WifiEnums.SSID_KEY])
716
717        # Ensure we don't connect to the network.
718        asserts.assert_false(
719            wutils.wait_for_connect(self.dut,
720                                    passpoint_config[WifiEnums.SSID_KEY],
721                                    assert_on_fail=False),
722            "Should not connect to network suggestions from unapproved app")
723
724        self.dut.log.info("Enabling suggestions from test")
725        # Now Enable suggestions by the app & ensure we connect to the network.
726        self.set_approved(True)
727
728        # Ensure the app is approved.
729        asserts.assert_true(self.is_approved(),
730                            "Suggestions should be enabled")
731
732        # Start a new scan to trigger auto-join.
733        wutils.start_wifi_connection_scan_and_ensure_network_found(
734            self.dut, passpoint_config[WifiEnums.SSID_KEY])
735        time.sleep(PASSPOINT_TIMEOUT)
736        wutils.wait_for_connect(self.dut, passpoint_config[WifiEnums.SSID_KEY])
737        if "carrierId" in passpoint_config:
738            self.clear_carrier_approved(passpoint_config["carrierId"])
739
740    @test_tracker_info(uuid="cf624cda-4d25-42f1-80eb-6c717fb08338")
741    def test_fail_to_connect_to_passpoint_network_when_imsi_protection_exemption_not_approved(
742            self):
743        """
744        Adds a passpoint network suggestion using SIM credential without IMSI privacy protection.
745        Before user approves the exemption, ensure that the device does noconnect to it until we
746        approve the carrier exemption.
747
748        Steps:
749        1. Send a network suggestion to the device with IMSI protection exemption not approved.
750        2. Ensure the network is present in scan results, but we don't connect
751           to it.
752        3. Now approve the carrier.
753        4. Wait for the device to connect to it.
754        """
755        asserts.skip_if(not hasattr(self, "passpoint_networks"),
756                        "No passpoint networks, skip this test")
757        passpoint_config = self.passpoint_networks[ATT]
758        passpoint_config[WifiEnums.SSID_KEY] = self.passpoint_networks[ATT][
759            WifiEnums.SSID_KEY][0]
760        asserts.skip_if("carrierId" not in passpoint_config,
761                        "Not a SIM based passpoint network, skip this test")
762
763        # Ensure the carrier is not approved.
764        asserts.assert_false(
765            self.is_carrier_approved(passpoint_config["carrierId"]),
766            "Carrier shouldn't be approved")
767
768        self.dut.log.info("Adding network suggestions")
769        asserts.assert_true(
770            self.dut.droid.wifiAddNetworkSuggestions([passpoint_config]),
771            "Failed to add suggestions")
772
773        # Start a new scan to trigger auto-join.
774        wutils.start_wifi_connection_scan_and_ensure_network_found(
775            self.dut, passpoint_config[WifiEnums.SSID_KEY])
776
777        # Ensure we don't connect to the network.
778        asserts.assert_false(
779            wutils.wait_for_connect(self.dut,
780                                    passpoint_config[WifiEnums.SSID_KEY],
781                                    assert_on_fail=False),
782            "Should not connect to network suggestions from unapproved app")
783
784        self.dut.log.info("Enabling suggestions from test")
785        # Now approve IMSI protection exemption by carrier & ensure we connect to the network.
786        self.set_carrier_approved(passpoint_config["carrierId"], True)
787
788        # Ensure the carrier is approved.
789        asserts.assert_true(
790            self.is_carrier_approved(passpoint_config["carrierId"]),
791            "Carrier should be approved")
792
793        # Start a new scan to trigger auto-join.
794        wutils.start_wifi_connection_scan_and_ensure_network_found(
795            self.dut, passpoint_config[WifiEnums.SSID_KEY])
796        time.sleep(PASSPOINT_TIMEOUT)
797        wutils.wait_for_connect(self.dut, passpoint_config[WifiEnums.SSID_KEY])
798        self.clear_carrier_approved(passpoint_config["carrierId"])
799
800    @test_tracker_info(uuid="e35f99c8-78a4-4b96-9258-f9834b6ddd33")
801    def test_initial_auto_join_on_network_suggestion(self):
802        """
803        Add a network suggestion with enableAutojoin bit set to false, ensure the device doesn't
804        auto connect to this network
805
806        Steps:
807        1. Create a network suggestion.
808        2. Set EnableAutojoin to false.
809        3. Add this suggestion
810        4. Ensure device doesn't connect to his network
811        """
812        network_suggestion = self.wpa_psk_5g
813        # Set suggestion auto join initial to false.
814        network_suggestion[AutoJoin] = False
815        self.dut.log.info("Adding network suggestions")
816        asserts.assert_true(
817            self.dut.droid.wifiAddNetworkSuggestions([network_suggestion]),
818            "Failed to add suggestions")
819        # Enable suggestions by the app.
820        self.dut.log.debug("Enabling suggestions from test")
821        self.set_approved(True)
822        wutils.start_wifi_connection_scan_and_return_status(self.dut)
823        asserts.assert_false(
824            wutils.wait_for_connect(self.dut,
825                                    network_suggestion[WifiEnums.SSID_KEY],
826                                    assert_on_fail=False),
827            "Device should not connect.")
828
829    @test_tracker_info(uuid="ff4e451f-a380-4ff5-a5c2-dd9b1633d5e5")
830    def test_user_override_auto_join_on_network_suggestion(self):
831        """
832        Add a network suggestion, user change the auto join to false, ensure the device doesn't
833        auto connect to this network
834
835        Steps:
836        1. Create a network suggestion.
837        2. Add this suggestion, and ensure we connect to this network
838        3. Simulate user change the auto join to false.
839        4. Toggle the Wifi off and on
840        4. Ensure device doesn't connect to his network
841        """
842        network_suggestion = self.wpa_psk_5g
843        self.add_suggestions_and_ensure_connection(
844            [network_suggestion], network_suggestion[WifiEnums.SSID_KEY],
845            False)
846        wifi_info = self.dut.droid.wifiGetConnectionInfo()
847        self.dut.log.info(wifi_info)
848        network_id = wifi_info[WifiEnums.NETID_KEY]
849        # Simulate user disable auto join through Settings.
850        self.dut.log.info("Disable auto join on suggestion")
851        self.dut.droid.wifiEnableAutojoin(network_id, False)
852        wutils.wifi_toggle_state(self.dut, False)
853        wutils.wifi_toggle_state(self.dut, True)
854        asserts.assert_false(
855            wutils.wait_for_connect(self.dut,
856                                    network_suggestion[WifiEnums.SSID_KEY],
857                                    assert_on_fail=False),
858            "Device should not connect.")
859
860    @test_tracker_info(uuid="32201b1c-76a0-46dc-9983-2cd24312a783")
861    def test_untrusted_suggestion_without_untrusted_request(self):
862        """
863        Add an untrusted network suggestion, when no untrusted request, will not connect to it.
864        Steps:
865        1. Create a untrusted network suggestion.
866        2. Add this suggestion, and ensure device do not connect to this network
867        3. Request untrusted network and ensure device connect to this network
868        """
869        network_suggestion = self.open_5g
870        network_suggestion[Untrusted] = True
871        self.dut.log.info("Adding network suggestions")
872        asserts.assert_true(
873            self.dut.droid.wifiAddNetworkSuggestions([network_suggestion]),
874            "Failed to add suggestions")
875        # Start a new scan to trigger auto-join.
876        wutils.start_wifi_connection_scan_and_ensure_network_found(
877            self.dut, network_suggestion[WifiEnums.SSID_KEY])
878
879        # Ensure we don't connect to the network.
880        asserts.assert_false(
881            wutils.wait_for_connect(self.dut,
882                                    network_suggestion[WifiEnums.SSID_KEY],
883                                    assert_on_fail=False),
884            "Should not connect to untrusted network suggestions with no request"
885        )
886        network_request = {ClearCapabilities: True, TransportType: 1}
887        req_key = self.dut.droid.connectivityRequestNetwork(network_request)
888
889        # Start a new scan to trigger auto-join.
890        wutils.start_wifi_connection_scan_and_ensure_network_found(
891            self.dut, network_suggestion[WifiEnums.SSID_KEY])
892
893        wutils.wait_for_connect(self.dut,
894                                network_suggestion[WifiEnums.SSID_KEY],
895                                assert_on_fail=False)
896
897        self.dut.droid.connectivityUnregisterNetworkCallback(req_key)
898