1#!/usr/bin/env python3
2#
3#   Copyright 2020 - 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
17from acts.controllers.android_lib.tel import tel_utils
18from acts.controllers.cellular_lib import BaseCellularDut
19import os
20import time
21
22GET_BUILD_VERSION = 'getprop ro.build.version.release'
23PIXELLOGGER_CONTROL = 'am broadcast -n com.android.pixellogger/.receiver.' \
24                      'AlwaysOnLoggingReceiver -a com.android.pixellogger.' \
25                      'service.logging.LoggingService.' \
26                      'ACTION_CONFIGURE_ALWAYS_ON_LOGGING ' \
27                      '-e intent_key_enable "{}"'
28
29NETWORK_TYPE_TO_BITMASK = {
30    BaseCellularDut.PreferredNetworkType.LTE_ONLY: '01000001000000000000',
31    BaseCellularDut.PreferredNetworkType.NR_LTE: '11000001000000000000',
32    BaseCellularDut.PreferredNetworkType.WCDMA_ONLY: '00000100001110000100',
33}
34
35class AndroidCellularDut(BaseCellularDut.BaseCellularDut):
36    """ Android implementation of the cellular DUT class."""
37    def __init__(self, ad, logger):
38        """ Keeps a handler to the android device.
39
40        Args:
41           ad: Android device handler
42           logger: a handler to the logger object
43        """
44        self.ad = ad
45        self.log = logger
46        logger.info('Initializing Android DUT with baseband version {}'.format(
47            ad.adb.getprop('gsm.version.baseband')))
48
49    def toggle_airplane_mode(self, new_state=True):
50        """ Turns airplane mode on / off.
51
52        Args:
53          new_state: True if airplane mode needs to be enabled.
54        """
55        tel_utils.toggle_airplane_mode_by_adb(self.log, self.ad, new_state)
56
57    def toggle_data_roaming(self, new_state=True):
58        """ Enables or disables cellular data roaming.
59
60        Args:
61          new_state: True if data roaming needs to be enabled.
62        """
63        tel_utils.toggle_cell_data_roaming(self.ad, new_state)
64
65    def get_rx_tx_power_levels(self):
66        """ Obtains Rx and Tx power levels measured from the DUT.
67
68        Returns:
69            A tuple where the first element is an array with the RSRP value
70            in each Rx chain, and the second element is the Tx power in dBm.
71            Values for invalid or disabled Rx / Tx chains are set to None.
72        """
73        return tel_utils.get_rx_tx_power_levels(self.log, self.ad)
74
75    def set_apn(self, name, apn, type='default'):
76        """ Sets the Access Point Name.
77
78        Args:
79          name: the APN name
80          apn: the APN
81          type: the APN type
82        """
83        self.ad.droid.telephonySetAPN(name, apn, type)
84
85    def set_preferred_network_type(self, type):
86        """ Sets the preferred RAT.
87
88        Args:
89          type: an instance of class PreferredNetworkType
90        """
91
92        self.log.info('setting preferred network type: {}'.format(type))
93        # If android version is S or later, uses bit mask to set and return.
94        version = self.ad.adb.shell(GET_BUILD_VERSION)
95        self.log.info('The android version is {}'.format(version))
96        try:
97            version_in_number = int(version)
98            if version_in_number > 11:
99                base_cmd = 'cmd phone set-allowed-network-types-for-users -s 0 '
100                set_network_cmd = base_cmd + NETWORK_TYPE_TO_BITMASK[type]
101                self.ad.adb.shell(set_network_cmd)
102                get_network_cmd = ('cmd phone '
103                                   'get-allowed-network-types-for-users -s 0')
104                allowed_network = self.ad.adb.shell(get_network_cmd)
105                self.log.info('The allowed network: {}'.format(allowed_network))
106                return
107        except ValueError:
108            self.log.info('The android version is older than S, use sl4a')
109
110        if type == BaseCellularDut.PreferredNetworkType.LTE_ONLY:
111            formatted_type = tel_utils.NETWORK_MODE_LTE_ONLY
112        elif type == BaseCellularDut.PreferredNetworkType.WCDMA_ONLY:
113            formatted_type = tel_utils.NETWORK_MODE_WCDMA_ONLY
114        elif type == BaseCellularDut.PreferredNetworkType.GSM_ONLY:
115            formatted_type = tel_utils.NETWORK_MODE_GSM_ONLY
116        else:
117            raise ValueError('Invalid RAT type.')
118
119        if not self.ad.droid.telephonySetPreferredNetworkTypesForSubscription(
120                formatted_type, self.ad.droid.subscriptionGetDefaultSubId()):
121            self.log.error("Could not set preferred network type.")
122        else:
123            self.log.info("Preferred network type set.")
124
125    def get_telephony_signal_strength(self):
126        """ Wrapper for the method with the same name in tel_utils.
127
128        Will be deprecated and replaced by get_rx_tx_power_levels. """
129        tel_utils.get_telephony_signal_strength(self.ad)
130
131    def start_modem_logging(self):
132        """ Starts on-device log collection. """
133        self.ad.adb.shell('rm /data/vendor/slog/*.* -f')
134        self.ad.adb.shell(PIXELLOGGER_CONTROL.format('true'))
135
136    def stop_modem_logging(self):
137        """ Stops log collection and pulls logs. """
138        output_path = self.ad.device_log_path + '/modem/'
139        os.makedirs(output_path, exist_ok=True)
140        self.ad.adb.shell(PIXELLOGGER_CONTROL.format('false'))
141
142    def toggle_data(self, new_state=True):
143        """ Turns on/off of the cellular data.
144
145        Args:
146            new_state: True to enable cellular data
147        """
148        self.log.info('Toggles cellular data on: {}'.format(new_state))
149        if new_state:
150            self.ad.adb.shell('settings put global mobile_data 1')
151            self.ad.adb.shell('svc data enable')
152            time.sleep(5)
153            self.log.info('global mobile data: {}'.format(
154                self.ad.adb.shell('settings get global mobile_data')))
155        else:
156            self.ad.adb.shell('settings put global mobile_data 0')
157            self.ad.adb.shell('svc data disable')
158            self.log.info('global mobile data: {}'.format(
159                self.ad.adb.shell('settings get global mobile_data')))
160