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