1#!/usr/bin/env python3.4
2#
3#   Copyright 2017 - 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"""
17    Test Script for Project Fi Setting
18"""
19
20import time
21
22from acts.test_decorators import test_tracker_info
23from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
24from acts.test_utils.tel.tel_defines import CARRIER_SPT
25from acts.test_utils.tel.tel_defines import CARRIER_TMO
26from acts.test_utils.tel.tel_defines import CARRIER_USCC
27from acts.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
28from acts.test_utils.tel.tel_test_utils import abort_all_tests
29from acts.test_utils.tel.tel_test_utils import ensure_phone_subscription
30from acts.test_utils.tel.tel_test_utils import ensure_wifi_connected
31from acts.test_utils.tel.tel_test_utils import is_sim_ready
32from acts.test_utils.tel.tel_test_utils import log_screen_shot
33from acts.test_utils.tel.tel_test_utils import multithread_func
34from acts.test_utils.tel.tel_test_utils import reboot_device
35from acts.test_utils.tel.tel_test_utils import refresh_droid_config
36from acts.test_utils.tel.tel_test_utils import send_dialer_secret_code
37from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
38from acts.test_utils.tel.tel_test_utils import wait_for_state
39from acts.test_utils.tel.tel_test_utils import add_google_account
40from acts.test_utils.tel.tel_test_utils import remove_google_account
41
42CARRIER_AUTO = "auto"
43
44_CARRIER_DIALER_CODE_LOOKUP = {
45    CARRIER_AUTO: '342886',
46    CARRIER_SPT: '34777',
47    CARRIER_TMO: '34866',
48    CARRIER_USCC: '34872'
49}
50
51_SWITCHING_PREF_FILE = (
52    '/data/data/com.google.android.apps.tycho/shared_prefs/switching.xml')
53
54_INTENT_FLAGS = int(0x00008000 | 0x10000000 | 0x00080000 | 0x00020000)
55_TYCHO_PKG = 'com.google.android.apps.tycho'
56_MAX_WAIT_TIME = 600
57_TYCHO_VERBOSE_LOGGING_CMDS = [
58    "setprop log.tag.Tycho VERBOSE",
59    "CLASSPATH=/system/framework/am.jar su root app_process "
60    "/system/bin com.android.commands.am.Am broadcast -a "
61    "com.google.gservices.intent.action.GSERVICES_OVERRIDE "
62    "-e tycho.enable_request_logging true",
63    "CLASSPATH=/system/framework/am.jar su root app_process "
64    "/system/bin com.android.commands.am.Am broadcast -a "
65    "com.google.gservices.intent.action.GSERVICES_OVERRIDE "
66    "-e tycho.enable_sensitive_logging true",
67    "CLASSPATH=/system/framework/am.jar su root app_process "
68    "/system/bin com.android.commands.am.Am broadcast -a "
69    "com.google.gservices.intent.action.GSERVICES_OVERRIDE "
70    "-e tycho.enable_ample_logging true"
71]
72
73_TYCHO_SERVER_LAB_OVERRIDE_CMD = (
74    "am broadcast -a com.google.gservices.intent.action.GSERVICES_OVERRIDE -e "
75    "url:tycho_server_endpoint https://android.googleapis.com/nova/nfe/ rewrite"
76    " https://android.googleapis.com/lab/nova/nfe/")
77
78
79class TychoClassId(object):
80    """Tycho Activity/Service Classnames."""
81    # Activities
82    CARRIER_SETUP = 'CarrierSetupEntryPointTrampoline'
83    INIT_ACTIVITY = 'InitActivity'
84    # Services
85    SYNC_SERVICE = 'services.SyncService'
86    ACTIVATE_SUPER_NETWORK_SERVICE = 'services.SuperNetworkConfigurationService'
87
88
89class ActionTypeId(object):
90    """Andorid Action Type to trigger events."""
91    MAIN = 'android.intent.action.MAIN'
92    MASTER_CLEAR_NOTIFICATION = 'android.intent.action.MASTER_CLEAR_NOTIFICATION'
93    TYCHO_ACTIVATE_SUPER_NETWORK = (
94        'com.google.android.apps.tycho.ActionType.ACTIVATE_SUPER_NETWORK')
95
96
97class TelLiveProjectFiTest(TelephonyBaseTest):
98    def setup_class(self):
99        self.activation_attemps = self.user_params.get("activation_attemps", 3)
100
101    def _install_account_util(self, ad):
102        account_util = self.user_params["account_util"]
103        if isinstance(account_util, list):
104            account_util = account_util[0]
105        ad.log.info("Install account_util %s", account_util)
106        ad.ensure_screen_on()
107        ad.adb.install("-r %s" % account_util, timeout=300, ignore_status=True)
108        time.sleep(3)
109        if not ad.is_apk_installed("com.google.android.tradefed.account"):
110            ad.log.info("com.google.android.tradefed.account is not installed")
111            return False
112        return True
113
114    def _account_registration(self, ad):
115        toggle_airplane_mode_by_adb(self.log, ad, new_state=False)
116        for cmd in _TYCHO_VERBOSE_LOGGING_CMDS:
117            ad.adb.shell(cmd)
118        if hasattr(ad, "user_account"):
119            ad.exit_setup_wizard()
120            if not ad.is_apk_installed("com.google.android.tradefed.account"
121                                       ) and self.user_params.get(
122                                           "account_util"):
123                for _ in range(2):
124                    if self._install_account_util(ad):
125                        break
126                else:
127                    ad.log.error(
128                        "Fail to install com.google.android.tradefed.account")
129                    return False
130            ad.force_stop_apk(_TYCHO_PKG)
131            if not ensure_wifi_connected(self.log, ad, self.wifi_network_ssid,
132                                         self.wifi_network_pass):
133                ad.log.error("Failed to connect to wifi")
134                return False
135            ad.log.info("Add google account")
136            if not add_google_account(ad):
137                ad.log.error("Failed to add google account")
138                return False
139            ad.adb.shell(
140                'am instrument -w -e account "%[email protected]" -e password '
141                '"%s" -e sync true -e wait-for-checkin false '
142                'com.google.android.tradefed.account/.AddAccount' %
143                (ad.user_account, ad.user_password))
144            ad.log.info("Enable and activate tycho apk")
145            if not ad.is_apk_installed(_TYCHO_PKG):
146                ad.log.info("%s is not installed", _TYCHO_PKG)
147                return False
148            ad.adb.shell('pm enable %s' % _TYCHO_PKG)
149            # ad.adb.shell(_TYCHO_SERVER_LAB_OVERRIDE_CMD)
150            for i in range(1, self.activation_attemps + 1):
151                if i == self.activation_attemps:
152                    ad.log.info("Reboot and try Fi activation again")
153                    reboot_device(ad)
154                self.activate_fi_account(ad)
155                if not self.check_project_fi_activated(ad):
156                    ad.log.error("Fail to activate Fi account on attempt-%s",
157                                 i)
158                    if i == self.activation_attemps:
159                        return False
160                else:
161                    ad.log.info("Fi account is activated successfully")
162                    break
163        elif "Fi Network" in ad.adb.getprop("gsm.sim.operator.alpha"):
164            ad.log.error("Google account is not provided for Fi Network")
165            return False
166        if not ensure_phone_subscription(self.log, ad):
167            ad.log.error("Unable to find a valid subscription!")
168            return False
169        refresh_droid_config(self.log, ad)
170        return True
171
172    def start_service(self, ad, package, service_id, extras, action_type):
173        """Starts the specified service.
174
175        Args:
176          ad: (android_device.AndroidDevice) device to start activity on
177          package: (str) the package to start the service from
178          service_id: (str) service to start
179          extras: (dict) extras needed to specify with the activity id
180          action_type: The action type id to create the intent
181        """
182        ad.log.info('Starting service %s/.%s.', package, service_id)
183        intent = ad.droid.makeIntent(action_type, None, None, extras,
184                                     ['android.intent.category.DEFAULT'],
185                                     package, package + '.' + service_id,
186                                     _INTENT_FLAGS)
187        ad.droid.startServiceIntent(intent)
188
189    def start_activity(self, ad, package, activity_id, extras=None):
190        """Starts the specified activity.
191
192        Args:
193          ad: (android_device.AndroidDevice) device to start activity on
194          package: (str) the package to start
195          activity_id: (str) activity to start
196          extras: (dict) extras needed to specify with the activity id
197        """
198        ad.log.info('Starting activity %s/.%s.', package, activity_id)
199        intent = ad.droid.makeIntent(ActionTypeId.MAIN, None, None, extras,
200                                     ['android.intent.category.LAUNCHER'],
201                                     package, package + '.' + activity_id,
202                                     _INTENT_FLAGS)
203        ad.droid.startActivityIntent(intent, False)
204
205    def activate_fi_account(self, ad):
206        """Start Tycho InitActivity.
207
208        For in-app Tycho activition (post-SUW tests), Tycho does not
209        automatically trigger OMADM process. This method is used to start
210        Tycho InitActivity before launching super network activation.
211
212        The device will finally stay on Sprint network if everything goes well.
213
214        Args:
215          ad: Android device need to start Tycho InitActivity.
216        """
217        ad.force_stop_apk(_TYCHO_PKG)
218        ad.send_keycode("HOME")
219        extra = {'in_setup_wizard': False, 'force_show_account_chooser': False}
220        self.start_activity(ad, _TYCHO_PKG, TychoClassId.INIT_ACTIVITY, extra)
221        for _ in range(30):
222            ad.send_keycode("WAKEUP")
223            time.sleep(1)
224            current_window = ad.get_my_current_focus_window()
225            log_screen_shot(ad, self.test_name)
226            if ad.adb.shell(
227                    "settings get global device_provisioning_mobile_data"
228            ) != "1":
229                ad.adb.shell(
230                    "settings put global device_provisioning_mobile_data 1")
231            if 'SwitchConfirmDialogActivity' in current_window:
232                ad.log.info("In Switch Confirmation Dialog")
233                if ad.adb.getprop("ro.build.version.release")[0] not in ("8",
234                                                                         "O"):
235                    ad.send_keycode("TAB")
236                ad.send_keycode("TAB")
237                ad.send_keycode("ENTER")
238                time.sleep(10)
239            elif 'tycho.InitActivity' in current_window:
240                ad.log.info("In Tycho InitActivity")
241                ad.send_keycode("TAB")
242                ad.send_keycode("TAB")
243                ad.send_keycode("ENTER")
244                time.sleep(10)
245
246            elif 'tycho.AccountChooserActivity' in current_window:
247                ad.send_keycode("ENTER")
248            else:
249                ad.log.info("Finished activation process")
250                return
251
252    def check_project_fi_activated(self, ad, retries=20):
253        for _ in range(retries):
254            if is_sim_ready(self.log, ad) and (
255                    ad.droid.telephonyGetSimOperatorName() == "Fi Network"):
256                ad.log.info("SIM state is READY, SIM operator is Fi")
257                return True
258            time.sleep(5)
259
260    def start_tycho_activation(self, ad):
261        """Start the Tycho client and register to cellular network.
262
263        Starts Tycho within SUW:
264         - Tycho is expected to follow the in-SUW work flow:
265          - Tycho will perform TychoInit, handshake to server,
266            account configuration, etc
267          - If successful, Tycho will trigger a switch to Sprint Network
268          - If successful, Tycho will start OMA-DM activation sessions
269
270        The device will finally stay on Sprint network if everything goes well.
271
272        Args:
273          ad: Android device need to start Tycho activation.
274        """
275        extra = {'device_setup': True, 'has_account': True}
276        self.start_activity(ad, _TYCHO_PKG, TychoClassId.CARRIER_SETUP, extra)
277
278    def start_super_network_activation(self, ad):
279        """Start the Super-Network activation.
280
281        For in-app Tycho activition (post-SUW tests), this method starts
282        super-network activation after Tycho is initialized.
283
284        The device will finally stay on Sprint network if everything goes well.
285
286        Args:
287          ad: Android device need to start Tycho super network activation.
288        """
289        extra = {'in_setup_wizard': False, 'is_interactive': True}
290        self.start_service(ad, _TYCHO_PKG,
291                           TychoClassId.ACTIVATE_SUPER_NETWORK_SERVICE, extra,
292                           ActionTypeId.TYCHO_ACTIVATE_SUPER_NETWORK)
293
294    def get_active_carrier(self, ad):
295        """Gets the active carrier profile value from the device.
296
297        Args:
298            ad: An AndroidDevice Object.
299
300        Returns:
301            (string) A key from the CARRIER_TO_MCC_MNC map representing the
302            active carrier.
303
304        Raises:
305            KeyError: when an mcc_mnc code reported by the device is not a
306            recognized Fi partner carrier.
307        """
308        mcc_mnc = ad.droid.telephonyGetSimOperator()
309        if not mcc_mnc:
310            return "UNKNOWN"
311        try:
312            return operator_name_from_plmn_id(mcc_mnc)
313        except KeyError:
314            ad.log.error('Unknown Mobile Country Code/Mobile Network Code %s',
315                         mcc_mnc)
316            raise
317
318    def switch_sim(self, ad):
319        """Requests switch between physical sim and esim.
320
321        Args:
322            ad: An AndroidDevice Object.
323            timeout: (optional -- integer) the number of seconds in which a
324                     switch should be completed.
325
326        Raises:
327            Error: whenever a device is not set to the desired carrier within
328                   the timeout window.
329        """
330        old_sim_operator = ad.droid.telephonyGetSimOperatorName()
331        ad.log.info("Before SIM switch, SIM operator = %s", old_sim_operator)
332        send_dialer_secret_code(ad, "794824746")
333        time.sleep(10)
334        new_sim_operator = ad.droid.telephonyGetSimOperatorName()
335        ad.log.info("After SIM switch, SIM operator = %s", new_sim_operator)
336        refresh_droid_config(self.log, ad)
337        return old_sim_operator != new_sim_operator
338
339    def set_active_carrier(self,
340                           ad,
341                           carrier,
342                           timeout=_MAX_WAIT_TIME,
343                           check_interval=10):
344        """Requests an active carrier to be set on the device sim.
345
346        If switching to a different carrier, after the switch is completed
347        auto-switching will be disabled. To re-enable, call enable_auto_switching.
348
349        Args:
350            ad: An AndroidDevice Object.
351            carrier: (carrier_constants.Carrier) Which carrier to switch to.
352            timeout: (optional -- integer) the number of seconds in which a
353                     switch should be completed.
354
355        Raises:
356            Error: whenever a device is not set to the desired carrier within
357                   the timeout window.
358        """
359        # If there's no need to switch, then don't.
360        max_time = timeout
361        while max_time >= 0:
362            if self.is_ready_to_make_carrier_switch(ad):
363                break
364            time.sleep(check_interval)
365            max_time -= check_interval
366        else:
367            ad.log.error("Device stays in carrier switch lock state")
368            return False
369        if carrier == CARRIER_AUTO:
370            send_dialer_secret_code(ad, _CARRIER_DIALER_CODE_LOOKUP[carrier])
371            return True
372        old_carrier = self.get_active_carrier(ad)
373        if carrier == old_carrier:
374            ad.log.info('Already on %s, so no need to switch', carrier)
375            return True
376
377        # Start switch on device, using events to verify that the switch starts.
378        ad.log.info('Initiating unsolicited switch from %s to %s.',
379                    old_carrier, carrier)
380        send_dialer_secret_code(ad, _CARRIER_DIALER_CODE_LOOKUP[carrier])
381        return self.wait_for_carrier_switch_completed(
382            ad, carrier, timeout=timeout, check_interval=check_interval)
383
384    def is_switching_silent(self, ad):
385        """Checks if Tycho switching controller is in silent mode.
386
387        Note that silent mode is a sign of airplane mode, not of a switching lock.
388
389        Args: ad: An AndroidDevice Object.
390
391        Returns:
392            A Boolean True if the preferences file reports True, False otherwise.
393        """
394        return "isInSilentMode\" value=\"true" in ad.adb.shell(
395            "cat %s | grep isInSilentMode" % _SWITCHING_PREF_FILE,
396            ignore_status=True)
397
398    def is_switching_locked(self, ad):
399        """Checks if Tycho switching controller is locked.
400
401        Args: ad: An AndroidDevice Object.
402
403        Returns:
404            A Boolean True if the switching controller is locked for any reason,
405            False otherwise.
406        """
407        return "switchingInProgress\" value=\"true" in ad.adb.shell(
408            "cat %s | grep switchingInProgress" % _SWITCHING_PREF_FILE)
409
410    def is_ready_to_make_carrier_switch(self, ad):
411        """Checks if device is ready to make carrier switch.
412
413        Args:
414            ad: An AndroidDevice Object.
415
416        Returns:
417             A Boolean True if it is ready to make switch, False otherwise.
418        """
419        # Check Tycho switching controller states.
420        if self.is_switching_silent(ad):
421            ad.log.info(
422                "Cannot make carrier switch: SwitchingController is in silent "
423                "mode!")
424            return False
425        if self.is_switching_locked(ad):
426            ad.log.info(
427                "Cannot make carrier switch: SwitchingController is locked!")
428            return False
429        if self.is_carrier_switch_in_progress(ad):
430            ad.log.info("Cannot make carrier switch: Switch in progress!")
431            return False
432        return True
433
434    def is_carrier_switch_in_progress(self, ad):
435        """Checks if Tycho says that a switch is currently in progress.
436
437        Args:
438            ad: An AndroidDevice Object.
439
440        Returns:
441             A Boolean True if the preferences file reports True, False otherwise.
442        """
443        switching_preferences = ad.adb.shell("cat %s" % _SWITCHING_PREF_FILE)
444        return 'InProgress\" value=\"true' in switching_preferences
445
446    def check_network_carrier(self, ad, carrier):
447        current_carrier = self.get_active_carrier(ad)
448        ad.log.info("Current network carrier is %s", current_carrier)
449        is_in_switch = self.is_carrier_switch_in_progress(ad)
450        ad.log.info("Device in carrier switch progress mode")
451        return current_carrier == carrier and is_in_switch
452
453    def wait_for_carrier_switch_completed(self,
454                                          ad,
455                                          carrier,
456                                          timeout=_MAX_WAIT_TIME,
457                                          check_interval=10):
458        """Wait for carrier switch to complete.
459
460        This function waits for a carrier switch to complete by monitoring the
461        Tycho switching controller preference file.
462
463        Args:
464            ad: An Android device object.
465            carrier: The target carrier network to switch to.
466            timeout: (integer) Time wait for switch to complete.
467
468        Return:
469            True or False for successful/unsuccessful switch.
470        """
471        check_args = [ad, carrier]
472        if wait_for_state(self.check_network_carrier, True, check_interval,
473                          timeout, *check_args):
474            ad.log.info("Switched to %s successfully", carrier)
475            ad.send_keycode("ENTER")
476            return True
477        else:
478            active_carrier = self.get_active_carrier(ad)
479            if active_carrier == carrier:
480                ad.log.info("Switched to %s successfully", carrier)
481                return True
482            ad.log.error("Carrier is %s. Fail to switch to %s", active_carrier,
483                         carrier)
484            return False
485
486    def operator_network_switch(self, ad, carrier):
487        if ad.droid.telephonyGetSimOperatorName() == "Fi Network":
488            for i in range(3):
489                if self.set_active_carrier(ad, carrier):
490                    break
491                elif i == 2:
492                    ad.log.error("Failed to switch to %s", carrier)
493                    return False
494        if not ensure_phone_subscription(self.log, ad):
495            ad.log.error("Unable to find a valid subscription!")
496            return False
497        refresh_droid_config(self.log, ad)
498        return True
499
500    def network_switch_test(self, carrier):
501        tasks = [(self.operator_network_switch, [ad, carrier])
502                 for ad in self.android_devices]
503        if not multithread_func(self.log, tasks):
504            abort_all_tests(self.log,
505                            "Unable to switch to network %s" % carrier)
506        return True
507
508    """ Tests Begin """
509
510    @test_tracker_info(uuid="4d92318e-4980-471a-882b-3136c5dda384")
511    @TelephonyBaseTest.tel_test_wrap
512    def test_project_fi_account_activation(self):
513        """Test activate Fi account.
514
515        Returns:
516            True if success.
517            False if failed.
518        """
519        tasks = [(self._account_registration, [ad])
520                 for ad in self.android_devices]
521        try:
522            if not multithread_func(self.log, tasks):
523                abort_all_tests(self.log, "Unable to activate Fi account!")
524        except Exception as e:
525            self.log.error(e)
526            abort_all_tests(self.log, "Unable to activate Fi account!")
527        return True
528
529    @test_tracker_info(uuid="6bfbcc1d-e318-4964-bf36-5b82f086860d")
530    @TelephonyBaseTest.tel_test_wrap
531    def test_switch_to_tmobile_network(self):
532        """Test switch to tmobile network.
533
534        Returns:
535            True if success.
536            False if failed.
537        """
538        return self.network_switch_test(CARRIER_TMO)
539
540    @test_tracker_info(uuid="4f27944d-f3c5-423d-b0c5-5c66dbb98376")
541    @TelephonyBaseTest.tel_test_wrap
542    def test_switch_to_sprint_network(self):
543        """Test switch to tmobile network.
544
545        Returns:
546            True if success.
547            False if failed.
548        """
549        return self.network_switch_test(CARRIER_SPT)
550
551    @test_tracker_info(uuid="5f30c9bd-b79e-4805-aa46-7855ed9023f0")
552    @TelephonyBaseTest.tel_test_wrap
553    def test_switch_to_uscc_network(self):
554        """Test switch to tmobile network.
555
556        Returns:
557            True if success.
558            False if failed.
559        """
560        return self.network_switch_test(CARRIER_USCC)
561
562    @test_tracker_info(uuid="0b062751-d59d-420e-941e-3ffa02aea0d5")
563    @TelephonyBaseTest.tel_test_wrap
564    def test_switch_to_auto_network(self):
565        """Test switch to auto network selection.
566
567        Returns:
568            True if success.
569            False if failed.
570        """
571        return self.network_switch_test(CARRIER_AUTO)
572
573    @test_tracker_info(uuid="13c5f080-69bf-42fd-86ed-c67b1984c347")
574    @TelephonyBaseTest.tel_test_wrap
575    def test_switch_between_sim(self):
576        """Test switch between physical sim and esim.
577
578        Returns:
579            True if success.
580            False if failed.
581        """
582        for ad in self.android_devices:
583            self.switch_sim(ad)
584
585    @test_tracker_info(uuid="")
586    @TelephonyBaseTest.tel_test_wrap
587    def test_remove_google_account(self):
588        for ad in self.android_devices:
589            remove_google_account(ad)
590
591
592""" Tests End """
593