Merge "le advertisement address type settings api SL4A tests"
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
\ No newline at end of file
diff --git a/acts/framework/acts/controllers/OWNERS b/acts/framework/acts/controllers/OWNERS
index 64922ab..c4ba954 100644
--- a/acts/framework/acts/controllers/OWNERS
+++ b/acts/framework/acts/controllers/OWNERS
@@ -1,5 +1,5 @@
per-file asus_axe11000_ap.py = martschneider@google.com
-per-file fuchsia_device.py = chcl@google.com, dhobsd@google.com, haydennix@google.com, jmbrenna@google.com, mnck@google.com, silberst@google.com, tturney@google.com
+per-file fuchsia_device.py = chcl@google.com, dhobsd@google.com, haydennix@google.com, jmbrenna@google.com, mnck@google.com, silberst@google.com, tturney@google.com, sbalana@google.com
per-file bluetooth_pts_device.py = tturney@google.com
per-file cellular_simulator.py = iguarna@google.com, chaoyangf@google.com, codycaldwell@google.com, yixiang@google.com
per-file openwrt_ap.py = jerrypcchen@google.com, martschneider@google.com, gmoturu@google.com, sishichen@google.com
diff --git a/acts/framework/acts/controllers/access_point.py b/acts/framework/acts/controllers/access_point.py
index 21e26bb..a2f2840 100755
--- a/acts/framework/acts/controllers/access_point.py
+++ b/acts/framework/acts/controllers/access_point.py
@@ -185,15 +185,14 @@
ssh_settings: The ssh settings being used by the ssh connection.
dhcp_settings: The dhcp server settings being used.
"""
-
def __init__(self, configs):
"""
Args:
configs: configs for the access point from config file.
"""
self.ssh_settings = settings.from_config(configs['ssh_config'])
- self.log = logger.create_logger(lambda msg: '[Access Point|%s] %s' % (
- self.ssh_settings.hostname, msg))
+ self.log = logger.create_logger(lambda msg: '[Access Point|%s] %s' %
+ (self.ssh_settings.hostname, msg))
self.device_pdu_config = configs.get('PduDevice', None)
self.identifier = self.ssh_settings.hostname
@@ -429,11 +428,25 @@
def get_dhcp_logs(self):
"""Get DHCP logs for this AP object.
- This allows consumers of the access point objects validate DHCP
+ This allows consumers of the access point objects to validate DHCP
behavior.
"""
return self._dhcp.get_logs()
+ def get_hostapd_logs(self):
+ """Get hostapd logs for all interfaces on AP object.
+
+ This allows consumers of the access point objects to validate hostapd
+ behavior.
+
+ Returns: A dict with {interface: log} from hostapd instances.
+ """
+ hostapd_logs = dict()
+ for identifier in self._aps:
+ hostapd_logs[identifier] = self._aps.get(
+ identifier).hostapd.pull_logs()
+ return hostapd_logs
+
def start_nat(self):
"""Start NAT on the AP.
diff --git a/acts/framework/acts/controllers/android_device.py b/acts/framework/acts/controllers/android_device.py
index 7060b86..793cb23 100755
--- a/acts/framework/acts/controllers/android_device.py
+++ b/acts/framework/acts/controllers/android_device.py
@@ -48,6 +48,10 @@
ACTS_CONTROLLER_REFERENCE_NAME = "android_devices"
ANDROID_DEVICE_PICK_ALL_TOKEN = "*"
+# Key name for SL4A extra params in config file
+ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY = "sl4a_client_port"
+ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY = "sl4a_forwarded_port"
+ANDROID_DEVICE_SL4A_SERVER_PORT_KEY = "sl4a_server_port"
# Key name for adb logcat extra params in config file.
ANDROID_DEVICE_ADB_LOGCAT_PARAM_KEY = "adb_logcat_param"
ANDROID_DEVICE_EMPTY_CONFIG_MSG = "Configuration is empty, abort!"
@@ -235,12 +239,41 @@
raise errors.AndroidDeviceConfigError(
"Required value 'serial' is missing in AndroidDevice config %s."
% c)
+ client_port = 0
+ if ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY in c:
+ try:
+ client_port = int(c.pop(ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY))
+ except ValueError:
+ raise errors.AndroidDeviceConfigError(
+ "'%s' is not a valid number for config %s" %
+ (ANDROID_DEVICE_SL4A_CLIENT_PORT_KEY, c))
+ server_port = None
+ if ANDROID_DEVICE_SL4A_SERVER_PORT_KEY in c:
+ try:
+ server_port = int(c.pop(ANDROID_DEVICE_SL4A_SERVER_PORT_KEY))
+ except ValueError:
+ raise errors.AndroidDeviceConfigError(
+ "'%s' is not a valid number for config %s" %
+ (ANDROID_DEVICE_SL4A_SERVER_PORT_KEY, c))
+ forwarded_port = 0
+ if ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY in c:
+ try:
+ forwarded_port = int(
+ c.pop(ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY))
+ except ValueError:
+ raise errors.AndroidDeviceConfigError(
+ "'%s' is not a valid number for config %s" %
+ (ANDROID_DEVICE_SL4A_FORWARDED_PORT_KEY, c))
ssh_config = c.pop('ssh_config', None)
ssh_connection = None
if ssh_config is not None:
ssh_settings = settings.from_config(ssh_config)
ssh_connection = connection.SshConnection(ssh_settings)
- ad = AndroidDevice(serial, ssh_connection=ssh_connection)
+ ad = AndroidDevice(serial,
+ ssh_connection=ssh_connection,
+ client_port=client_port,
+ forwarded_port=forwarded_port,
+ server_port=server_port)
ad.load_config(c)
results.append(ad)
return results
@@ -360,14 +393,27 @@
adb: An AdbProxy object used for interacting with the device via adb.
fastboot: A FastbootProxy object used for interacting with the device
via fastboot.
+ client_port: Preferred client port number on the PC host side for SL4A
+ forwarded_port: Preferred server port number forwarded from Android
+ to the host PC via adb for SL4A connections
+ server_port: Preferred server port used by SL4A on Android device
+
"""
- def __init__(self, serial='', ssh_connection=None):
+ def __init__(self,
+ serial='',
+ ssh_connection=None,
+ client_port=0,
+ forwarded_port=0,
+ server_port=None):
self.serial = serial
# logging.log_path only exists when this is used in an ACTS test run.
log_path_base = getattr(logging, 'log_path', '/tmp/logs')
self.log_dir = 'AndroidDevice%s' % serial
self.log_path = os.path.join(log_path_base, self.log_dir)
+ self.client_port = client_port
+ self.forwarded_port = forwarded_port
+ self.server_port = server_port
self.log = tracelogger.TraceLogger(
AndroidDeviceLoggerAdapter(logging.getLogger(),
{'serial': serial}))
@@ -377,8 +423,8 @@
self.register_service(services.Sl4aService(self))
self.adb_logcat_process = None
self.adb = adb.AdbProxy(serial, ssh_connection=ssh_connection)
- self.fastboot = fastboot.FastbootProxy(
- serial, ssh_connection=ssh_connection)
+ self.fastboot = fastboot.FastbootProxy(serial,
+ ssh_connection=ssh_connection)
if not self.is_bootloader:
self.root_adb()
self._ssh_connection = ssh_connection
@@ -402,6 +448,34 @@
if self._ssh_connection:
self._ssh_connection.close()
+ def recreate_services(self, serial):
+ """Clean up the AndroidDevice object and re-create adb/sl4a services.
+
+ Unregister the existing services and re-create adb and sl4a services,
+ call this method when the connection break after certain API call
+ (e.g., enable USB tethering by #startTethering)
+
+ Args:
+ serial: the serial number of the AndroidDevice
+ """
+ # Clean the old services
+ for service in self._services:
+ service.unregister()
+ self._services.clear()
+ if self._ssh_connection:
+ self._ssh_connection.close()
+ self._sl4a_manager.stop_service()
+
+ # Wait for old services to stop
+ time.sleep(5)
+
+ # Re-create the new adb and sl4a services
+ self.register_service(services.AdbLogcatService(self))
+ self.register_service(services.Sl4aService(self))
+ self.adb.wait_for_device()
+ self.terminate_all_sessions()
+ self.start_services()
+
def register_service(self, service):
"""Registers the service on the device. """
service.register()
@@ -428,8 +502,8 @@
Stop adb logcat and terminate sl4a sessions if exist.
"""
- event_bus.post(
- android_events.AndroidStopServicesEvent(self), ignore_errors=True)
+ event_bus.post(android_events.AndroidStopServicesEvent(self),
+ ignore_errors=True)
def is_connected(self):
out = self.adb.devices()
@@ -654,7 +728,13 @@
>>> ad = AndroidDevice()
>>> droid, ed = ad.get_droid()
"""
- session = self._sl4a_manager.create_session()
+ self.log.debug(
+ "Creating RPC client_port={}, forwarded_port={}, server_port={}".
+ format(self.client_port, self.forwarded_port, self.server_port))
+ session = self._sl4a_manager.create_session(
+ client_port=self.client_port,
+ forwarded_port=self.forwarded_port,
+ server_port=self.server_port)
droid = session.rpc_client
if handle_event:
ed = session.get_event_dispatcher()
@@ -674,9 +754,8 @@
"""
for cmd in ("ps -A", "ps"):
try:
- out = self.adb.shell(
- '%s | grep "S %s"' % (cmd, package_name),
- ignore_status=True)
+ out = self.adb.shell('%s | grep "S %s"' % (cmd, package_name),
+ ignore_status=True)
if package_name not in out:
continue
try:
@@ -768,10 +847,10 @@
return adb_excerpt_path
def search_logcat(self,
- matching_string,
- begin_time=None,
- end_time=None,
- logcat_path=None):
+ matching_string,
+ begin_time=None,
+ end_time=None,
+ logcat_path=None):
"""Search logcat message with given string.
Args:
@@ -801,13 +880,12 @@
"""
if not logcat_path:
logcat_path = os.path.join(self.device_log_path,
- 'adblog_%s_debug.txt' % self.serial)
+ 'adblog_%s_debug.txt' % self.serial)
if not os.path.exists(logcat_path):
self.log.warning("Logcat file %s does not exist." % logcat_path)
return
- output = job.run(
- "grep '%s' %s" % (matching_string, logcat_path),
- ignore_status=True)
+ output = job.run("grep '%s' %s" % (matching_string, logcat_path),
+ ignore_status=True)
if not output.stdout or output.exit_status != 0:
return []
if begin_time:
@@ -815,13 +893,13 @@
log_begin_time = acts_logger.epoch_to_log_line_timestamp(
begin_time)
begin_time = datetime.strptime(log_begin_time,
- "%Y-%m-%d %H:%M:%S.%f")
+ "%Y-%m-%d %H:%M:%S.%f")
if end_time:
if not isinstance(end_time, datetime):
log_end_time = acts_logger.epoch_to_log_line_timestamp(
end_time)
end_time = datetime.strptime(log_end_time,
- "%Y-%m-%d %H:%M:%S.%f")
+ "%Y-%m-%d %H:%M:%S.%f")
result = []
logs = re.findall(r'(\S+\s\S+)(.*)', output.stdout)
for log in logs:
@@ -893,8 +971,8 @@
Returns:
Linux UID for the apk.
"""
- output = self.adb.shell(
- "dumpsys package %s | grep userId=" % apk_name, ignore_status=True)
+ output = self.adb.shell("dumpsys package %s | grep userId=" % apk_name,
+ ignore_status=True)
result = re.search(r"userId=(\d+)", output)
if result:
return result.group(1)
@@ -960,9 +1038,8 @@
"""
for cmd in ("ps -A", "ps"):
try:
- out = self.adb.shell(
- '%s | grep "S %s"' % (cmd, package_name),
- ignore_status=True)
+ out = self.adb.shell('%s | grep "S %s"' % (cmd, package_name),
+ ignore_status=True)
if package_name in out:
self.log.info("apk %s is running", package_name)
return True
@@ -987,8 +1064,8 @@
True if package is installed. False otherwise.
"""
try:
- self.adb.shell(
- 'am force-stop %s' % package_name, ignore_status=True)
+ self.adb.shell('am force-stop %s' % package_name,
+ ignore_status=True)
except Exception as e:
self.log.warning("Fail to stop package %s: %s", package_name, e)
@@ -1029,8 +1106,8 @@
br_out_path = out.split(':')[1].strip().split()[0]
self.adb.pull("%s %s" % (br_out_path, full_out_path))
else:
- self.adb.bugreport(
- " > {}".format(full_out_path), timeout=BUG_REPORT_TIMEOUT)
+ self.adb.bugreport(" > {}".format(full_out_path),
+ timeout=BUG_REPORT_TIMEOUT)
self.log.info("Bugreport for %s taken at %s.", test_name,
full_out_path)
self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT)
@@ -1092,10 +1169,10 @@
if not host_path:
host_path = self.log_path
for device_path in device_paths:
- self.log.info(
- 'Pull from device: %s -> %s' % (device_path, host_path))
- self.adb.pull(
- "%s %s" % (device_path, host_path), timeout=PULL_TIMEOUT)
+ self.log.info('Pull from device: %s -> %s' %
+ (device_path, host_path))
+ self.adb.pull("%s %s" % (device_path, host_path),
+ timeout=PULL_TIMEOUT)
def check_crash_report(self,
test_name=None,
@@ -1110,10 +1187,9 @@
except Exception as e:
self.log.debug("received exception %s", e)
continue
- crashes = self.get_file_names(
- crash_path,
- skip_files=CRASH_REPORT_SKIPS,
- begin_time=begin_time)
+ crashes = self.get_file_names(crash_path,
+ skip_files=CRASH_REPORT_SKIPS,
+ begin_time=begin_time)
if crash_path == "/data/tombstones/" and crashes:
tombstones = crashes[:]
for tombstone in tombstones:
@@ -1136,8 +1212,9 @@
# Sleep 10 seconds for the buffered log to be written in qxdm log file
time.sleep(10)
log_path = getattr(self, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
- qxdm_logs = self.get_file_names(
- log_path, begin_time=begin_time, match_string="*.qmdl")
+ qxdm_logs = self.get_file_names(log_path,
+ begin_time=begin_time,
+ match_string="*.qmdl")
if qxdm_logs:
qxdm_log_path = os.path.join(self.device_log_path,
"QXDM_%s" % self.serial)
@@ -1146,10 +1223,9 @@
self.log.info("Pull QXDM Log %s to %s", qxdm_logs, qxdm_log_path)
self.pull_files(qxdm_logs, qxdm_log_path)
- self.adb.pull(
- "/firmware/image/qdsp6m.qdb %s" % qxdm_log_path,
- timeout=PULL_TIMEOUT,
- ignore_status=True)
+ self.adb.pull("/firmware/image/qdsp6m.qdb %s" % qxdm_log_path,
+ timeout=PULL_TIMEOUT,
+ ignore_status=True)
# Zip Folder
utils.zip_directory('%s.zip' % qxdm_log_path, qxdm_log_path)
shutil.rmtree(qxdm_log_path)
@@ -1176,8 +1252,9 @@
]
sdm_logs = []
for path in log_paths:
- sdm_logs += self.get_file_names(
- path, begin_time=begin_time, match_string="*.sdm*")
+ sdm_logs += self.get_file_names(path,
+ begin_time=begin_time,
+ match_string="*.sdm*")
if sdm_logs:
sdm_log_path = os.path.join(self.device_log_path,
"SDM_%s" % self.serial)
@@ -1263,8 +1340,8 @@
status: true if iperf client start successfully.
results: results have data flow information
"""
- out = self.adb.shell(
- "iperf3 -c {} {}".format(server_host, extra_args), timeout=timeout)
+ out = self.adb.shell("iperf3 -c {} {}".format(server_host, extra_args),
+ timeout=timeout)
clean_out = out.split('\n')
if "error" in clean_out[0].lower():
return False, clean_out
@@ -1315,7 +1392,9 @@
'Device %s booting process timed out.' % self.serial,
serial=self.serial)
- def reboot(self, stop_at_lock_screen=False, timeout=180,
+ def reboot(self,
+ stop_at_lock_screen=False,
+ timeout=180,
wait_after_reboot_complete=1):
"""Reboots the device.
@@ -1352,8 +1431,8 @@
# want the device to be missing to prove the device has kicked
# off the reboot.
break
- self.wait_for_boot_completion(
- timeout=(timeout - time.time() + timeout_start))
+ self.wait_for_boot_completion(timeout=(timeout - time.time() +
+ timeout_start))
self.log.debug('Wait for a while after boot completion.')
time.sleep(wait_after_reboot_complete)
@@ -1388,8 +1467,8 @@
break
except adb.AdbError as e:
if timer + 1 == timeout:
- self.log.warning(
- 'Unable to find IP address for %s.' % interface)
+ self.log.warning('Unable to find IP address for %s.' %
+ interface)
return None
else:
time.sleep(1)
@@ -1454,7 +1533,7 @@
for cmd in dumpsys_cmd:
output = self.adb.shell(cmd, ignore_status=True)
if not output or "not found" in output or "Can't find" in output or (
- "mFocusedApp=null" in output):
+ "mFocusedApp=null" in output):
result = ''
else:
result = output.split(' ')[-2]
@@ -1603,11 +1682,11 @@
return
if not self.is_user_setup_complete() or self.is_setupwizard_on():
# b/116709539 need this to prevent reboot after skip setup wizard
- self.adb.shell(
- "am start -a com.android.setupwizard.EXIT", ignore_status=True)
- self.adb.shell(
- "pm disable %s" % self.get_setupwizard_package_name(),
- ignore_status=True)
+ self.adb.shell("am start -a com.android.setupwizard.EXIT",
+ ignore_status=True)
+ self.adb.shell("pm disable %s" %
+ self.get_setupwizard_package_name(),
+ ignore_status=True)
# Wait up to 5 seconds for user_setup_complete to be updated
end_time = time.time() + 5
while time.time() < end_time:
@@ -1657,8 +1736,8 @@
try:
self.ensure_verity_disabled()
self.adb.remount()
- out = self.adb.push(
- '%s %s' % (src_file_path, dst_file_path), timeout=push_timeout)
+ out = self.adb.push('%s %s' % (src_file_path, dst_file_path),
+ timeout=push_timeout)
if 'error' in out:
self.log.error('Unable to push system file %s to %s due to %s',
src_file_path, dst_file_path, out)
diff --git a/acts/framework/acts/controllers/asus_axe11000_ap.py b/acts/framework/acts/controllers/asus_axe11000_ap.py
index d19af3b..c549d6e 100644
--- a/acts/framework/acts/controllers/asus_axe11000_ap.py
+++ b/acts/framework/acts/controllers/asus_axe11000_ap.py
@@ -246,7 +246,7 @@
BAND_2G_RAD_PORT).get_attribute("value")
dict_2g["radius_secret"] = self.driver.find_element_by_name(
BAND_2G_RAD_KEY).get_attribute("value")
- channel_field = self._get_webdriver_elements_for_channels(band)
+ channel_field = self._get_webdriver_elements_for_channels("2g")
ch_val = self.driver.find_element_by_name(channel_field).get_attribute(
"value")
channel = 0
@@ -282,9 +282,9 @@
BAND_5G_RAD_IP).get_attribute("value")
dict_5g["radius_port"] = self.driver.find_element_by_name(
BAND_5G_RAD_PORT).get_attribute("value")
- dict_2g["radius_secret"] = self.driver.find_element_by_name(
+ dict_5g["radius_secret"] = self.driver.find_element_by_name(
BAND_5G_RAD_KEY).get_attribute("value")
- channel_field = self._get_webdriver_elements_for_channels(band)
+ channel_field = self._get_webdriver_elements_for_channels("5g")
ch_val = self.driver.find_element_by_name(channel_field).get_attribute(
"value")
channel = 0
@@ -312,7 +312,7 @@
if dict_6g["security"] == "sae":
dict_6g["password"] = self.driver.find_element_by_name(
BAND_6G_PSK).get_attribute("value")
- channel_field = self._get_webdriver_elements_for_channels(band)
+ channel_field = self._get_webdriver_elements_for_channels("6g")
ch_val = self.driver.find_element_by_name(channel_field).get_attribute(
"value")
channel = 0
diff --git a/acts/framework/acts/controllers/fuchsia_device.py b/acts/framework/acts/controllers/fuchsia_device.py
index 86b8423..59abec3 100644
--- a/acts/framework/acts/controllers/fuchsia_device.py
+++ b/acts/framework/acts/controllers/fuchsia_device.py
@@ -55,6 +55,7 @@
from acts.controllers.fuchsia_lib.logging_lib import FuchsiaLoggingLib
from acts.controllers.fuchsia_lib.netstack.netstack_lib import FuchsiaNetstackLib
from acts.controllers.fuchsia_lib.ram_lib import FuchsiaRamLib
+from acts.controllers.fuchsia_lib.session_manager_lib import FuchsiaSessionManagerLib
from acts.controllers.fuchsia_lib.syslog_lib import FuchsiaSyslogError
from acts.controllers.fuchsia_lib.syslog_lib import start_syslog
from acts.controllers.fuchsia_lib.sysinfo_lib import FuchsiaSysInfoLib
@@ -219,6 +220,7 @@
self.sl4f_port = fd_conf_data.get("sl4f_port", 80)
self.ssh_port = fd_conf_data.get("ssh_port", 22)
self.ssh_config = fd_conf_data.get("ssh_config", None)
+ self.ssh_priv_key = fd_conf_data.get("ssh_priv_key", None)
self.authorized_file = fd_conf_data.get("authorized_file_loc", None)
self.serial_number = fd_conf_data.get("serial_number", None)
self.device_type = fd_conf_data.get("device_type", None)
@@ -228,6 +230,8 @@
self.build_type = fd_conf_data.get("build_type", None)
self.server_path = fd_conf_data.get("server_path", None)
self.specific_image = fd_conf_data.get("specific_image", None)
+ self.ffx_binary_path = fd_conf_data.get("ffx_binary_path", None)
+ self.mdns_name = fd_conf_data.get("mdns_name", None)
# Instead of the input ssh_config, a new config is generated with proper
# ControlPath to the test output directory.
@@ -281,6 +285,9 @@
else:
time.sleep(1)
if mdns_ip and utils.is_valid_ipv6_address(mdns_ip):
+ # self.ip was actually an mdns name. Use it for self.mdns_name
+ # unless one was explicitly provided.
+ self.mdns_name = self.mdns_name or self.ip
self.ip = mdns_ip
self.address = "http://[{}]:{}".format(self.ip, self.sl4f_port)
else:
@@ -318,11 +325,12 @@
self.teardown_commands = fd_conf_data.get('teardown_commands', [])
try:
+ self.init_ffx_connection()
self.run_commands_from_config(self.setup_commands)
- except FuchsiaDeviceError:
+ except Exception as e:
# Prevent a threading error, since controller isn't fully up yet.
self.clean_up()
- raise FuchsiaDeviceError('Failed to run setup commands.')
+ raise e
def _set_control_path_config(self, old_config, new_config):
"""Given an input ssh_config, write to a new config with proper
@@ -438,6 +446,9 @@
self.sysinfo_lib = FuchsiaSysInfoLib(self.address, self.test_counter,
self.client_id)
+ # Grab commands from FuchsiaSessionManagerLib
+ self.session_manager_lib = FuchsiaSessionManagerLib(self)
+
# Grabs command from FuchsiaWlanDeprecatedConfigurationLib
self.wlan_deprecated_configuration_lib = (
FuchsiaWlanDeprecatedConfigurationLib(self.address,
@@ -486,6 +497,58 @@
requests.get(url=self.init_address, data=init_data)
self.test_counter += 1
+ def init_ffx_connection(self):
+ """Initializes ffx's connection to the device."""
+ self.log.debug("Initializing ffx connection")
+
+ # ffx looks for the private key in several default locations. For testbeds
+ # which have the private key in another location, set it now.
+ if self.ssh_priv_key:
+ self.ffx_command(f"config set ssh.priv {self.ssh_priv_key}")
+
+ # Wait for the device to be available. If the device isn't available within
+ # a short time (e.g. 5 seconds), log a warning before waiting longer.
+ try:
+ self.ffx_command("target wait", timeout_sec=5)
+ except job.TimeoutError as e:
+ longer_wait_sec = 60
+ self.log.info(
+ "Device is not immediately available via ffx." +
+ f" Waiting up to {longer_wait_sec} seconds for device to be reachable."
+ )
+ self.ffx_command("target wait", timeout_sec=longer_wait_sec)
+
+ # Test actual connectivity to the device by getting device information.
+ # Use a shorter timeout than default because this command can hang for
+ # a long time if the device is not actually connectable.
+ try:
+ result = self.ffx_command("target show --json", timeout_sec=15)
+ except Exception as e:
+ self.log.error(
+ f'Failed to reach target device. Try running "{self.ffx_binary_path}'
+ + ' doctor" to diagnose issues.')
+ raise e
+
+ # Compare the device's version to the ffx version
+ result_json = json.loads(result.stdout)
+ build_info = next(
+ filter(lambda s: s.get('label') == 'build', result_json))
+ version_info = next(
+ filter(lambda s: s.get('label') == 'version', build_info['child']))
+ device_version = version_info.get('value')
+ ffx_version = self.ffx_command("version").stdout
+
+ if not getattr(self, '_have_logged_ffx_version', False):
+ self._have_logged_ffx_version = True
+ self.log.info(
+ f"Device version: {device_version}, ffx version: {ffx_version}"
+ )
+ if device_version != ffx_version:
+ self.log.warning(
+ "ffx versions that differ from device versions may" +
+ " have compatibility issues. It is recommended to" +
+ " use versions within 6 weeks of each other.")
+
def run_commands_from_config(self, cmd_dicts):
"""Runs commands on the Fuchsia device from the config file. Useful for
device and/or Fuchsia specific configuration.
@@ -701,6 +764,7 @@
'SL4F.')
self.start_services()
self.init_server_connection()
+ self.init_ffx_connection()
raise ConnectionError('Device never went down.')
self.log.info('Device is unreachable as expected.')
if reboot_type == FUCHSIA_REBOOT_TYPE_HARD:
@@ -746,6 +810,7 @@
'Initiating connection to SL4F and verifying commands can run.')
try:
self.init_server_connection()
+ self.init_ffx_connection()
self.hwinfo_lib.getDeviceInfo()
except Exception as err:
raise ConnectionError(
@@ -1285,6 +1350,56 @@
bt_snoop_file.write(bt_snoop_data)
bt_snoop_file.close()
+ def ffx_command(self,
+ command,
+ timeout_sec=FUCHSIA_DEFAULT_COMMAND_TIMEOUT,
+ skip_status_code_check=False):
+ """Runs an ffx command.
+
+ Args:
+ command: string, command to run with ffx.
+ timeout_sec: Seconds to wait for a command to complete.
+ skip_status_code_check: Whether to check for the status code.
+
+ Raises:
+ ValueError: if necessary attributes are not set.
+ job.TimeoutError: when the command times out.
+ Error: when the command returns non-zero and skip_status_code_check is False.
+ FuchsiaDeviceError: when stderr has contents and skip_status_code_check is False.
+
+ Returns:
+ A job.Result object containing the results of the command.
+ """
+ if not self.ffx_binary_path:
+ raise ValueError(
+ 'Must provide "ffx_binary_path: path_to_ffx" in the device config'
+ )
+ if not self.mdns_name:
+ raise ValueError(
+ 'Must provide "mdns_name: device_MDNS_name" in the device config'
+ )
+
+ self.log.debug(f'Running "ffx {command}".')
+
+ full_command = f'{self.ffx_binary_path} --target {self.mdns_name} {command}'
+ result = job.run(command=full_command,
+ timeout=timeout_sec,
+ ignore_status=skip_status_code_check)
+
+ if isinstance(result, Exception):
+ raise result
+
+ elif not skip_status_code_check and result.stderr:
+ self.log.warning(
+ f'Ran "{full_command}", exit status {result.exit_status}')
+ self.log.warning(f'stdout: {result.stdout}')
+ self.log.warning(f'stderr: {result.stderr}')
+
+ raise FuchsiaDeviceError(
+ f'Error when running "{full_command}": {result.stderr}')
+
+ return result
+
class FuchsiaDeviceLoggerAdapter(logging.LoggerAdapter):
def process(self, msg, kwargs):
diff --git a/acts/framework/acts/controllers/fuchsia_lib/OWNERS b/acts/framework/acts/controllers/fuchsia_lib/OWNERS
index 0bc23b3..febd4ad 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/OWNERS
+++ b/acts/framework/acts/controllers/fuchsia_lib/OWNERS
@@ -5,3 +5,4 @@
mnck@google.com
silberst@google.com
tturney@google.com
+sbalana@google.com
diff --git a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py
index 1d202c6..d50f726 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_controller.py
@@ -111,7 +111,12 @@
net_ifaces = self.device.netstack_controller.list_interfaces()
wlan_ifaces_by_role = {'client': {}, 'ap': {}}
for iface in net_ifaces:
- iface_mac = utils.mac_address_list_to_str(iface['mac'])
+ try:
+ # Some interfaces might not have a MAC
+ iface_mac = utils.mac_address_list_to_str(iface['mac'])
+ except Exception as e:
+ self.log.debug(f'Error {e} getting MAC for iface {iface}')
+ continue
if iface_mac in wlan_ifaces_by_mac:
wlan_ifaces_by_mac[iface_mac]['netstack_id'] = iface['id']
diff --git a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py
index ab2773d..7fe7aa3 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/lib_controllers/wlan_policy_controller.py
@@ -20,6 +20,10 @@
from acts import logger
from acts import signals
+import typing
+if typing.TYPE_CHECKING:
+ from acts.controllers.fuchsia_device import FuchsiaDevice
+
SAVED_NETWORKS = "saved_networks"
CLIENT_STATE = "client_connections_state"
CONNECTIONS_ENABLED = "ConnectionsEnabled"
@@ -41,12 +45,13 @@
"""
def __init__(self, fuchsia_device):
- self.device = fuchsia_device
+ self.device: FuchsiaDevice = fuchsia_device
self.log = logger.create_tagged_trace_logger(
'WlanPolicyController for FuchsiaDevice | %s' % self.device.ip)
self.client_controller = False
self.preserved_networks_and_client_state = None
self.policy_configured = False
+ self._paused_session = False
def _configure_wlan(self, preserve_saved_networks, timeout=15):
"""Sets up wlan policy layer.
@@ -57,7 +62,7 @@
"""
end_time = time.time() + timeout
- # Kill basemgr
+ # Kill basemgr (Component v1 version of session manager)
while time.time() < end_time:
response = self.device.basemgr_lib.killBasemgr()
if not response.get('error'):
@@ -69,6 +74,16 @@
raise WlanPolicyControllerError(
'Failed to issue successful basemgr kill call.')
+ # Stop the session manager, which also holds the Policy controller.
+ response = self.device.session_manager_lib.pauseSession()
+ if response.get('error'):
+ self.log.error('Failed to stop the session.')
+ raise WlanPolicyControllerError(response['error'])
+ else:
+ if response.get('result') == 'Success':
+ self._paused_session = True
+ self.log.debug(f"Paused session: {response.get('result')}")
+
# Acquire control of policy layer
while time.time() < end_time:
# Create a client controller
@@ -114,6 +129,13 @@
if not self.policy_configured:
self._configure_wlan()
self.restore_preserved_networks_and_client_state()
+ if self._paused_session:
+ response = self.device.session_manager_lib.resumeSession()
+ if response.get('error'):
+ self.log.warning('Failed to resume the session.')
+ self.log.warning(response['error'])
+ else:
+ self.log.debug(f"Resumed session: {response.get('result')}")
def start_client_connections(self):
"""Allow device to connect to networks via policy layer (including
diff --git a/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py b/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py
new file mode 100644
index 0000000..2593dde
--- /dev/null
+++ b/acts/framework/acts/controllers/fuchsia_lib/session_manager_lib.py
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import typing
+if typing.TYPE_CHECKING:
+ from acts.controllers.fuchsia_device import FuchsiaDevice
+
+
+class FuchsiaSessionManagerLib():
+ def __init__(self, fuchsia_device):
+ self.device: FuchsiaDevice = fuchsia_device
+
+ def resumeSession(self):
+ """Resumes a previously paused session
+
+ Returns:
+ Dictionary:
+ error: None, unless an error occurs
+ result: 'Success' or None if error
+ """
+ try:
+ self.device.ffx_command(
+ "component start /core/session-manager/session:session")
+ return {'error': None, 'result': 'Success'}
+ except Exception as e:
+ return {'error': e, 'result': None}
+
+ def pauseSession(self):
+ """Pause the session, allowing for later resumption
+
+ Returns:
+ Dictionary:
+ error: None, unless an error occurs
+ result: 'Success', 'NoSessionToPause', or None if error
+ """
+ result = self.device.ffx_command(
+ "component stop -r /core/session-manager/session:session",
+ skip_status_code_check=True)
+
+ if result.exit_status == 0:
+ return {'error': None, 'result': 'Success'}
+ else:
+ if "InstanceNotFound" in result.stderr:
+ return {'error': None, 'result': 'NoSessionToPause'}
+ else:
+ return {'error': result, 'result': None}
diff --git a/acts/framework/acts/controllers/fuchsia_lib/utils_lib.py b/acts/framework/acts/controllers/fuchsia_lib/utils_lib.py
index 6ea9589..3fc1813 100644
--- a/acts/framework/acts/controllers/fuchsia_lib/utils_lib.py
+++ b/acts/framework/acts/controllers/fuchsia_lib/utils_lib.py
@@ -267,7 +267,6 @@
image_tgz = os.path.basename(fuchsia_device.specific_image)
job.run('tar xfvz %s/%s -C %s' % (tmp_path, image_tgz, tmp_path))
- os.chdir(tmp_path)
all_files = []
for root, _dirs, files in itertools.islice(os.walk(tmp_path), 1, None):
for filename in files:
@@ -328,13 +327,9 @@
flash_process_found = True
if not flash_process_found:
break
- logging.info('Flashing fuchsia_device(%s) with %s/%s.' %
- (fuchsia_device.orig_ip, tmp_path, image_tgz))
+ logging.info(f'Flashing {fuchsia_device.orig_ip} with {tmp_path}/{image_tgz} using authorized keys "{fuchsia_device.authorized_file}".')
try:
- flash_output = job.run(
- 'bash flash.sh --ssh-key=%s -s %s' %
- (fuchsia_device.authorized_file, fuchsia_device.serial_number),
- timeout=120)
+ flash_output = job.run(f'bash {tmp_path}/flash.sh --ssh-key={fuchsia_device.authorized_file} -s {fuchsia_device.serial_number}', timeout=120)
logging.debug(flash_output.stderr)
except job.TimeoutError as err:
raise TimeoutError(err)
diff --git a/acts/framework/acts/controllers/openwrt_ap.py b/acts/framework/acts/controllers/openwrt_ap.py
index 22221ef..ac0712d 100644
--- a/acts/framework/acts/controllers/openwrt_ap.py
+++ b/acts/framework/acts/controllers/openwrt_ap.py
@@ -1,14 +1,17 @@
"""Controller for Open WRT access point."""
+import random
import re
import time
from acts import logger
+from acts import signals
from acts.controllers.ap_lib import hostapd_constants
from acts.controllers.openwrt_lib import network_settings
from acts.controllers.openwrt_lib import wireless_config
from acts.controllers.openwrt_lib import wireless_settings_applier
from acts.controllers.utils_lib.ssh import connection
from acts.controllers.utils_lib.ssh import settings
+from acts.controllers.openwrt_lib.openwrt_constants import OpenWrtWifiSetting
import yaml
MOBLY_CONTROLLER_CONFIG_NAME = "OpenWrtAP"
@@ -20,6 +23,7 @@
ENT_SECURITY = "wpa2"
OWE_SECURITY = "owe"
SAE_SECURITY = "sae"
+SAEMIXED_SECURITY = "sae-mixed"
ENABLE_RADIO = "0"
PMF_ENABLED = 2
WIFI_2G = "wifi2g"
@@ -293,7 +297,7 @@
else:
self.ssh.run(
'uci set wireless.@wifi-iface[{}].key={}'.format(3, pwd_5g))
- self.log.info("Set 5G password to :{}".format(pwd_2g))
+ self.log.info("Set 5G password to :{}".format(pwd_5g))
if pwd_2g:
if len(pwd_2g) < 8 or len(pwd_2g) > 63:
@@ -309,6 +313,89 @@
self.ssh.run("uci commit wireless")
self.ssh.run("wifi")
+ def set_ssid(self, ssid_5g=None, ssid_2g=None):
+ """Set SSID for individual interface.
+
+ Args:
+ ssid_5g: 8 ~ 63 chars for 5g network.
+ ssid_2g: 8 ~ 63 chars for 2g network.
+ """
+ if ssid_5g:
+ if len(ssid_5g) < 8 or len(ssid_5g) > 63:
+ self.log.error("SSID must be 8~63 characters long")
+ # Only accept ascii letters and digits
+ else:
+ self.ssh.run(
+ 'uci set wireless.@wifi-iface[{}].ssid={}'.format(3, ssid_5g))
+ self.log.info("Set 5G SSID to :{}".format(ssid_5g))
+
+ if ssid_2g:
+ if len(ssid_2g) < 8 or len(ssid_2g) > 63:
+ self.log.error("SSID must be 8~63 characters long")
+ # Only accept ascii letters and digits
+ else:
+ self.ssh.run(
+ 'uci set wireless.@wifi-iface[{}].ssid={}'.format(2, ssid_2g))
+ self.log.info("Set 2G SSID to :{}".format(ssid_2g))
+
+ self.ssh.run("uci commit wireless")
+ self.ssh.run("wifi")
+
+ def generate_mobility_domain(self):
+ """Generate 4-character hexadecimal ID
+
+ Returns: String; a 4-character hexadecimal ID.
+ """
+ md = "{:04x}".format(random.getrandbits(16))
+ self.log.info("Mobility Domain ID: {}".format(md))
+ return md
+
+ def enable_80211r(self, iface, md):
+ """Enable 802.11r for one single radio.
+
+ Args:
+ iface: index number of wifi-iface.
+ 2: radio1
+ 3: radio0
+ md: mobility domain. a 4-character hexadecimal ID.
+ Raises: TestSkip if 2g or 5g radio is not up or 802.11r is not enabled.
+ """
+ str_output = self.ssh.run("wifi status").stdout
+ wifi_status = yaml.load(str_output.replace("\t", "").replace("\n", ""),
+ Loader=yaml.FullLoader)
+ # Check if the radio is up.
+ if iface == OpenWrtWifiSetting.IFACE_2G:
+ if wifi_status['radio1']['up']:
+ self.log.info("2g network is ENABLED")
+ else:
+ raise signals.TestSkip("2g network is NOT ENABLED")
+ elif iface == OpenWrtWifiSetting.IFACE_5G:
+ if wifi_status['radio0']['up']:
+ self.log.info("5g network is ENABLED")
+ else:
+ raise signals.TestSkip("5g network is NOT ENABLED")
+
+ # Setup 802.11r.
+ self.ssh.run(
+ "uci set wireless.@wifi-iface[{}].ieee80211r='1'".format(iface))
+ self.ssh.run(
+ "uci set wireless.@wifi-iface[{}].ft_psk_generate_local='1'"
+ .format(iface))
+ self.ssh.run(
+ "uci set wireless.@wifi-iface[{}].mobility_domain='{}'"
+ .format(iface, md))
+ self.ssh.run(
+ "uci commit wireless")
+ self.ssh.run("wifi")
+
+ # Check if 802.11r is enabled.
+ result = self.ssh.run(
+ "uci get wireless.@wifi-iface[{}].ieee80211r".format(iface)).stdout
+ if result == '1':
+ self.log.info("802.11r is ENABLED")
+ else:
+ raise signals.TestSkip("802.11r is NOT ENABLED")
+
def generate_wireless_configs(self, wifi_configs):
"""Generate wireless configs to configure.
@@ -335,7 +422,8 @@
config["security"],
hostapd_constants.BAND_2G,
password=config["password"],
- hidden=config["hiddenSSID"]))
+ hidden=config["hiddenSSID"],
+ ieee80211w=config["ieee80211w"]))
elif config["security"] == PSK1_SECURITY:
wireless_configs.append(
wireless_config.WirelessConfig("%s%s" % (WIFI_2G, num_2g),
@@ -343,7 +431,8 @@
config["security"],
hostapd_constants.BAND_2G,
password=config["password"],
- hidden=config["hiddenSSID"]))
+ hidden=config["hiddenSSID"],
+ ieee80211w=config["ieee80211w"]))
elif config["security"] == WEP_SECURITY:
wireless_configs.append(
wireless_config.WirelessConfig("%s%s" % (WIFI_2G, num_2g),
@@ -376,6 +465,15 @@
password=config["password"],
hidden=config["hiddenSSID"],
ieee80211w=PMF_ENABLED))
+ elif config["security"] == SAEMIXED_SECURITY:
+ wireless_configs.append(
+ wireless_config.WirelessConfig("%s%s" % (WIFI_2G, num_2g),
+ config["SSID"],
+ config["security"],
+ hostapd_constants.BAND_2G,
+ password=config["password"],
+ hidden=config["hiddenSSID"],
+ ieee80211w=config["ieee80211w"]))
elif config["security"] == ENT_SECURITY:
wireless_configs.append(
wireless_config.WirelessConfig(
@@ -397,7 +495,8 @@
config["security"],
hostapd_constants.BAND_5G,
password=config["password"],
- hidden=config["hiddenSSID"]))
+ hidden=config["hiddenSSID"],
+ ieee80211w=config["ieee80211w"]))
elif config["security"] == PSK1_SECURITY:
wireless_configs.append(
wireless_config.WirelessConfig("%s%s" % (WIFI_5G, num_5g),
@@ -405,7 +504,8 @@
config["security"],
hostapd_constants.BAND_5G,
password=config["password"],
- hidden=config["hiddenSSID"]))
+ hidden=config["hiddenSSID"],
+ ieee80211w=config["ieee80211w"]))
elif config["security"] == WEP_SECURITY:
wireless_configs.append(
wireless_config.WirelessConfig("%s%s" % (WIFI_5G, num_5g),
@@ -438,6 +538,15 @@
password=config["password"],
hidden=config["hiddenSSID"],
ieee80211w=PMF_ENABLED))
+ elif config["security"] == SAEMIXED_SECURITY:
+ wireless_configs.append(
+ wireless_config.WirelessConfig("%s%s" % (WIFI_5G, num_5g),
+ config["SSID"],
+ config["security"],
+ hostapd_constants.BAND_5G,
+ password=config["password"],
+ hidden=config["hiddenSSID"],
+ ieee80211w=config["ieee80211w"]))
elif config["security"] == ENT_SECURITY:
wireless_configs.append(
wireless_config.WirelessConfig(
diff --git a/acts/framework/acts/controllers/openwrt_lib/network_const.py b/acts/framework/acts/controllers/openwrt_lib/network_const.py
index 0a3fb42..3aba0de 100644
--- a/acts/framework/acts/controllers/openwrt_lib/network_const.py
+++ b/acts/framework/acts/controllers/openwrt_lib/network_const.py
@@ -1,3 +1,5 @@
+LOCALHOST = "192.168.1.1"
+
# params for ipsec.conf
IPSEC_CONF = {
"config setup": {
@@ -15,7 +17,7 @@
"conn L2TP_PSK": {
"keyexchange": "ikev1",
"type": "transport",
- "left": "192.168.1.1",
+ "left": LOCALHOST,
"leftprotoport": "17/1701",
"leftauth": "psk",
"right": "%any",
@@ -30,7 +32,7 @@
"conn L2TP_RSA": {
"keyexchange": "ikev1",
"type": "transport",
- "left": "192.168.1.1",
+ "left": LOCALHOST,
"leftprotoport": "17/1701",
"leftauth": "pubkey",
"leftcert": "serverCert.der",
@@ -45,7 +47,7 @@
IPSEC_HYBRID_RSA = {
"conn HYBRID_RSA": {
"keyexchange": "ikev1",
- "left": "192.168.1.1",
+ "left": LOCALHOST,
"leftsubnet": "0.0.0.0/0",
"leftauth": "pubkey",
"leftcert": "serverCert.der",
@@ -62,7 +64,7 @@
IPSEC_XAUTH_PSK = {
"conn XAUTH_PSK": {
"keyexchange": "ikev1",
- "left": "192.168.1.1",
+ "left": LOCALHOST,
"leftsubnet": "0.0.0.0/0",
"leftauth": "psk",
"right": "%any",
@@ -76,7 +78,7 @@
IPSEC_XAUTH_RSA = {
"conn XAUTH_RSA": {
"keyexchange": "ikev1",
- "left": "192.168.1.1",
+ "left": LOCALHOST,
"leftsubnet": "0.0.0.0/0",
"leftcert": "serverCert.der",
"leftsendcert": "always",
@@ -88,6 +90,100 @@
}
}
+IPSEC_IKEV2_MSCHAPV2 = {
+ "conn IKEV2_MSCHAPV2": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": LOCALHOST,
+ "leftcert": "serverCert.der",
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "pubkey",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightid": "vpntest",
+ "rightauth": "eap-mschapv2",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_PSK = {
+ "conn IKEV2_PSK": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": LOCALHOST,
+ "leftauth": "psk",
+ "leftsubnet": "0.0.0.0/0",
+ "right": "%any",
+ "rightid": "vpntest",
+ "rightauth": "psk",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_RSA = {
+ "conn IKEV2_RSA": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": LOCALHOST,
+ "leftcert": "serverCert.der",
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "pubkey",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightid": "vpntest@%s" % LOCALHOST,
+ "rightauth": "pubkey",
+ "rightcert": "clientCert.pem",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_MSCHAPV2_HOSTNAME = {
+ "conn IKEV2_MSCHAPV2_HOSTNAME": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": "strongswan-vpn-server.android-iperf.com",
+ "leftcert": "serverCert.der",
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "pubkey",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightid": "vpntest",
+ "rightauth": "eap-mschapv2",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_PSK_HOSTNAME = {
+ "conn IKEV2_PSK_HOSTNAME": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": "strongswan-vpn-server.android-iperf.com",
+ "leftauth": "psk",
+ "leftsubnet": "0.0.0.0/0",
+ "right": "%any",
+ "rightid": "vpntest",
+ "rightauth": "psk",
+ "auto": "add"
+ }
+}
+
+IPSEC_IKEV2_RSA_HOSTNAME = {
+ "conn IKEV2_RSA_HOSTNAME": {
+ "keyexchange": "ikev2",
+ "left": LOCALHOST,
+ "leftid": "strongswan-vpn-server.android-iperf.com",
+ "leftcert": "serverCert.der",
+ "leftsubnet": "0.0.0.0/0",
+ "leftauth": "pubkey",
+ "leftsendcert": "always",
+ "right": "%any",
+ "rightid": "vpntest@strongswan-vpn-server.android-iperf.com",
+ "rightauth": "pubkey",
+ "rightcert": "clientCert.pem",
+ "auto": "add"
+ }
+}
+
# parmas for lx2tpd
XL2TPD_CONF_GLOBAL = (
@@ -149,7 +245,6 @@
"iptables -I FORWARD -m policy --dir out --pol ipsec --proto esp -j ACCEPT",
"iptables -I OUTPUT -m policy --dir out --pol ipsec --proto esp -j ACCEPT",
"iptables -t nat -I POSTROUTING -m policy --pol ipsec --dir out -j ACCEPT",
- "iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT",
"iptables -A INPUT -p esp -j ACCEPT",
"iptables -A INPUT -i eth0.2 -p udp --dport 500 -j ACCEPT",
"iptables -A INPUT -i eth0.2 -p tcp --dport 500 -j ACCEPT",
diff --git a/acts/framework/acts/controllers/openwrt_lib/network_settings.py b/acts/framework/acts/controllers/openwrt_lib/network_settings.py
index ca1b212..b3c1e4e 100644
--- a/acts/framework/acts/controllers/openwrt_lib/network_settings.py
+++ b/acts/framework/acts/controllers/openwrt_lib/network_settings.py
@@ -42,6 +42,7 @@
XL2TPD_OPTION_CONFIG_PATH = "/etc/ppp/options.xl2tpd"
FIREWALL_CUSTOM_OPTION_PATH = "/etc/firewall.user"
PPP_CHAP_SECRET_PATH = "/etc/ppp/chap-secrets"
+IKEV2_VPN_CERT_KEYS_PATH = "/var/ikev2_cert.sh"
TCPDUMP_DIR = "/tmp/tcpdump/"
LOCALHOST = "192.168.1.1"
DEFAULT_PACKAGE_INSTALL_TIMEOUT = 200
@@ -90,6 +91,7 @@
"ipv6_prefer_option": self.remove_ipv6_prefer_option,
"block_dns_response": self.unblock_dns_response,
"setup_mdns": self.remove_mdns,
+ "add_dhcp_rapid_commit": self.remove_dhcp_rapid_commit,
"setup_captive_portal": self.remove_cpative_portal
}
# This map contains cleanup functions to restore the configuration to
@@ -462,7 +464,11 @@
# setup vpn server local ip
self.setup_vpn_local_ip()
# generate cert and key for rsa
- self.generate_vpn_cert_keys(country, org)
+ if self.l2tp.name == "ikev2-server":
+ self.generate_ikev2_vpn_cert_keys(country, org)
+ self.add_resource_record(self.l2tp.hostname, LOCALHOST)
+ else:
+ self.generate_vpn_cert_keys(country, org)
# restart service
self.service_manager.need_restart(SERVICE_IPSEC)
self.service_manager.need_restart(SERVICE_XL2TPD)
@@ -474,6 +480,8 @@
self.config.discard("setup_vpn_l2tp_server")
self.restore_firewall_rules_for_l2tp()
self.remove_vpn_local_ip()
+ if self.l2tp.name == "ikev2-server":
+ self.clear_resource_record()
self.service_manager.need_restart(SERVICE_IPSEC)
self.service_manager.need_restart(SERVICE_XL2TPD)
self.service_manager.need_restart(SERVICE_FIREWALL)
@@ -507,6 +515,12 @@
config.append("")
config = []
+ load_ipsec_config(network_const.IPSEC_IKEV2_MSCHAPV2, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_PSK, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_RSA, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_MSCHAPV2_HOSTNAME, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_PSK_HOSTNAME, True)
+ load_ipsec_config(network_const.IPSEC_IKEV2_RSA_HOSTNAME, True)
load_ipsec_config(network_const.IPSEC_CONF)
load_ipsec_config(network_const.IPSEC_L2TP_PSK)
load_ipsec_config(network_const.IPSEC_L2TP_RSA)
@@ -600,6 +614,54 @@
self.ssh.run("mv clientPkcs.p12 /www/downloads/")
self.ssh.run("chmod 664 /www/downloads/clientPkcs.p12")
+ def generate_ikev2_vpn_cert_keys(self, country, org):
+ rsa = "--type rsa"
+ lifetime = "--lifetime 365"
+ size = "--size 4096"
+
+ if not self.path_exists("/www/downloads/"):
+ self.ssh.run("mkdir /www/downloads/")
+
+ ikev2_vpn_cert_keys = [
+ "ipsec pki --gen %s %s --outform der > caKey.der" % (rsa, size),
+ "ipsec pki --self --ca %s --in caKey.der %s --dn "
+ "\"C=%s, O=%s, CN=%s\" --outform der > caCert.der" %
+ (lifetime, rsa, country, org, self.l2tp.hostname),
+ "ipsec pki --gen %s %s --outform der > serverKey.der" % (size, rsa),
+ "ipsec pki --pub --in serverKey.der %s | ipsec pki --issue %s "
+ r"--cacert caCert.der --cakey caKey.der --dn \"C=%s, O=%s, CN=%s\" "
+ "--san %s --san %s --flag serverAuth --flag ikeIntermediate "
+ "--outform der > serverCert.der" % (rsa, lifetime, country, org,
+ self.l2tp.hostname, LOCALHOST,
+ self.l2tp.hostname),
+ "ipsec pki --gen %s %s --outform der > clientKey.der" % (size, rsa),
+ "ipsec pki --pub --in clientKey.der %s | ipsec pki --issue %s "
+ r"--cacert caCert.der --cakey caKey.der --dn \"C=%s, O=%s, CN=%s@%s\" "
+ r"--san \"%s\" --san \"%s@%s\" --san \"%s@%s\" --outform der "
+ "> clientCert.der" % (rsa, lifetime, country, org, self.l2tp.username,
+ self.l2tp.hostname, self.l2tp.username,
+ self.l2tp.username, LOCALHOST,
+ self.l2tp.username, self.l2tp.hostname),
+ "openssl rsa -inform DER -in clientKey.der "
+ "-out clientKey.pem -outform PEM",
+ "openssl x509 -inform DER -in clientCert.der "
+ "-out clientCert.pem -outform PEM",
+ "openssl x509 -inform DER -in caCert.der "
+ "-out caCert.pem -outform PEM",
+ "openssl pkcs12 -in clientCert.pem -inkey clientKey.pem "
+ "-certfile caCert.pem -export -out clientPkcs.p12 -passout pass:",
+ "mv caCert.pem /etc/ipsec.d/cacerts/",
+ "mv *Cert* /etc/ipsec.d/certs/",
+ "mv *Key* /etc/ipsec.d/private/",
+ "mv clientPkcs.p12 /www/downloads/",
+ "chmod 664 /www/downloads/clientPkcs.p12",
+ ]
+ file_string = "\n".join(ikev2_vpn_cert_keys)
+ self.create_config_file(file_string, IKEV2_VPN_CERT_KEYS_PATH)
+
+ self.ssh.run("chmod +x %s" % IKEV2_VPN_CERT_KEYS_PATH)
+ self.ssh.run("%s" % IKEV2_VPN_CERT_KEYS_PATH)
+
def update_firewall_rules_list(self):
"""Update rule list in /etc/config/firewall."""
new_rules_list = []
@@ -854,6 +916,18 @@
self.service_manager.need_restart(SERVICE_DNSMASQ)
self.commit_changes()
+ def add_dhcp_rapid_commit(self):
+ self.create_config_file("dhcp-rapid-commit\n","/etc/dnsmasq.conf")
+ self.config.add("add_dhcp_rapid_commit")
+ self.service_manager.need_restart(SERVICE_DNSMASQ)
+ self.commit_changes()
+
+ def remove_dhcp_rapid_commit(self):
+ self.create_config_file("","/etc/dnsmasq.conf")
+ self.config.discard("add_dhcp_rapid_commit")
+ self.service_manager.need_restart(SERVICE_DNSMASQ)
+ self.commit_changes()
+
def start_tcpdump(self, test_name, args="", interface="br-lan"):
""""Start tcpdump on OpenWrt.
@@ -906,9 +980,11 @@
return tcpdump_remote_path if pull_dir else None
def clear_tcpdump(self):
- self.ssh.run("killall tpcdump", ignore_status=True)
- if self.ssh.run("pgrep tpcdump", ignore_status=True).stdout:
+ self.ssh.run("killall tcpdump", ignore_status=True)
+ if self.ssh.run("pgrep tcpdump", ignore_status=True).stdout:
raise signals.TestFailure("Failed to clean up tcpdump process.")
+ if self.path_exists(TCPDUMP_DIR):
+ self.ssh.run("rm -f %s/*" % TCPDUMP_DIR)
def _get_tcpdump_pid(self, tcpdump_file_name):
"""Check tcpdump process on OpenWrt."""
diff --git a/acts/framework/acts/controllers/openwrt_lib/openwrt_constants.py b/acts/framework/acts/controllers/openwrt_lib/openwrt_constants.py
index 5848b5b..5ab4124 100644
--- a/acts/framework/acts/controllers/openwrt_lib/openwrt_constants.py
+++ b/acts/framework/acts/controllers/openwrt_lib/openwrt_constants.py
@@ -23,4 +23,8 @@
WPA2_PSK_DEFAULT = "psk2"
WPA2_PSK_CCMP = "psk2+ccmp"
WPA2_PSK_TKIP = "psk2+tkip"
- WPA2_PSK_TKIP_AND_CCMP = "psk2+tkip+ccmp"
\ No newline at end of file
+ WPA2_PSK_TKIP_AND_CCMP = "psk2+tkip+ccmp"
+
+class OpenWrtWifiSetting:
+ IFACE_2G = 2
+ IFACE_5G = 3
\ No newline at end of file
diff --git a/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py b/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py
index ec0bbf1..a366c02 100644
--- a/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py
+++ b/acts/framework/acts/controllers/openwrt_lib/wireless_settings_applier.py
@@ -15,6 +15,7 @@
ENT_SECURITY = "wpa2"
OWE_SECURITY = "owe"
SAE_SECURITY = "sae"
+SAEMIXED_SECURITY = "sae-mixed"
ENABLE_RADIO = "0"
DISABLE_RADIO = "1"
ENABLE_HIDDEN = "1"
@@ -108,7 +109,8 @@
self.ssh.run("uci set wireless.%s.encryption='%s'" %
(config.name, config.security))
if config.security == PSK_SECURITY or config.security == SAE_SECURITY\
- or config.security == PSK1_SECURITY:
+ or config.security == PSK1_SECURITY\
+ or config.security == SAEMIXED_SECURITY:
self.ssh.run("uci set wireless.%s.key='%s'" %
(config.name, config.password))
elif config.security == WEP_SECURITY:
diff --git a/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py b/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py
index dbc59e7..959274d 100644
--- a/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py
+++ b/acts/framework/acts/controllers/sl4a_lib/sl4a_manager.py
@@ -111,12 +111,12 @@
self._listen_for_port_lock = threading.Lock()
self._sl4a_ports = set()
self.adb = adb
- self.log = logger.create_logger(
- lambda msg: '[SL4A Manager|%s] %s' % (adb.serial, msg))
+ self.log = logger.create_logger(lambda msg: '[SL4A Manager|%s] %s' % (
+ adb.serial, msg))
self.sessions = {}
self._started = False
- self.error_reporter = error_reporter.ErrorReporter(
- 'SL4A %s' % adb.serial)
+ self.error_reporter = error_reporter.ErrorReporter('SL4A %s' %
+ adb.serial)
@property
def sl4a_ports_in_use(self):
@@ -163,8 +163,8 @@
raise rpc_client.Sl4aConnectionError(
'Unable to find a valid open port for a new server connection. '
- 'Expected port: %s. Open ports: %s' % (device_port,
- self._sl4a_ports))
+ 'Expected port: %s. Open ports: %s' %
+ (device_port, self._sl4a_ports))
def _get_all_ports_command(self):
"""Returns the list of all ports from the command to get ports."""
@@ -242,6 +242,7 @@
def create_session(self,
max_connections=None,
client_port=0,
+ forwarded_port=0,
server_port=None):
"""Creates an SL4A server with the given ports if possible.
@@ -250,7 +251,9 @@
be randomized.
Args:
- client_port: The port on the host machine
+ client_port: The client port on the host machine
+ forwarded_port: The server port on the host machine forwarded
+ by adb from the Android device
server_port: The port on the Android device.
max_connections: The max number of client connections for the
session.
@@ -266,22 +269,25 @@
# Otherwise, open a new server on a random port.
else:
server_port = 0
+ self.log.debug(
+ "Creating SL4A session client_port={}, forwarded_port={}, server_port={}"
+ .format(client_port, forwarded_port, server_port))
self.start_sl4a_service()
- session = sl4a_session.Sl4aSession(
- self.adb,
- client_port,
- server_port,
- self.obtain_sl4a_server,
- self.diagnose_failure,
- max_connections=max_connections)
+ session = sl4a_session.Sl4aSession(self.adb,
+ client_port,
+ server_port,
+ self.obtain_sl4a_server,
+ self.diagnose_failure,
+ forwarded_port,
+ max_connections=max_connections)
self.sessions[session.uid] = session
return session
def stop_service(self):
"""Stops The SL4A Service. Force-stops the SL4A apk."""
try:
- self.adb.shell(
- 'am force-stop %s' % SL4A_PKG_NAME, ignore_status=True)
+ self.adb.shell('am force-stop %s' % SL4A_PKG_NAME,
+ ignore_status=True)
except Exception as e:
self.log.warning("Fail to stop package %s: %s", SL4A_PKG_NAME, e)
self._started = False
diff --git a/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py b/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py
index c0a4e1d..04fd787 100644
--- a/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py
+++ b/acts/framework/acts/controllers/sl4a_lib/sl4a_session.py
@@ -55,6 +55,7 @@
device_port,
get_server_port_func,
on_error_callback,
+ forwarded_port=0,
max_connections=None):
"""Creates an SL4A Session.
@@ -67,6 +68,8 @@
server for its first connection.
device_port: The SL4A server port to be used as a hint for which
SL4A server to connect to.
+ forwarded_port: The server port on host machine forwarded by adb
+ from Android device to accept SL4A connection
"""
self._event_dispatcher = None
self._terminate_lock = threading.Lock()
@@ -79,24 +82,24 @@
self.log = logger.create_logger(_log_formatter)
+ self.forwarded_port = forwarded_port
self.server_port = device_port
self.uid = UNKNOWN_UID
self.obtain_server_port = get_server_port_func
self._on_error_callback = on_error_callback
connection_creator = self._rpc_connection_creator(host_port)
- self.rpc_client = rpc_client.RpcClient(
- self.uid,
- self.adb.serial,
- self.diagnose_failure,
- connection_creator,
- max_connections=max_connections)
+ self.rpc_client = rpc_client.RpcClient(self.uid,
+ self.adb.serial,
+ self.diagnose_failure,
+ connection_creator,
+ max_connections=max_connections)
def _rpc_connection_creator(self, host_port):
def create_client(uid):
- return self._create_rpc_connection(
- ports=sl4a_ports.Sl4aPorts(host_port, 0, self.server_port),
- uid=uid)
+ return self._create_rpc_connection(ports=sl4a_ports.Sl4aPorts(
+ host_port, self.forwarded_port, self.server_port),
+ uid=uid)
return create_client
@@ -156,10 +159,14 @@
ports.server_port = self.obtain_server_port(ports.server_port)
self.server_port = ports.server_port
# Forward the device port to the host.
- ports.forwarded_port = self._create_forwarded_port(ports.server_port)
+ ports.forwarded_port = self._create_forwarded_port(
+ ports.server_port, hinted_port=ports.forwarded_port)
client_socket, fd = self._create_client_side_connection(ports)
- client = rpc_connection.RpcConnection(
- self.adb, ports, client_socket, fd, uid=uid)
+ client = rpc_connection.RpcConnection(self.adb,
+ ports,
+ client_socket,
+ fd,
+ uid=uid)
client.open()
if uid == UNKNOWN_UID:
self.uid = client.uid
@@ -195,9 +202,9 @@
except OSError as e:
# If the port is in use, log and ask for any open port.
if e.errno == errno.EADDRINUSE:
- self.log.warning(
- 'Port %s is already in use on the host. '
- 'Generating a random port.' % ports.client_port)
+ self.log.warning('Port %s is already in use on the host. '
+ 'Generating a random port.' %
+ ports.client_port)
ports.client_port = 0
return self._create_client_side_connection(ports)
raise
diff --git a/acts/framework/setup.py b/acts/framework/setup.py
index cb4f330..98a8fb0 100755
--- a/acts/framework/setup.py
+++ b/acts/framework/setup.py
@@ -61,8 +61,8 @@
install_requires.append('scipy<1.6')
install_requires.append('numpy<1.20')
elif sys.version_info < (3, 8):
- # Python 3.7 uses latest scipy and numpy up to 1.21.x
- install_requires.append('scipy')
+ # Python 3.7 uses latest scipy up to 1.7.x and numpy up to 1.21.x
+ install_requires.append('scipy<1.8')
install_requires.append('numpy<1.22')
else:
# Python 3.8+ is supported by latest scipy and numpy
diff --git a/acts/framework/tests/acts_utils_test.py b/acts/framework/tests/acts_utils_test.py
index 742e07f..e662db8 100755
--- a/acts/framework/tests/acts_utils_test.py
+++ b/acts/framework/tests/acts_utils_test.py
@@ -72,74 +72,68 @@
FUCHSIA_INTERFACES = {
'id':
'1',
- 'result': [{
- 'features':
- 4,
- 'filepath':
- '[none]',
- 'id':
- 1,
- 'ipv4_addresses': [[127, 0, 0, 1]],
- 'ipv6_addresses': [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]],
- 'is_administrative_status_enabled':
- True,
- 'is_physical_status_up':
- True,
- 'mac': [0, 0, 0, 0, 0, 0],
- 'mtu':
- 65536,
- 'name':
- 'lo',
- 'topopath':
- 'loopback'
- }, {
- 'features':
- 0,
- 'filepath':
- '/dev/class/ethernet/000',
- 'id':
- 2,
- 'ipv4_addresses': [[100, 127, 110, 79]],
- 'ipv6_addresses':
- [[254, 128, 0, 0, 0, 0, 0, 0, 198, 109, 60, 117, 44, 236, 29, 114],
- [36, 1, 250, 0, 4, 128, 122, 0, 141, 79, 133, 255, 204, 92, 120, 126],
- [36, 1, 250, 0, 4, 128, 122, 0, 4, 89, 185, 147, 252, 191, 20, 25]],
- 'is_administrative_status_enabled':
- True,
- 'is_physical_status_up':
- True,
- 'mac': [0, 224, 76, 5, 76, 229],
- 'mtu':
- 1514,
- 'name':
- 'eno1',
- 'topopath':
- '@/dev/xhci/xhci/usb-bus/001/001/ifc-000/usb-cdc-ecm/ethernet'
- }, {
- 'features':
- 1,
- 'filepath':
- '/dev/class/ethernet/001',
- 'id':
- 3,
- 'ipv4_addresses': [],
- 'ipv6_addresses':
- [[254, 128, 0, 0, 0, 0, 0, 0, 96, 255, 93, 96, 52, 253, 253, 243],
- [254, 128, 0, 0, 0, 0, 0, 0, 70, 7, 11, 255, 254, 118, 126, 192]],
- 'is_administrative_status_enabled':
- False,
- 'is_physical_status_up':
- False,
- 'mac': [68, 7, 11, 118, 126, 192],
- 'mtu':
- 1500,
- 'name':
- 'wlanxc0',
- 'topopath':
- '@/dev/wifi/wlanphy/wlanif-client/wlan-ethernet/ethernet'
- }],
+ 'result': [
+ {
+ 'id': 1,
+ 'name': 'lo',
+ 'ipv4_addresses': [
+ [127, 0, 0, 1],
+ ],
+ 'ipv6_addresses': [
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
+ ],
+ 'online': True,
+ 'mac': [0, 0, 0, 0, 0, 0],
+ },
+ {
+ 'id':
+ 2,
+ 'name':
+ 'eno1',
+ 'ipv4_addresses': [
+ [100, 127, 110, 79],
+ ],
+ 'ipv6_addresses': [
+ [
+ 254, 128, 0, 0, 0, 0, 0, 0, 198, 109, 60, 117, 44, 236, 29,
+ 114
+ ],
+ [
+ 36, 1, 250, 0, 4, 128, 122, 0, 141, 79, 133, 255, 204, 92,
+ 120, 126
+ ],
+ [
+ 36, 1, 250, 0, 4, 128, 122, 0, 4, 89, 185, 147, 252, 191,
+ 20, 25
+ ],
+ ],
+ 'online':
+ True,
+ 'mac': [0, 224, 76, 5, 76, 229],
+ },
+ {
+ 'id':
+ 3,
+ 'name':
+ 'wlanxc0',
+ 'ipv4_addresses': [],
+ 'ipv6_addresses': [
+ [
+ 254, 128, 0, 0, 0, 0, 0, 0, 96, 255, 93, 96, 52, 253, 253,
+ 243
+ ],
+ [
+ 254, 128, 0, 0, 0, 0, 0, 0, 70, 7, 11, 255, 254, 118, 126,
+ 192
+ ],
+ ],
+ 'online':
+ False,
+ 'mac': [68, 7, 11, 118, 126, 192],
+ },
+ ],
'error':
- None
+ None,
}
CORRECT_FULL_IP_LIST = {
@@ -163,6 +157,8 @@
FUCHSIA_INIT_SERVER = ('acts.controllers.fuchsia_device.FuchsiaDevice.'
'init_server_connection')
+FUCHSIA_INIT_FFX = ('acts.controllers.fuchsia_device.FuchsiaDevice.'
+ 'init_ffx_connection')
FUCHSIA_SET_CONTROL_PATH_CONFIG = ('acts.controllers.fuchsia_device.'
'FuchsiaDevice._set_control_path_config')
FUCHSIA_START_SERVICES = ('acts.controllers.fuchsia_device.FuchsiaDevice.'
@@ -531,15 +527,14 @@
CORRECT_EMPTY_IP_LIST)
@mock.patch(FUCHSIA_INIT_SERVER)
+ @mock.patch(FUCHSIA_INIT_FFX)
@mock.patch(FUCHSIA_SET_CONTROL_PATH_CONFIG)
@mock.patch(FUCHSIA_START_SERVICES)
@mock.patch(FUCHSIA_NETSTACK_LIST_INTERFACES)
@mock.patch(FUCHSIA_INIT_NETSTACK)
- def test_fuchsia_get_interface_ip_addresses_full(self, init_mock,
- list_interfaces_mock,
- start_services_mock,
- control_path_mock,
- fuchsia_device_mock):
+ def test_fuchsia_get_interface_ip_addresses_full(
+ self, init_mock, list_interfaces_mock, start_services_mock,
+ control_path_mock, ffx_mock, fuchsia_device_mock):
# Will never actually be created/used.
logging.log_path = '/tmp/unit_test_garbage'
@@ -552,15 +547,14 @@
CORRECT_FULL_IP_LIST)
@mock.patch(FUCHSIA_INIT_SERVER)
+ @mock.patch(FUCHSIA_INIT_FFX)
@mock.patch(FUCHSIA_SET_CONTROL_PATH_CONFIG)
@mock.patch(FUCHSIA_START_SERVICES)
@mock.patch(FUCHSIA_NETSTACK_LIST_INTERFACES)
@mock.patch(FUCHSIA_INIT_NETSTACK)
- def test_fuchsia_get_interface_ip_addresses_empty(self, init_mock,
- list_interfaces_mock,
- start_services_mock,
- control_path_mock,
- fuchsia_device_mock):
+ def test_fuchsia_get_interface_ip_addresses_empty(
+ self, init_mock, list_interfaces_mock, start_services_mock,
+ control_path_mock, ffx_mock, fuchsia_device_mock):
# Will never actually be created/used.
logging.log_path = '/tmp/unit_test_garbage'
diff --git a/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py b/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py
index e90c527..ba05a53 100644
--- a/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/abstract_devices/wlan_device_lib/AbstractDeviceWlanDeviceBaseTest.py
@@ -13,6 +13,9 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
+
+from acts import context
from acts_contrib.test_utils.wifi.WifiBaseTest import WifiBaseTest
from mobly import utils
@@ -32,18 +35,46 @@
device.take_bug_report(STAGE_NAME_TEARDOWN_CLASS, begin_time)
def on_fail(self, test_name, begin_time):
- try:
- self.dut.get_log(test_name, begin_time)
- if (not hasattr(self.dut.device, "take_bug_report_on_fail")
- or self.dut.device.take_bug_report_on_fail):
- # Take a bug report if device does not have a take bug report flag,
- # or if the flag is true
- self.dut.take_bug_report(test_name, begin_time)
- except Exception:
- pass
+ """Gets a wlan_device log and calls the generic device fail on DUT."""
+ self.dut.get_log(test_name, begin_time)
+ self.on_device_fail(self.dut.device, test_name, begin_time)
- try:
- if self.dut.device.hard_reboot_on_fail:
- self.dut.hard_power_cycle(self.pdu_devices)
- except AttributeError:
- pass
+ def on_device_fail(self, device, test_name, begin_time):
+ """Gets a generic device DUT bug report.
+
+ This method takes a bug report if the generic device does not have a
+ 'take_bug_report_on_fail', or if the flag is true. This method also
+ power cycles if 'hard_reboot_on_fail' is True.
+
+ Args:
+ device: Generic device to gather logs from.
+ test_name: Name of the test that triggered this function.
+ begin_time: Logline format timestamp taken when the test started.
+ """
+ if (not hasattr(device, "take_bug_report_on_fail")
+ or device.take_bug_report_on_fail):
+ device.take_bug_report(test_name, begin_time)
+
+ if device.hard_reboot_on_fail:
+ device.reboot(reboot_type='hard', testbed_pdus=self.pdu_devices)
+
+ def download_ap_logs(self):
+ """Downloads the DHCP and hostapad logs from the access_point.
+
+ Using the current TestClassContext and TestCaseContext this method pulls
+ the DHCP and hostapd logs and outputs them to the correct path.
+ """
+ current_path = context.get_current_context().get_full_output_path()
+ dhcp_full_out_path = os.path.join(current_path, "dhcp_log.txt")
+
+ dhcp_log_file = open(dhcp_full_out_path, 'w')
+ dhcp_log_file.write(self.access_point.get_dhcp_logs())
+ dhcp_log_file.close()
+
+ hostapd_logs = self.access_point.get_hostapd_logs()
+ for interface in hostapd_logs:
+ out_name = interface + "_hostapd_log.txt"
+ hostapd_full_out_path = os.path.join(current_path, out_name)
+ hostapd_log_file = open(hostapd_full_out_path, 'w')
+ hostapd_log_file.write(hostapd_logs[interface])
+ hostapd_log_file.close()
diff --git a/acts_tests/acts_contrib/test_utils/bt/BluetoothCarHfpBaseTest.py b/acts_tests/acts_contrib/test_utils/bt/BluetoothCarHfpBaseTest.py
index 303b961..1c20301 100644
--- a/acts_tests/acts_contrib/test_utils/bt/BluetoothCarHfpBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/bt/BluetoothCarHfpBaseTest.py
@@ -25,7 +25,7 @@
from acts.keys import Config
from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
from acts_contrib.test_utils.bt.bt_test_utils import pair_pri_to_sec
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
from acts_contrib.test_utils.tel.tel_test_utils import setup_droid_properties
diff --git a/acts_tests/acts_contrib/test_utils/bt/bt_carkit_lib.py b/acts_tests/acts_contrib/test_utils/bt/bt_carkit_lib.py
index 959e65a..ce206da 100644
--- a/acts_tests/acts_contrib/test_utils/bt/bt_carkit_lib.py
+++ b/acts_tests/acts_contrib/test_utils/bt/bt_carkit_lib.py
@@ -26,17 +26,17 @@
from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_EARPIECE
from acts_contrib.test_utils.tel.tel_defines import AUDIO_ROUTE_SPEAKER
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
+from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
+from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
from acts_contrib.test_utils.tel.tel_voice_utils import get_audio_route
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
from acts_contrib.test_utils.tel.tel_voice_utils import set_audio_route
from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts.utils import exe_cmd
from acts.utils import get_current_epoch_time
diff --git a/acts_tests/acts_contrib/test_utils/coex/coex_test_utils.py b/acts_tests/acts_contrib/test_utils/coex/coex_test_utils.py
index 4975757..a335f09 100644
--- a/acts_tests/acts_contrib/test_utils/coex/coex_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/coex/coex_test_utils.py
@@ -50,10 +50,10 @@
from acts_contrib.test_utils.car.car_telecom_utils import wait_for_not_in_call
from acts_contrib.test_utils.car.car_telecom_utils import wait_for_ringing
from acts_contrib.test_utils.tel.tel_test_utils import get_phone_number
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
from acts_contrib.test_utils.tel.tel_test_utils import setup_droid_properties
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
from acts_contrib.test_utils.wifi.wifi_power_test_utils import get_phone_ip
from acts_contrib.test_utils.wifi.wifi_test_utils import reset_wifi
from acts_contrib.test_utils.wifi.wifi_test_utils import wifi_connect
diff --git a/acts_tests/acts_contrib/test_utils/net/net_test_utils.py b/acts_tests/acts_contrib/test_utils/net/net_test_utils.py
index ba1f513d..81416c8 100644
--- a/acts_tests/acts_contrib/test_utils/net/net_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/net/net_test_utils.py
@@ -24,15 +24,18 @@
from acts import utils
from acts.controllers import adb
from acts.controllers.adb_lib.error import AdbError
+from acts.libs.proc import job
from acts.utils import start_standing_subprocess
from acts.utils import stop_standing_subprocess
from acts_contrib.test_utils.net import connectivity_const as cconst
+from acts_contrib.test_utils.tel import tel_defines
from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
-from scapy.all import get_if_list
+from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
+from scapy.config import conf
+from scapy.compat import plain_str
VPN_CONST = cconst.VpnProfile
VPN_TYPE = cconst.VpnProfileType
@@ -287,7 +290,7 @@
return vpn_profile
-def start_tcpdump(ad, test_name):
+def start_tcpdump(ad, test_name, interface="any"):
"""Start tcpdump on all interfaces.
Args:
@@ -301,8 +304,8 @@
file_name = "%s/tcpdump_%s_%s.pcap" % (TCPDUMP_PATH, ad.serial, test_name)
ad.log.info("tcpdump file is %s", file_name)
- cmd = "adb -s {} shell tcpdump -i any -s0 -w {}".format(ad.serial,
- file_name)
+ cmd = "adb -s {} shell tcpdump -i {} -s0 -w {}".format(ad.serial,
+ interface, file_name)
try:
return start_standing_subprocess(cmd, 5)
except Exception:
@@ -462,6 +465,34 @@
return operator in carrier_supports_ipv6
+def is_carrier_supports_entitlement(dut):
+ """Verify if carrier supports entitlement
+
+ Args:
+ dut: Android device
+
+ Return:
+ True if carrier supports entitlement, otherwise false
+ """
+
+ carriers_supports_entitlement = [
+ tel_defines.CARRIER_VZW,
+ tel_defines.CARRIER_ATT,
+ tel_defines.CARRIER_TMO,
+ tel_defines.CARRIER_SBM]
+ operator = get_operator_name("log", dut)
+ return operator in carriers_supports_entitlement
+
+
+def set_cap_net_raw_capability():
+ """Set the CAP_NET_RAW capability
+
+ To send the Scapy packets, we need to get the CAP_NET_RAW capability first.
+ """
+ cap_net_raw = "sudo setcap cap_net_raw=eip $(readlink -f $(which act.py))"
+ utils.exe_cmd(cap_net_raw)
+
+
def supports_ipv6_tethering(self, dut):
"""Check if provider supports IPv6 tethering.
@@ -478,19 +509,15 @@
def start_usb_tethering(ad):
- """Start USB tethering.
+ """Start USB tethering using #startTethering API.
+
+ Enable USB tethering by #startTethering API will break the RPC session,
+ Make sure you call #ad.recreate_services after call this API - b/149116235
Args:
- ad: android device object
+ ad: AndroidDevice object
"""
- # TODO: test USB tethering by #startTethering API - b/149116235
- ad.log.info("Starting USB Tethering")
- ad.stop_services()
- ad.adb.shell(USB_TETHERING_MODE, ignore_status=True)
- ad.adb.wait_for_device()
- ad.start_services()
- if "rndis" not in ad.adb.shell(DEVICE_IP_ADDRESS):
- raise signals.TestFailure("Unable to enable USB tethering.")
+ ad.droid.connectivityStartTethering(tel_defines.TETHERING_USB, False)
def stop_usb_tethering(ad):
@@ -524,3 +551,29 @@
return new_ifaces.pop()
time.sleep(1)
asserts.fail("Timeout waiting for tethering interface on host")
+
+
+def get_if_list():
+ """Returns a list containing all network interfaces.
+
+ The newest version of Scapy.get_if_list() returns the cached interfaces,
+ which might be out-dated, and unable to perceive the interface changes.
+ Use this method when need to monitoring the network interfaces changes.
+ Reference: https://github.com/secdev/scapy/pull/2707
+
+ Returns:
+ A list of the latest network interfaces. For example:
+ ['cvd-ebr', ..., 'eno1', 'enx4afa19a8dde1', 'lo', 'wlxd03745d68d88']
+ """
+
+ # Get ifconfig output
+ result = job.run([conf.prog.ifconfig])
+ if result.exit_status:
+ raise asserts.fail(
+ "Failed to execute ifconfig: {}".format(plain_str(result.stderr)))
+
+ interfaces = [
+ line[:line.find(':')] for line in plain_str(result.stdout).splitlines()
+ if ": flags" in line.lower()
+ ]
+ return interfaces
diff --git a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_hotspot_traffic_power_test.py b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_hotspot_traffic_power_test.py
index a4c2df6..755f511 100644
--- a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_hotspot_traffic_power_test.py
+++ b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_hotspot_traffic_power_test.py
@@ -15,8 +15,8 @@
# limitations under the License.
import time
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
from acts_contrib.test_utils.wifi import wifi_test_utils as wutils
import acts_contrib.test_utils.power.cellular.cellular_traffic_power_test as ctpt
diff --git a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_voice_call_power_test.py b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_voice_call_power_test.py
index 802d8cc..f64a1e4 100644
--- a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_voice_call_power_test.py
+++ b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_voice_call_power_test.py
@@ -19,7 +19,8 @@
from acts.controllers.anritsu_lib.md8475a import VirtualPhoneAutoAnswer
import acts_contrib.test_utils.power.cellular.cellular_power_base_test as PWCEL
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call, hangup_call, set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call, hangup_call
class PowerTelVoiceCallTest(PWCEL.PowerCellularLabBaseTest):
diff --git a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_volte_power_test.py b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_volte_power_test.py
index 986878d..e3b9531 100644
--- a/acts_tests/acts_contrib/test_utils/power/cellular/cellular_volte_power_test.py
+++ b/acts_tests/acts_contrib/test_utils/power/cellular/cellular_volte_power_test.py
@@ -20,7 +20,8 @@
import acts.controllers.anritsu_lib.md8475a as md8475a
import acts_contrib.test_utils.power.cellular.cellular_power_base_test as PWCEL
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call, hangup_call, set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_test_utils import set_phone_silent_mode
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call, hangup_call
class PowerTelVoLTECallTest(PWCEL.PowerCellularLabBaseTest):
diff --git a/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py b/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py
index 9a55400..9ff86be 100644
--- a/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/tel/GFTInOutBaseTest.py
@@ -13,16 +13,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
-import sys
-import collections
-import random
+
import time
-import datetime
-import os
-import logging
-import subprocess
-import math
-import re
from acts import asserts
from acts.test_decorators import test_info
from acts.test_decorators import test_tracker_info
@@ -31,12 +23,12 @@
from acts.libs.utils.multithread import multithread_func
from acts.base_test import BaseTestClass
from acts_contrib.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
+from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_log
+from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_logs
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_log
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_logs
-from acts_contrib.test_utils.tel.tel_test_utils import log_screen_shot
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
from acts_contrib.test_utils.tel.gft_inout_utils import mo_voice_call
from acts_contrib.test_utils.tel.gft_inout_utils import get_voice_call_type
from acts_contrib.test_utils.tel.gft_inout_utils import verify_data_connection
@@ -61,6 +53,7 @@
def setup_test(self):
TelephonyBaseTest.setup_test(self)
+ self.user_params["telephony_auto_rerun"] = 0
self.my_error_msg = ""
def teardown_test(self):
@@ -82,8 +75,8 @@
network_type_data = ad.droid.telephonyGetCurrentDataNetworkType()
data_state = ad.droid.telephonyGetDataConnectionState()
service_state = get_service_state_by_adb(ad.log,ad)
- sim_state = ad.droid.telephonyGetSimState()
wifi_info = ad.droid.wifiGetConnectionInfo()
+ sim_state = ad.droid.telephonyGetSimState()
if ad.droid.wifiCheckState():
if wifi_info["supplicant_state"] == "completed":
ad.log.info("Wifi is connected=%s" %(wifi_info["SSID"]))
@@ -100,7 +93,7 @@
return False
return True
- def adjust_cellular_signal(self, power):
+ def adjust_cellular_signal(self, power, adjust_gradually=False):
"""Sets the attenuation value of cellular port
Args:
power: power level for attenuator to be set
@@ -108,14 +101,20 @@
return True if ceullular port is set
"""
if self.user_params.get("Attenuator"):
- self.log.info("adjust cellular signal set mini-circuits to %s" %(power))
- self.attenuators[CELLULAR_PORT].set_atten(power)
+ if 'adjust_gradually' in self.user_params:
+ adjust_gradually = self.user_params.get('adjust_gradually')
+ if adjust_gradually:
+ self.log.info("adjust cellular signal gradually to mini-circuits to %s" %(power))
+ self.adjust_atten_slowly(10, NO_SERVICE_AREA)
+ else:
+ self.log.info("adjust cellular signal set mini-circuits to %s" %(power))
+ self.attenuators[CELLULAR_PORT].set_atten(power)
return True
else:
self.log.info("Attenuator is set to False in config file")
return False
- def adjust_wifi_signal(self, power):
+ def adjust_wifi_signal(self, power, adjust_gradually=False):
"""Sets the attenuation value of wifi port
Args:
power: power level for attenuator to be set
@@ -123,10 +122,16 @@
return True if wifi port is set
"""
if self.user_params.get("Attenuator"):
- self.log.info("adjust wifi signal set mini-circuits to %s" %(power))
- self.attenuators[WIFI_PORT].set_atten(power)
- self.attenuators[2].set_atten(power)
- self.attenuators[3].set_atten(power)
+ if 'adjust_gradually' in self.user_params:
+ adjust_gradually = self.user_params.get('adjust_gradually')
+ if adjust_gradually:
+ self.log.info("adjust wifi signal set mini-circuits to %s" %(power))
+ self.adjust_atten_slowly(10, NO_WIFI_AREA)
+ else:
+ self.log.info("adjust wifi signal and set mini-circuits to %s" %(power))
+ self.attenuators[WIFI_PORT].set_atten(power)
+ self.attenuators[2].set_atten(power)
+ self.attenuators[3].set_atten(power)
else:
self.log.info("Attenuator is set to False in config file")
return False
@@ -169,8 +174,10 @@
def adjust_atten_slowly(self, adjust_level, move_to, step=9 , step_time=5):
"""adjust attenuator slowly
Args:
- port: port of attenuator
- power: power level for attenuator to be set
+ adjust_level: adjust power level for each cycle
+ move_to: NO_SERVICE_AREA, IN_SERVICE_AREA , WIFI_AREA, NO_WIFI_AREA
+ step: adjust attenuator how many time
+ step_time: wait for how many sec for each loop
Returns:
return True if given port is set
"""
@@ -217,38 +224,61 @@
self.check_network()
return True
- def verify_device_status(self, ad, call_type=None, end_call=True, talk_time=30):
+ def verify_device_status(self, ad, call_type=None, end_call=True,
+ talk_time=30, verify_data=True, verify_voice=True, data_retries=2, voice_retries=2):
"""verfiy device status includes network service, data connection and voice call
Args:
ad: android device
call_type: WFC call, VOLTE call. CSFB call, voice call
end_call: hangup call after voice call flag
talk_time: in call duration in sec
+ verify_data: flag to check data connection
+ verify_voice: flag to check voice
+ data_retries: retry times for data verification
+ voice_retris:retry times for voice call
Returns:
- return True if given port is set
+ return True if pass
"""
- test_result = True
tasks = [(check_network_service, (ad, )) for ad in self.android_devices]
if not multithread_func(self.log, tasks):
log_screen_shot(ad, "check_network_service_fail")
- test_result = False
- tasks = [(verify_data_connection, (ad, )) for ad in self.android_devices]
- if not multithread_func(self.log, tasks):
- log_screen_shot(ad, "verify_data_connection_fail")
- test_result = False
- if call_type != None:
- tasks = [(mo_voice_call, (self.log, ad, call_type, end_call, talk_time))
+ ad.log.info("check_network_service fail")
+ return False
+ else:
+ self.log.info("check_network_service pass")
+ if verify_data:
+ tasks = [(verify_data_connection, (ad, data_retries ))
for ad in self.android_devices]
- if not multithread_func(self.log, tasks):
- log_screen_shot(ad, "verify_voice_call_fail")
- test_result = False
- return test_result
+ if not multithread_func(self.log, tasks):
+ log_screen_shot(ad, "verify_data_connection_fail")
+ ad.log.info("verify_data_connection_fail")
+ return False
+ else:
+ self.log.info("verify_data_connection pass")
+ if verify_voice:
+ if call_type:
+ tasks = [(mo_voice_call, (self.log, ad, call_type, end_call, talk_time,
+ voice_retries)) for ad in self.android_devices]
+ if not multithread_func(self.log, tasks):
+ log_screen_shot(ad, "verify_voice_call_fail")
+ ad.log.info("verify_voice_call_fail")
+ return False
+ else:
+ self.log.info("verify_voice_call pass")
+ return True
+ return True
- def _on_fail(self, error_msg=""):
+ def _on_failure(self, error_msg="", assert_on_fail=True, test_result=False):
""" operation on fail
Args:
error_msg: error message to be written to log
"""
+ if assert_on_fail:
+ asserts.assert_true(False, "assert_on_fail: %s."
+ %(error_msg),extras={"failure_cause": error_msg})
+ for ad in self.android_devices:
+ log_screen_shot(ad, error_msg)
self.log.info(error_msg)
+
diff --git a/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py b/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py
index 67019c5..ca65cb8 100644
--- a/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py
+++ b/acts_tests/acts_contrib/test_utils/tel/TelephonyBaseTest.py
@@ -32,10 +32,19 @@
from acts import utils
from acts.libs.utils.multithread import multithread_func
from acts.libs.utils.multithread import run_multithread_func
-
+from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_BACKGROUND
+from acts_contrib.test_utils.tel.tel_defines import SINGLE_SIM_CONFIG, MULTI_SIM_CONFIG
+from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_FOREGROUND
+from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_RINGING
+from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_ABSENT
+from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
+from acts_contrib.test_utils.tel.tel_defines import WIFI_VERBOSE_LOGGING_DISABLED
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_defines import CHIPSET_MODELS_LIST
from acts_contrib.test_utils.tel.tel_bootloader_utils import flash_radio
from acts_contrib.test_utils.tel.tel_ims_utils import activate_wfc_on_device
from acts_contrib.test_utils.tel.tel_logging_utils import disable_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_log
from acts_contrib.test_utils.tel.tel_logging_utils import set_qxdm_logger_command
from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_loggers
@@ -46,17 +55,15 @@
from acts_contrib.test_utils.tel.tel_logging_utils import start_tcpdumps
from acts_contrib.test_utils.tel.tel_logging_utils import stop_tcpdumps
from acts_contrib.test_utils.tel.tel_logging_utils import get_tcpdump_log
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_idle
from acts_contrib.test_utils.tel.tel_subscription_utils import initial_set_up_for_subid_information
from acts_contrib.test_utils.tel.tel_subscription_utils import set_default_sub_for_all_services
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_test_utils import build_id_override
from acts_contrib.test_utils.tel.tel_test_utils import enable_connectivity_metrics
from acts_contrib.test_utils.tel.tel_test_utils import enable_radio_log_on
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts_contrib.test_utils.tel.tel_test_utils import force_connectivity_metrics_upload
-from acts_contrib.test_utils.tel.tel_test_utils import get_screen_shot_log
from acts_contrib.test_utils.tel.tel_test_utils import get_sim_state
from acts_contrib.test_utils.tel.tel_test_utils import install_apk
from acts_contrib.test_utils.tel.tel_test_utils import print_radio_info
@@ -76,15 +83,7 @@
from acts_contrib.test_utils.tel.tel_test_utils import check_google_fi_activated
from acts_contrib.test_utils.tel.tel_test_utils import phone_switch_to_msim_mode
from acts_contrib.test_utils.tel.tel_test_utils import activate_esim_using_suw
-from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_BACKGROUND
-from acts_contrib.test_utils.tel.tel_defines import SINGLE_SIM_CONFIG, MULTI_SIM_CONFIG
-from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_FOREGROUND
-from acts_contrib.test_utils.tel.tel_defines import PRECISE_CALL_STATE_LISTEN_LEVEL_RINGING
-from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_ABSENT
-from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import WIFI_VERBOSE_LOGGING_DISABLED
-from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import CHIPSET_MODELS_LIST
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
class TelephonyBaseTest(BaseTestClass):
@@ -504,6 +503,11 @@
stop_tcpdumps(self.android_devices)
def on_fail(self, test_name, begin_time):
+ for ad in self.android_devices:
+ # open Phone information page
+ ad.adb.shell("am start -n com.android.phone/.settings.RadioInfo")
+ time.sleep(3)
+ ad.screenshot(f"{ad.serial}_last_screen")
self._take_bug_report(test_name, begin_time)
def on_pass(self, test_name, begin_time):
diff --git a/acts_tests/acts_contrib/test_utils/tel/anritsu_utils.py b/acts_tests/acts_contrib/test_utils/tel/anritsu_utils.py
index 04a9e35..2e04dac 100644
--- a/acts_tests/acts_contrib/test_utils/tel/anritsu_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/anritsu_utils.py
@@ -47,11 +47,11 @@
from acts_contrib.test_utils.tel.tel_defines import EventSmsDeliverSuccess
from acts_contrib.test_utils.tel.tel_defines import EventSmsSentSuccess
from acts_contrib.test_utils.tel.tel_defines import EventSmsReceived
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_idle
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_droid_not_in_call
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_droid_not_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call
# Timers
# Time to wait after registration before sending a command to Anritsu
@@ -480,7 +480,7 @@
None
"""
# Setting IP address for internet connection sharing
- # Google Fi _init_PDN
+ # Google Fi _init_PDN
if sim_card == FiTMO or sim_card == FiSPR or sim_card == FiUSCC:
pdn.ue_address_ipv4 = ipv4
pdn.ue_address_ipv6 = ipv6
@@ -498,9 +498,9 @@
pdn.secondary_dns_address_ipv4 = Fi_DNS_IPV4_ADDR_Sec
pdn.dns_address_ipv6 = Fi_DNS_IPV6_ADDR
pdn.cscf_address_ipv4 = Fi_CSCF_IPV4_ADDR_Data
- pdn.cscf_address_ipv6 = Fi_CSCF_IPV6_ADDR_Data
+ pdn.cscf_address_ipv6 = Fi_CSCF_IPV6_ADDR_Data
# Pixel Lab _init_PDN_
- else:
+ else:
anritsu_handle.gateway_ipv4addr = GATEWAY_IPV4_ADDR
pdn.ue_address_ipv4 = ipv4
pdn.ue_address_ipv6 = ipv6
@@ -550,7 +550,7 @@
vnid.cscf_monitoring_ua = CSCF_Monitoring_UA_URI
vnid.psap = Switch.ENABLE
vnid.psap_auto_answer = Switch.ENABLE
- else:
+ else:
vnid.cscf_address_ipv4 = CSCF_IPV4_ADDR
vnid.cscf_address_ipv6 = ipv6_address
vnid.imscscf_iptype = ip_type
diff --git a/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py b/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py
index b93baed..2e4cfd4 100644
--- a/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/gft_inout_utils.py
@@ -15,27 +15,27 @@
# limitations under the License.
import time
-
-from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
-from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
-from acts_contrib.test_utils.tel.tel_test_utils import log_screen_shot
-from acts_contrib.test_utils.tel.tel_ims_utils import is_ims_registered
-from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
-from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
from acts_contrib.test_utils.tel.gft_inout_defines import VOLTE_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import CSFB_CALL
from acts_contrib.test_utils.tel.gft_inout_defines import WFC_CALL
+from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
+from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
+from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
+from acts_contrib.test_utils.tel.tel_ims_utils import is_ims_registered
+from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
+from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_volte
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_csfb
+from acts_contrib.test_utils.tel.tel_data_utils import browsing_test
-def check_no_service_time(ad, timeout=60):
+def check_no_service_time(ad, timeout=120):
""" check device is no service or not
Args:
@@ -60,7 +60,8 @@
%(timeout, service_state))
return False
-def check_back_to_service_time(ad, timeout=30):
+
+def check_back_to_service_time(ad, timeout=120):
""" check device is back to service or not
Args:
@@ -75,7 +76,8 @@
if service_state == SERVICE_STATE_IN_SERVICE:
if i==0:
check_network_service(ad)
- ad.log.info("Skip check_back_to_service_time. Device is in-service and service_state=%s" %(service_state))
+ ad.log.info("Skip check_back_to_service_time. Service_state=%s"
+ %(service_state))
return True
else:
ad.log.info("device is back to service in %s sec and service_state=%s"
@@ -88,6 +90,7 @@
%(timeout, service_state))
return False
+
def check_network_service(ad):
""" check network service
@@ -106,11 +109,13 @@
ad.log.info("networkType_data=%s" %(network_type_data))
ad.log.info("service_state=%s" %(service_state))
if service_state == SERVICE_STATE_OUT_OF_SERVICE:
+ log_screen_shot(ad, "device_out_of_service")
return False
return True
-def mo_voice_call(log, ad, call_type, end_call=True, talk_time=15):
+def mo_voice_call(log, ad, call_type, end_call=True, talk_time=15,
+ retries=1, retry_time=30):
""" MO voice call and check call type.
End call if necessary.
@@ -120,24 +125,32 @@
call_type: WFC call, VOLTE call. CSFB call, voice call
end_call: hangup call after voice call flag
talk_time: in call duration in sec
+ retries: retry times
+ retry_time: wait for how many sec before next retry
Returns:
True if pass; False if fail.
"""
callee_number = ad.mt_phone_number
- ad.log.info("MO voice call")
+ ad.log.info("MO voice call. call_type=%s" %(call_type))
if is_phone_in_call(log, ad):
ad.log.info("%s is in call. hangup_call before initiate call" %(callee_number))
hangup_call(log, ad)
time.sleep(1)
- if initiate_call(log, ad, callee_number):
- time.sleep(5)
- check_voice_call_type(ad,call_type)
- get_voice_call_type(ad)
- else:
- ad.log.error("initiate_call fail")
- return False
+ for i in range(retries):
+ ad.log.info("mo_voice_call attempt %d", i + 1)
+ if initiate_call(log, ad, callee_number):
+ time.sleep(5)
+ check_voice_call_type(ad,call_type)
+ get_voice_call_type(ad)
+ break
+ else:
+ ad.log.error("initiate_call fail attempt %d", i + 1)
+ time.sleep(retry_time)
+ if i+1 == retries:
+ ad.log.error("mo_voice_call retry failure")
+ return False
time.sleep(10)
if end_call:
@@ -146,10 +159,14 @@
ad.log.info("end voice call")
if not hangup_call(log, ad):
ad.log.error("end call fail")
+ ad.droid.telecomShowInCallScreen()
+ log_screen_shot(ad, "end_call_fail")
return False
else:
#Call drop is unexpected
ad.log.error("%s Unexpected call drop" %(call_type))
+ ad.droid.telecomShowInCallScreen()
+ log_screen_shot(ad, "call_drop")
return False
ad.log.info("%s successful" %(call_type))
return True
@@ -166,6 +183,7 @@
True if pass; False if fail.
"""
if is_phone_in_call(ad.log, ad):
+ ad.droid.telecomShowInCallScreen()
log_screen_shot(ad, "expected_call_type_%s" %call_type)
if call_type == CSFB_CALL:
if not is_phone_in_call_csfb(ad.log, ad):
@@ -214,31 +232,36 @@
ad.log.error("device is not in call")
return "UNKNOWN"
-def verify_data_connection(ad):
+
+def verify_data_connection(ad, retries=3, retry_time=30):
""" verify data connection
Args:
ad: android device
+ retries: retry times
+ retry_time: wait for how many sec before next retry
Returns:
True if pass; False if fail.
"""
- data_state = ad.droid.telephonyGetDataConnectionState()
- wifi_info = ad.droid.wifiGetConnectionInfo()
- if wifi_info["supplicant_state"] == "completed":
- ad.log.info("Wifi is connected=%s" %(wifi_info["SSID"]))
- if data_state != DATA_STATE_CONNECTED:
- ad.log.info("data is not connected. data_state=%s" %(data_state))
- return False
- else:
+ for i in range(retries):
+ data_state = ad.droid.telephonyGetDataConnectionState()
+ wifi_info = ad.droid.wifiGetConnectionInfo()
+ if wifi_info["supplicant_state"] == "completed":
+ ad.log.info("Wifi is connected=%s" %(wifi_info["SSID"]))
+ ad.log.info("verify_data_connection attempt %d", i + 1)
if not verify_internet_connection(ad.log, ad, retries=3):
data_state = ad.droid.telephonyGetDataConnectionState()
network_type_data = ad.droid.telephonyGetCurrentDataNetworkType()
ad.log.error("verify_internet fail. data_state=%s, network_type_data=%s"
- %(data_state, network_type_data))
- return False
- ad.log.info("verify_data_connection pass")
- return True
+ %(data_state, network_type_data))
+ ad.log.info("verify_data_connection fail attempt %d", i + 1)
+ log_screen_shot(ad, "verify_internet")
+ time.sleep(retry_time)
+ else:
+ ad.log.info("verify_data_connection pass")
+ return True
+ return False
def check_ims_state(ad):
@@ -261,6 +284,22 @@
return r1
+def browsing_test_ping_retry(ad):
+ """ If browse test fails, use ping to test data connection
+ Args:
+ ad: android device
-
+ Returns:
+ True if pass; False if fail.
+ """
+ if not browsing_test(ad.log, ad):
+ ad.log.error("Failed to browse websites!")
+ if verify_data_connection(ad):
+ ad.log.info("Ping success!")
+ return True
+ else:
+ ad.log.info("Ping fail!")
+ return False
+ else:
+ ad.log.info("Successful to browse websites!")
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py
index 9635738..6789647 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_5g_test_utils.py
@@ -15,13 +15,8 @@
# limitations under the License.
import time
-import random
-import re
-from queue import Empty
-from acts.utils import rand_ascii_str
from acts.libs.utils.multithread import multithread_func
-from acts_contrib.test_utils.tel.tel_defines import GEN_5G
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_LTE_GSM_WCDMA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_ONLY
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
@@ -30,59 +25,70 @@
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_WCDMA_ONLY
-from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_volte
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_csfb
from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_sa
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_volte
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_csfb
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_generation
+from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import get_current_override_network_type
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
-def provision_device_for_5g(log, ads, nr_type=None):
+def provision_device_for_5g(log, ads, nr_type = None, sub_id = None,
+ mmwave = None):
"""Provision Devices for 5G
Args:
log: Log object.
ads: android device object(s).
- nr_type: NR network type
+ nr_type: NR network type.
+ sub_id: The target SIM for querying.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: Device(s) are provisioned on 5G
False: Device(s) are not provisioned on 5G
"""
if nr_type == 'sa':
- if not provision_device_for_5g_sa(log, ads):
+ if not provision_device_for_5g_sa(
+ log, ads, sub_id=sub_id, mmwave=mmwave):
return False
elif nr_type == 'nsa':
- if not provision_device_for_5g_nsa(log, ads, nr_type='nsa'):
+ if not provision_device_for_5g_nsa(
+ log, ads, sub_id=sub_id, mmwave=mmwave):
return False
elif nr_type == 'mmwave':
- if not provision_device_for_5g_nsa(log, ads, nr_type='mmwave'):
+ if not provision_device_for_5g_nsa(
+ log, ads, sub_id=sub_id, mmwave=mmwave):
return False
else:
- if not provision_device_for_5g_nsa(log, ads, nr_type='nsa'):
+ if not provision_device_for_5g_nsa(
+ log, ads, sub_id=sub_id, mmwave=mmwave):
return False
return True
-def provision_device_for_5g_nsa(log, ads, nr_type=None):
+def provision_device_for_5g_nsa(log, ads, sub_id = None, mmwave = None):
"""Provision Devices for 5G NSA
Args:
log: Log object.
ads: android device object(s).
- nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
- wave
+ sub_id: The target SIM for querying.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: Device(s) are provisioned on 5G NSA
False: Device(s) are not provisioned on 5G NSA
"""
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
if isinstance(ads, list):
# Mode Pref
tasks = [(set_preferred_mode_for_5g, [ad]) for ad in ads]
@@ -90,7 +96,7 @@
log.error("failed to set preferred network mode on 5g")
return False
# Attach
- tasks = [(is_current_network_5g_nsa, [ad, nr_type]) for ad in ads]
+ tasks = [(is_current_network_5g_nsa, [ad, sub_id, mmwave]) for ad in ads]
if not multithread_func(log, tasks):
log.error("phone not on 5g")
return False
@@ -100,7 +106,7 @@
set_preferred_mode_for_5g(ads)
# Attach nsa5g
- if not is_current_network_5g_nsa(ads, nr_type):
+ if not is_current_network_5g_nsa(ads, sub_id, mmwave):
ads.log.error("Phone not attached on 5g")
return False
return True
@@ -182,29 +188,35 @@
return True
-def verify_5g_attach_for_both_devices(log, ads, nr_type=None):
+def verify_5g_attach_for_both_devices(log, ads, sub_id = None, nr_type = None,
+ mmwave = None):
"""Verify the network is attached
Args:
log: Log object.
ads: android device object(s).
- nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
- wave
+ sub_id: The target SIM for querying.
+ nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone,
+ 'mmwave' for 5G millimeter wave.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: Device(s) are attached on 5G
False: Device(s) are not attached on 5G NSA
"""
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
if nr_type=='sa':
# Attach
- tasks = [(is_current_network_5g_sa, [ad]) for ad in ads]
+ tasks = [(is_current_network_5g_sa, [ad, sub_id, mmwave]) for ad in ads]
if not multithread_func(log, tasks):
log.error("phone not on 5g sa")
return False
return True
else:
# Attach
- tasks = [(is_current_network_5g_nsa, [ad, nr_type]) for ad in ads]
+ tasks = [(is_current_network_5g_nsa, [ad, sub_id, mmwave]) for ad in ads]
if not multithread_func(log, tasks):
log.error("phone not on 5g nsa")
return False
@@ -225,17 +237,22 @@
return set_preferred_network_mode_pref(ad.log, ad, sub_id, mode)
-def provision_device_for_5g_sa(log, ads):
+def provision_device_for_5g_sa(log, ads, sub_id = None, mmwave = None):
"""Provision Devices for 5G SA
Args:
log: Log object.
ads: android device object(s).
+ sub_id: The target SIM for querying.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: Device(s) are provisioned on 5G SA
False: Device(s) are not provisioned on 5G SA
"""
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
if isinstance(ads, list):
# Mode Pref
tasks = [(set_preferred_mode_for_5g, [ad, None, NETWORK_MODE_NR_ONLY]) for ad in ads]
@@ -243,7 +260,7 @@
log.error("failed to set preferred network mode on 5g SA")
return False
- tasks = [(is_current_network_5g_sa, [ad]) for ad in ads]
+ tasks = [(is_current_network_5g_sa, [ad, sub_id, mmwave]) for ad in ads]
if not multithread_func(log, tasks):
log.error("phone not on 5g SA")
return False
@@ -252,46 +269,59 @@
# Mode Pref
set_preferred_mode_for_5g(ads, None, NETWORK_MODE_NR_ONLY)
- if not is_current_network_5g_sa(ads):
+ if not is_current_network_5g_sa(ads, sub_id, mmwave):
ads.log.error("Phone not attached on SA 5g")
return False
return True
-def check_current_network_5g(ad, timeout=30, nr_type=None):
+def check_current_network_5g(
+ ad, sub_id = None, nr_type = None, mmwave = None, timeout = 30):
"""Verifies data network type is on 5G
Args:
ad: android device object.
+ sub_id: The target SIM for querying.
timeout: max time to wait for event
nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
- wave
+ wave.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: if data is on 5g
False: if data is not on 5g
"""
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
if nr_type == 'sa':
- if not is_current_network_5g_sa(ad):
+ if not is_current_network_5g_sa(ad, sub_id, mmwave=mmwave):
return False
else:
- if not is_current_network_5g_nsa(ad, nr_type= nr_type, timeout=timeout):
+ if not is_current_network_5g_nsa(ad, sub_id, mmwave=mmwave,
+ timeout=timeout):
return False
return True
-def test_activation_by_condition(ad, from_3g=False, nr_type=None, precond_func=None):
+def test_activation_by_condition(ad, sub_id=None, from_3g=False, nr_type=None,
+ precond_func=None, mmwave=None):
"""Test 5G activation based on various pre-conditions.
Args:
ad: android device object.
+ sub_id: The target SIM for querying.
from_3g: If true, test 5G activation from 3G attaching. Otherwise, starting from 5G attaching.
nr_type: check the band of NR network. Default is to check sub-6.
precond_func: A function to execute pre conditions before testing 5G activation.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
If success, return true. Otherwise, return false.
"""
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
wifi_toggle_state(ad.log, ad, False)
toggle_airplane_mode(ad.log, ad, False)
if not from_3g:
@@ -318,7 +348,7 @@
ad.log.error("Fail to ensure initial data in 4G")
# 5G attach
ad.log.info("Waiting for 5g NSA attach for 60 secs")
- if is_current_network_5g_nsa(ad, nr_type= nr_type, timeout=60):
+ if is_current_network_5g_nsa(ad, sub_id, mmwave=mmwave, timeout=60):
ad.log.info("Success! attached on 5g NSA")
return True
else:
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py
index 58ce9ee..f35272e 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_5g_utils.py
@@ -19,140 +19,121 @@
from acts_contrib.test_utils.tel.tel_defines import DisplayInfoContainer
from acts_contrib.test_utils.tel.tel_defines import EventDisplayInfoChanged
-def is_current_network_5g_nsa(ad, nr_type=None, timeout=30):
+def is_current_network_5g_nsa(ad, sub_id = None, mmwave = None, timeout=30):
"""Verifies 5G NSA override network type
Args:
ad: android device object.
- nr_type: 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
- wave
+ sub_id: The target SIM for querying.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
timeout: max time to wait for event.
Returns:
True: if data is on nsa5g NSA
False: if data is not on nsa5g NSA
"""
- ad.ed.clear_events(EventDisplayInfoChanged)
- ad.droid.telephonyStartTrackingDisplayInfoChange()
- if nr_type == 'mmwave':
- nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_MMWAVE
- elif nr_type == 'nsa':
- nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
+ def _nsa_display_monitor(ad, sub_id, mmwave, timeout):
+ ad.ed.clear_events(EventDisplayInfoChanged)
+ ad.droid.telephonyStartTrackingDisplayInfoChangeForSubscription(sub_id)
+ if mmwave:
+ nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_MMWAVE
+ else:
+ nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA
+ try:
+ event = ad.ed.wait_for_event(
+ EventDisplayInfoChanged,
+ ad.ed.is_event_match,
+ timeout=timeout,
+ field=DisplayInfoContainer.OVERRIDE,
+ value=nsa_band)
+ ad.log.info("Got expected event %s", event)
+ return True
+ except Empty:
+ ad.log.info("No event for display info change with <%s>", nsa_band)
+ ad.screenshot("5g_nsa_icon_checking")
+ return False
+ finally:
+ ad.droid.telephonyStopTrackingServiceStateChangeForSubscription(
+ sub_id)
+
+ if mmwave is None:
+ return _nsa_display_monitor(
+ ad, sub_id, mmwave=False, timeout=timeout) or _nsa_display_monitor(
+ ad, sub_id, mmwave=True, timeout=timeout)
else:
- nsa_band = OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA
- try:
- event = ad.ed.wait_for_event(
- EventDisplayInfoChanged,
- ad.ed.is_event_match,
- timeout=timeout,
- field=DisplayInfoContainer.OVERRIDE,
- value=nsa_band)
- ad.log.info("Got expected event %s", event)
- return True
- except Empty:
- ad.log.info("No event for display info change")
- ad.screenshot("5g_nsa_icon_checking")
- return False
- finally:
- ad.droid.telephonyStopTrackingDisplayInfoChange()
- return None
+ return _nsa_display_monitor(ad, sub_id, mmwave, timeout)
-def is_current_network_5g_nsa_for_subscription(ad, nr_type=None, timeout=30, sub_id=None):
- """Verifies 5G NSA override network type for subscription id.
- Args:
- ad: android device object.
- nr_type: 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter wave
- timeout: max time to wait for event.
- sub_id: subscription id.
-
- Returns:
- True: if data is on nsa5g NSA
- False: if data is not on nsa5g NSA
- """
- if not sub_id:
- return is_current_network_5g_nsa(ad, nr_type=nr_type)
-
- voice_sub_id_changed = False
- current_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
- if current_sub_id != sub_id:
- ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
- voice_sub_id_changed = True
-
- result = is_current_network_5g_nsa(ad, nr_type=nr_type)
-
- if voice_sub_id_changed:
- ad.droid.subscriptionSetDefaultVoiceSubId(current_sub_id)
-
- return result
-
-
-def is_current_network_5g_sa(ad):
+def is_current_network_5g_sa(ad, sub_id = None, mmwave = None):
"""Verifies 5G SA override network type
Args:
ad: android device object.
+ sub_id: The target SIM for querying.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
Returns:
True: if data is on 5g SA
False: if data is not on 5g SA
"""
- network_connected = ad.droid.telephonyGetCurrentDataNetworkType()
- if network_connected == 'NR':
- ad.log.debug("Network is currently connected to %s", network_connected)
- return True
- else:
- ad.log.error("Network is currently connected to %s, Expected on NR", network_connected)
- ad.screenshot("5g_sa_icon_checking")
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+ current_rat = ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
+ sub_id)
+ # TODO(richardwychang): check SA MMWAVE when function ready.
+ sa_type = ['NR',]
+ if mmwave is None:
+ if current_rat in sa_type:
+ ad.log.debug("Network is currently connected to %s", current_rat)
+ return True
+ else:
+ ad.log.error(
+ "Network is currently connected to %s, Expected on %s",
+ current_rat, sa_type)
+ ad.screenshot("5g_sa_icon_checking")
+ return False
+ elif mmwave:
+ ad.log.error("SA MMWAVE currently not support.")
return False
+ else:
+ if current_rat == 'NR':
+ ad.log.debug("Network is currently connected to %s", current_rat)
+ return True
+ else:
+ ad.log.error(
+ "Network is currently connected to %s, Expected on NR",
+ current_rat)
+ ad.screenshot("5g_sa_icon_checking")
+ return False
-def is_current_network_5g(ad, nr_type=None, timeout=30):
+def is_current_network_5g(ad, sub_id = None, nr_type = None, mmwave = None,
+ timeout = 30):
"""Verifies 5G override network type
Args:
ad: android device object
- nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
- wave
+ sub_id: The target SIM for querying.
+ nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone.
+ mmwave: True to detect 5G millimeter wave, False to detect sub-6,
+ None to detect both.
timeout: max time to wait for event.
Returns:
True: if data is on 5G regardless of SA or NSA
False: if data is not on 5G refardless of SA or NSA
"""
+ sub_id = sub_id if sub_id else ad.droid.subscriptionGetDefaultDataSubId()
+
if nr_type == 'nsa':
- return is_current_network_5g_nsa(ad, nr_type = 'nsa', timeout=timeout)
+ return is_current_network_5g_nsa(
+ ad, sub_id=sub_id, mmwave=mmwave, timeout=timeout)
elif nr_type == 'sa':
- return is_current_network_5g_sa(ad)
- elif nr_type == 'mmwave':
- return is_current_network_5g_nsa(ad, nr_type = 'mmwave', timeout=timeout)
+ return is_current_network_5g_sa(ad, sub_id=sub_id, mmwave=mmwave)
else:
- return is_current_network_5g_nsa(ad, nr_type=None) or is_current_network_5g_sa(ad)
-
-
-def is_current_network_5g_for_subscription(ad, sub_id=None, nr_type=None):
- """Verifies 5G override network type for subscription id.
- Args:
- ad: android device object
- sub_id: subscription id
- nr_type: 'sa' for 5G standalone, 'nsa' for 5G non-standalone, 'mmwave' for 5G millimeter
- wave
-
- Returns:
- True: if data is on 5G regardless of NSA or SA.
- False: if data is not on 5G regardless of NSA or SA.
- """
- if not sub_id:
- return is_current_network_5g(ad, nr_type=nr_type)
-
- voice_sub_id_changed = False
- current_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
- if current_sub_id != sub_id:
- ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
- voice_sub_id_changed = True
-
- result = is_current_network_5g(ad, nr_type=nr_type)
-
- if voice_sub_id_changed:
- ad.droid.subscriptionSetDefaultVoiceSubId(current_sub_id)
-
- return result
+ return is_current_network_5g_nsa(
+ ad, sub_id=sub_id, mmwave=mmwave,
+ timeout=timeout) or is_current_network_5g_sa(
+ ad, sub_id=sub_id, mmwave=mmwave)
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py
new file mode 100644
index 0000000..8f754ed
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_bt_utils.py
@@ -0,0 +1,187 @@
+#!/usr/bin/env python3
+#
+# Copyright 2022 - Google
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import time
+
+from acts_contrib.test_utils.bt.bt_test_utils import bluetooth_enabled_check
+from acts_contrib.test_utils.bt.bt_test_utils import disable_bluetooth
+from acts_contrib.test_utils.bt.bt_test_utils import pair_pri_to_sec
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
+from acts_contrib.test_utils.tel.tel_data_utils import test_internet_connection
+from acts_contrib.test_utils.tel.tel_data_utils import wait_for_cell_data_connection
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+
+
+def enable_bluetooth_tethering_connection(log, provider, clients):
+ for ad in [provider] + clients:
+ if not bluetooth_enabled_check(ad):
+ ad.log.info("Bluetooth is not enabled")
+ return False
+ else:
+ ad.log.info("Bluetooth is enabled")
+ time.sleep(5)
+ provider.log.info("Provider enabling bluetooth tethering")
+ try:
+ provider.droid.bluetoothPanSetBluetoothTethering(True)
+ except Exception as e:
+ provider.log.warning(
+ "Failed to enable provider Bluetooth tethering with %s", e)
+ provider.droid.bluetoothPanSetBluetoothTethering(True)
+
+ if wait_for_state(provider.droid.bluetoothPanIsTetheringOn, True):
+ provider.log.info("Provider Bluetooth tethering is enabled.")
+ else:
+ provider.log.error(
+ "Failed to enable provider Bluetooth tethering.")
+ provider.log.error("bluetoothPanIsTetheringOn = %s",
+ provider.droid.bluetoothPanIsTetheringOn())
+ return False
+ for client in clients:
+ if not (pair_pri_to_sec(provider, client)):
+ client.log.error("Client failed to pair with provider")
+ return False
+ else:
+ client.log.info("Client paired with provider")
+
+ time.sleep(5)
+ for client in clients:
+ client.droid.bluetoothConnectBonded(provider.droid.bluetoothGetLocalAddress())
+
+ time.sleep(20)
+ return True
+
+
+def verify_bluetooth_tethering_connection(log, provider, clients,
+ change_rat=None,
+ toggle_data=False,
+ toggle_tethering=False,
+ voice_call=False,
+ toggle_bluetooth=True):
+ """Setups up a bluetooth tethering connection between two android devices.
+
+ Returns:
+ True if PAN connection and verification is successful,
+ false if unsuccessful.
+ """
+
+
+ if not enable_bluetooth_tethering_connection(log, provider, clients):
+ return False
+
+ if not test_internet_connection(log, provider, clients):
+ log.error("Internet connection check failed")
+ return False
+ if voice_call:
+ log.info("====== Voice call test =====")
+ for caller, callee in [(provider, clients[0]),
+ (clients[0], provider)]:
+ if not call_setup_teardown(
+ log, caller, callee, ad_hangup=None):
+ log.error("Setup Call Failed.")
+ hangup_call(log, caller)
+ return False
+ log.info("Verify data.")
+ if not verify_internet_connection(
+ log, clients[0], retries=1):
+ clients[0].log.warning(
+ "client internet connection state is not on")
+ else:
+ clients[0].log.info(
+ "client internet connection state is on")
+ hangup_call(log, caller)
+ if not verify_internet_connection(
+ log, clients[0], retries=1):
+ clients[0].log.warning(
+ "client internet connection state is not on")
+ return False
+ else:
+ clients[0].log.info(
+ "client internet connection state is on")
+ if toggle_tethering:
+ log.info("====== Toggling provider bluetooth tethering =====")
+ provider.log.info("Disable bluetooth tethering")
+ provider.droid.bluetoothPanSetBluetoothTethering(False)
+ if not test_internet_connection(log, provider, clients, False, True):
+ log.error(
+ "Internet connection check failed after disable tethering")
+ return False
+ provider.log.info("Enable bluetooth tethering")
+ if not enable_bluetooth_tethering_connection(log,
+ provider, clients):
+ provider.log.error(
+ "Fail to re-enable bluetooth tethering")
+ return False
+ if not test_internet_connection(log, provider, clients, True, True):
+ log.error(
+ "Internet connection check failed after enable tethering")
+ return False
+ if toggle_bluetooth:
+ log.info("====== Toggling provider bluetooth =====")
+ provider.log.info("Disable provider bluetooth")
+ disable_bluetooth(provider.droid)
+ time.sleep(10)
+ if not test_internet_connection(log, provider, clients, False, True):
+ log.error(
+ "Internet connection check failed after disable bluetooth")
+ return False
+ if not enable_bluetooth_tethering_connection(log,
+ provider, clients):
+ provider.log.error(
+ "Fail to re-enable bluetooth tethering")
+ return False
+ if not test_internet_connection(log, provider, clients, True, True):
+ log.error(
+ "Internet connection check failed after enable bluetooth")
+ return False
+ if toggle_data:
+ log.info("===== Toggling provider data connection =====")
+ provider.log.info("Disable provider data connection")
+ provider.droid.telephonyToggleDataConnection(False)
+ time.sleep(10)
+ if not test_internet_connection(log, provider, clients, False, False):
+ return False
+ provider.log.info("Enable provider data connection")
+ provider.droid.telephonyToggleDataConnection(True)
+ if not wait_for_cell_data_connection(log, provider,
+ True):
+ provider.log.error(
+ "Provider failed to enable data connection.")
+ return False
+ if not test_internet_connection(log, provider, clients, True, True):
+ log.error(
+ "Internet connection check failed after enable data")
+ return False
+ if change_rat:
+ log.info("===== Change provider RAT to %s =====", change_rat)
+ if not ensure_network_generation(
+ log,
+ provider,
+ change_rat,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ toggle_apm_after_setting=False):
+ provider.log.error("Provider failed to reselect to %s.",
+ change_rat)
+ return False
+ if not test_internet_connection(log, provider, clients, True, True):
+ log.error(
+ "Internet connection check failed after RAT change to %s",
+ change_rat)
+ return False
+ return True
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py
index 27572fe..05808f9 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_data_utils.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2021 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,88 +14,102 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+
+import logging
+import os
import time
import random
from queue import Empty
+from acts.controllers.android_device import SL4A_APK_NAME
from acts.utils import adb_shell_ping
from acts.utils import rand_ascii_str
from acts.utils import disable_doze
from acts.utils import enable_doze
from acts.libs.utils.multithread import multithread_func
from acts.libs.utils.multithread import run_multithread_func
-from acts_contrib.test_utils.bt.bt_test_utils import bluetooth_enabled_check
-from acts_contrib.test_utils.bt.bt_test_utils import disable_bluetooth
-from acts_contrib.test_utils.bt.bt_test_utils import pair_pri_to_sec
from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
+from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
+from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_DISCONNECTED
from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
+from acts_contrib.test_utils.tel.tel_defines import EventConnectivityChanged
from acts_contrib.test_utils.tel.tel_defines import EventNetworkCallback
from acts_contrib.test_utils.tel.tel_defines import GEN_5G
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_USER_PLANE_DATA
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WIFI_CONNECTION
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_CELL
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_WIFI
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
from acts_contrib.test_utils.tel.tel_defines import RAT_5G
+from acts_contrib.test_utils.tel.tel_defines import TETHERING_MODE_WIFI
+from acts_contrib.test_utils.tel.tel_defines import TYPE_MOBILE
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_AFTER_REBOOT
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_DATA_STATUS_CHANGE_DURING_WIFI_TETHERING
-from acts_contrib.test_utils.tel.tel_defines import TETHERING_MODE_WIFI
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TETHERING_ENTITLEMENT_CHECK
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_NW_VALID_FAIL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL_RECOVERY
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL_FOR_IMS
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_TETHERING_AFTER_REBOOT
+from acts_contrib.test_utils.tel.tel_defines import DataConnectionStateContainer
+from acts_contrib.test_utils.tel.tel_defines import EventDataConnectionStateChanged
+from acts_contrib.test_utils.tel.tel_5g_test_utils import check_current_network_5g
+from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
+from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
from acts_contrib.test_utils.tel.tel_ims_utils import is_ims_registered
from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_ims_registered
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import check_is_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_mobile_data_usage
+from acts_contrib.test_utils.tel.tel_lookup_tables import connection_type_from_type_string
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_default_state
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_voice_attach_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import _check_file_existence
+from acts_contrib.test_utils.tel.tel_test_utils import _generate_file_directory_and_file_name
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state
+from acts_contrib.test_utils.tel.tel_test_utils import get_internet_connection_type
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import get_service_state_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import get_wifi_usage
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_network_generation_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import is_event_match
from acts_contrib.test_utils.tel.tel_test_utils import rat_generation_from_rat
-from acts_contrib.test_utils.tel.tel_test_utils import set_wifi_to_default
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
-from acts_contrib.test_utils.tel.tel_test_utils import start_wifi_tethering
-from acts_contrib.test_utils.tel.tel_test_utils import stop_wifi_tethering
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
from acts_contrib.test_utils.tel.tel_test_utils import verify_internet_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_cell_data_connection
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_voice_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_wifi_data_connection
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_2G
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_CONFIG_APBAND_5G
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_reset
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_task
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import WIFI_SSID_KEY
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call_active
-from acts_contrib.test_utils.tel.tel_5g_test_utils import check_current_network_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import provision_device_for_5g
-from acts_contrib.test_utils.tel.tel_5g_test_utils import verify_5g_attach_for_both_devices
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan
-from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_idle_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_active
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_iwlan
+from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_short_seq
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_2G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_CONFIG_APBAND_5G
+from acts_contrib.test_utils.tel.tel_wifi_utils import WIFI_SSID_KEY
+from acts_contrib.test_utils.tel.tel_wifi_utils import check_is_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import get_wifi_usage
+from acts_contrib.test_utils.tel.tel_wifi_utils import set_wifi_to_default
+from acts_contrib.test_utils.tel.tel_wifi_utils import start_wifi_tethering
+from acts_contrib.test_utils.tel.tel_wifi_utils import stop_wifi_tethering
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_reset
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
def wifi_tethering_cleanup(log, provider, client_list):
@@ -513,7 +527,7 @@
return False
if nw_gen == GEN_5G:
- if not check_current_network_5g(ad, timeout=60, nr_type=nr_type):
+ if not check_current_network_5g(ad, nr_type=nr_type, timeout=60):
return False
else:
if not is_droid_in_network_generation_for_subscription(
@@ -862,7 +876,7 @@
ensure_phones_idle(log, ad_list)
if nw_gen == GEN_5G:
- if not provision_device_for_5g(log, android_devices, nr_type= nr_type):
+ if not provision_device_for_5g(log, android_devices, nr_type=nr_type):
return False
elif nw_gen:
if not ensure_network_generation_for_subscription(
@@ -1018,7 +1032,7 @@
ensure_phones_idle(log, clients)
wifi_toggle_state(log, provider, False)
if network_generation == RAT_5G:
- if not provision_device_for_5g(log, provider, nr_type= nr_type):
+ if not provision_device_for_5g(log, provider, nr_type=nr_type):
return False
elif network_generation:
if not ensure_network_generation(
@@ -1042,7 +1056,7 @@
provider.log.info("Disable provider wifi tethering")
stop_wifi_tethering(log, provider)
provider.log.info("Provider disable bluetooth")
- disable_bluetooth(provider.droid)
+ provider.droid.bluetoothToggleState(False)
time.sleep(10)
for ad in clients:
@@ -1052,7 +1066,7 @@
ad.log.info("Client disable data")
ad.droid.telephonyToggleDataConnection(False)
ad.log.info("Client disable bluetooth")
- disable_bluetooth(ad.droid)
+ ad.droid.bluetoothToggleState(False)
ad.log.info("Client disable wifi")
wifi_toggle_state(log, ad, False)
@@ -1071,164 +1085,6 @@
return True
-def enable_bluetooth_tethering_connection(log, provider, clients):
- for ad in [provider] + clients:
- if not bluetooth_enabled_check(ad):
- ad.log.info("Bluetooth is not enabled")
- return False
- else:
- ad.log.info("Bluetooth is enabled")
- time.sleep(5)
- provider.log.info("Provider enabling bluetooth tethering")
- try:
- provider.droid.bluetoothPanSetBluetoothTethering(True)
- except Exception as e:
- provider.log.warning(
- "Failed to enable provider Bluetooth tethering with %s", e)
- provider.droid.bluetoothPanSetBluetoothTethering(True)
-
- if wait_for_state(provider.droid.bluetoothPanIsTetheringOn, True):
- provider.log.info("Provider Bluetooth tethering is enabled.")
- else:
- provider.log.error(
- "Failed to enable provider Bluetooth tethering.")
- provider.log.error("bluetoothPanIsTetheringOn = %s",
- provider.droid.bluetoothPanIsTetheringOn())
- return False
- for client in clients:
- if not (pair_pri_to_sec(provider, client)):
- client.log.error("Client failed to pair with provider")
- return False
- else:
- client.log.info("Client paired with provider")
-
- time.sleep(5)
- for client in clients:
- client.droid.bluetoothConnectBonded(provider.droid.bluetoothGetLocalAddress())
-
- time.sleep(20)
- return True
-
-
-def verify_bluetooth_tethering_connection(log, provider, clients,
- change_rat=None,
- toggle_data=False,
- toggle_tethering=False,
- voice_call=False,
- toggle_bluetooth=True):
- """Setups up a bluetooth tethering connection between two android devices.
-
- Returns:
- True if PAN connection and verification is successful,
- false if unsuccessful.
- """
-
-
- if not enable_bluetooth_tethering_connection(log, provider, clients):
- return False
-
- if not test_internet_connection(log, provider, clients):
- log.error("Internet connection check failed")
- return False
- if voice_call:
- log.info("====== Voice call test =====")
- for caller, callee in [(provider, clients[0]),
- (clients[0], provider)]:
- if not call_setup_teardown(
- log, caller, callee, ad_hangup=None):
- log.error("Setup Call Failed.")
- hangup_call(log, caller)
- return False
- log.info("Verify data.")
- if not verify_internet_connection(
- log, clients[0], retries=1):
- clients[0].log.warning(
- "client internet connection state is not on")
- else:
- clients[0].log.info(
- "client internet connection state is on")
- hangup_call(log, caller)
- if not verify_internet_connection(
- log, clients[0], retries=1):
- clients[0].log.warning(
- "client internet connection state is not on")
- return False
- else:
- clients[0].log.info(
- "client internet connection state is on")
- if toggle_tethering:
- log.info("====== Toggling provider bluetooth tethering =====")
- provider.log.info("Disable bluetooth tethering")
- provider.droid.bluetoothPanSetBluetoothTethering(False)
- if not test_internet_connection(log, provider, clients, False, True):
- log.error(
- "Internet connection check failed after disable tethering")
- return False
- provider.log.info("Enable bluetooth tethering")
- if not enable_bluetooth_tethering_connection(log,
- provider, clients):
- provider.log.error(
- "Fail to re-enable bluetooth tethering")
- return False
- if not test_internet_connection(log, provider, clients, True, True):
- log.error(
- "Internet connection check failed after enable tethering")
- return False
- if toggle_bluetooth:
- log.info("====== Toggling provider bluetooth =====")
- provider.log.info("Disable provider bluetooth")
- disable_bluetooth(provider.droid)
- time.sleep(10)
- if not test_internet_connection(log, provider, clients, False, True):
- log.error(
- "Internet connection check failed after disable bluetooth")
- return False
- if not enable_bluetooth_tethering_connection(log,
- provider, clients):
- provider.log.error(
- "Fail to re-enable bluetooth tethering")
- return False
- if not test_internet_connection(log, provider, clients, True, True):
- log.error(
- "Internet connection check failed after enable bluetooth")
- return False
- if toggle_data:
- log.info("===== Toggling provider data connection =====")
- provider.log.info("Disable provider data connection")
- provider.droid.telephonyToggleDataConnection(False)
- time.sleep(10)
- if not test_internet_connection(log, provider, clients, False, False):
- return False
- provider.log.info("Enable provider data connection")
- provider.droid.telephonyToggleDataConnection(True)
- if not wait_for_cell_data_connection(log, provider,
- True):
- provider.log.error(
- "Provider failed to enable data connection.")
- return False
- if not test_internet_connection(log, provider, clients, True, True):
- log.error(
- "Internet connection check failed after enable data")
- return False
- if change_rat:
- log.info("===== Change provider RAT to %s =====", change_rat)
- if not ensure_network_generation(
- log,
- provider,
- change_rat,
- voice_or_data=NETWORK_SERVICE_DATA,
- toggle_apm_after_setting=False):
- provider.log.error("Provider failed to reselect to %s.",
- change_rat)
- return False
- if not test_internet_connection(log, provider, clients, True, True):
- log.error(
- "Internet connection check failed after RAT change to %s",
- change_rat)
- return False
- return True
-
-
def test_tethering_wifi_and_voice_call(log, provider, clients,
provider_data_rat,
provider_setup_func,
@@ -1246,7 +1102,7 @@
return False
if provider_setup_func == RAT_5G:
- if not provision_device_for_5g(log, provider, nr_type= nr_type):
+ if not provision_device_for_5g(log, provider, nr_type=nr_type):
return False
try:
log.info("1. Setup WiFi Tethering.")
@@ -1320,36 +1176,38 @@
True, False, True, False, False, True, False, False, False, False,
True, False, False, False, False, False, False, False, False
]
+ try:
+ for toggle in wifi_toggles:
- for toggle in wifi_toggles:
+ wifi_reset(log, ad, toggle)
- wifi_reset(log, ad, toggle)
+ if not wait_for_cell_data_connection(
+ log, ad, True, MAX_WAIT_TIME_WIFI_CONNECTION):
+ log.error("Failed data connection, aborting!")
+ return False
- if not wait_for_cell_data_connection(
- log, ad, True, MAX_WAIT_TIME_WIFI_CONNECTION):
- log.error("Failed wifi connection, aborting!")
- return False
+ if not verify_internet_connection(log, ad):
+ log.error("Failed to get user-plane traffic, aborting!")
+ return False
- if not verify_internet_connection(log, ad):
- log.error("Failed to get user-plane traffic, aborting!")
- return False
+ if toggle:
+ wifi_toggle_state(log, ad, True)
- if toggle:
- wifi_toggle_state(log, ad, True)
+ ensure_wifi_connected(log, ad, wifi_network_ssid,
+ wifi_network_pass)
- ensure_wifi_connected(log, ad, wifi_network_ssid,
- wifi_network_pass)
+ if not wait_for_wifi_data_connection(
+ log, ad, True, MAX_WAIT_TIME_WIFI_CONNECTION):
+ log.error("Failed wifi connection, aborting!")
+ return False
- if not wait_for_wifi_data_connection(
- log, ad, True, MAX_WAIT_TIME_WIFI_CONNECTION):
- log.error("Failed wifi connection, aborting!")
- return False
-
- if not verify_http_connection(
- log, ad, 'http://www.google.com', 100, .1):
- log.error("Failed to get user-plane traffic, aborting!")
- return False
- return True
+ if not verify_http_connection(
+ log, ad, 'http://www.google.com', 100, .1):
+ log.error("Failed to get user-plane traffic, aborting!")
+ return False
+ return True
+ finally:
+ wifi_toggle_state(log, ad, False)
def test_call_setup_in_active_data_transfer(
@@ -1391,7 +1249,7 @@
wait_time_in_call)
if nw_gen == GEN_5G:
- if not provision_device_for_5g(log, ads[0], nr_type= nr_type):
+ if not provision_device_for_5g(log, ads[0], nr_type=nr_type):
return False
elif nw_gen:
if not ensure_network_generation(log, ads[0], nw_gen,
@@ -1446,7 +1304,8 @@
return False
# Disable airplane mode if test under apm on.
toggle_airplane_mode(log, ads[0], False)
- if nw_gen == GEN_5G and not check_current_network_5g(ads[0], nr_type= nr_type):
+ if nw_gen == GEN_5G and not check_current_network_5g(ads[0],
+ nr_type=nr_type):
ads[0].log.error("Phone not attached on 5G after call.")
return False
return True
@@ -1477,7 +1336,7 @@
False if failed.
"""
if nw_gen == GEN_5G:
- if not provision_device_for_5g(log, ads[0], nr_type= nr_type):
+ if not provision_device_for_5g(log, ads[0], nr_type=nr_type):
return False
elif nw_gen:
if not ensure_network_generation(log, ads[0], nw_gen,
@@ -1524,7 +1383,8 @@
ad_download.force_stop_apk("com.google.android.youtube")
# Disable airplane mode if test under apm on.
toggle_airplane_mode(log, ads[0], False)
- if nw_gen == GEN_5G and not check_current_network_5g(ads[0], nr_type= nr_type):
+ if nw_gen == GEN_5G and not check_current_network_5g(ads[0],
+ nr_type=nr_type):
ads[0].log.error("Phone not attached on 5G after call.")
result = False
return result
@@ -1594,7 +1454,8 @@
time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- if nw_gen == GEN_5G and not verify_5g_attach_for_both_devices(log, ads, nr_type= nr_type):
+ if nw_gen == GEN_5G and not verify_5g_attach_for_both_devices(
+ log, ads, nr_type=nr_type):
log.error("Phone not attached on 5G after epdg call.")
return False
@@ -1695,7 +1556,7 @@
ssid=None,
password=None,
pre_teardown_func=None,
- nr_type= None):
+ nr_type=None):
"""WiFi Tethering test
Args:
log: log object.
@@ -1721,7 +1582,7 @@
nr_type: NR network type e.g. NSA, SA, MMWAVE.
"""
- if not test_setup_tethering(log, provider, clients, nw_gen, nr_type= nr_type):
+ if not test_setup_tethering(log, provider, clients, nw_gen, nr_type=nr_type):
log.error("Verify %s Internet access failed.", nw_gen)
return False
@@ -2022,7 +1883,7 @@
provider,
clients,
new_gen=None,
- nr_type= None):
+ nr_type=None):
"""Verify toggle Data network during WiFi Tethering.
Args:
log: log object.
@@ -2047,7 +1908,7 @@
check_iteration=2,
do_cleanup=False,
ssid=ssid,
- nr_type= nr_type):
+ nr_type=nr_type):
log.error("WiFi Tethering failed.")
return False
if not provider.droid.wifiIsApEnabled():
@@ -2239,3 +2100,769 @@
else:
return False
return False
+
+
+def wait_for_cell_data_connection(
+ log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
+ """Wait for data connection status to be expected value for default
+ data subscription.
+
+ Wait for the data connection status to be DATA_STATE_CONNECTED
+ or DATA_STATE_DISCONNECTED.
+
+ Args:
+ log: Log object.
+ ad: Android Device Object.
+ state: Expected status: True or False.
+ If True, it will wait for status to be DATA_STATE_CONNECTED.
+ If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
+ timeout_value: wait for cell data timeout value.
+ This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ sub_id = get_default_data_sub_id(ad)
+ return wait_for_cell_data_connection_for_subscription(
+ log, ad, sub_id, state, timeout_value)
+
+
+def _is_data_connection_state_match(log, ad, expected_data_connection_state):
+ return (expected_data_connection_state ==
+ ad.droid.telephonyGetDataConnectionState())
+
+
+def _is_network_connected_state_match(log, ad,
+ expected_network_connected_state):
+ return (expected_network_connected_state ==
+ ad.droid.connectivityNetworkIsConnected())
+
+
+def wait_for_cell_data_connection_for_subscription(
+ log,
+ ad,
+ sub_id,
+ state,
+ timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
+ """Wait for data connection status to be expected value for specified
+ subscrption id.
+
+ Wait for the data connection status to be DATA_STATE_CONNECTED
+ or DATA_STATE_DISCONNECTED.
+
+ Args:
+ log: Log object.
+ ad: Android Device Object.
+ sub_id: subscription Id
+ state: Expected status: True or False.
+ If True, it will wait for status to be DATA_STATE_CONNECTED.
+ If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
+ timeout_value: wait for cell data timeout value.
+ This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ state_str = {
+ True: DATA_STATE_CONNECTED,
+ False: DATA_STATE_DISCONNECTED
+ }[state]
+
+ data_state = ad.droid.telephonyGetDataConnectionState()
+ if not state and ad.droid.telephonyGetDataConnectionState() == state_str:
+ return True
+
+ ad.ed.clear_events(EventDataConnectionStateChanged)
+ ad.droid.telephonyStartTrackingDataConnectionStateChangeForSubscription(
+ sub_id)
+ ad.droid.connectivityStartTrackingConnectivityStateChange()
+ try:
+ ad.log.info("User data enabled for sub_id %s: %s", sub_id,
+ ad.droid.telephonyIsDataEnabledForSubscription(sub_id))
+ data_state = ad.droid.telephonyGetDataConnectionState()
+ ad.log.info("Data connection state is %s", data_state)
+ ad.log.info("Network is connected: %s",
+ ad.droid.connectivityNetworkIsConnected())
+ if data_state == state_str:
+ return _wait_for_nw_data_connection(
+ log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
+
+ try:
+ ad.ed.wait_for_event(
+ EventDataConnectionStateChanged,
+ is_event_match,
+ timeout=timeout_value,
+ field=DataConnectionStateContainer.DATA_CONNECTION_STATE,
+ value=state_str)
+ except Empty:
+ ad.log.info("No expected event EventDataConnectionStateChanged %s",
+ state_str)
+
+ # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
+ # data connection state.
+ # Otherwise, the network state will not be correct.
+ # The bug is tracked here: b/20921915
+
+ # Previously we use _is_data_connection_state_match,
+ # but telephonyGetDataConnectionState sometimes return wrong value.
+ # The bug is tracked here: b/22612607
+ # So we use _is_network_connected_state_match.
+
+ if _wait_for_droid_in_state(log, ad, timeout_value,
+ _is_network_connected_state_match, state):
+ return _wait_for_nw_data_connection(
+ log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
+ else:
+ return False
+
+ finally:
+ ad.droid.telephonyStopTrackingDataConnectionStateChangeForSubscription(
+ sub_id)
+
+
+def wait_for_data_connection(
+ log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
+ """Wait for data connection status to be expected value.
+
+ Wait for the data connection status to be DATA_STATE_CONNECTED
+ or DATA_STATE_DISCONNECTED.
+
+ Args:
+ log: Log object.
+ ad: Android Device Object.
+ state: Expected status: True or False.
+ If True, it will wait for status to be DATA_STATE_CONNECTED.
+ If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
+ timeout_value: wait for network data timeout value.
+ This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ return _wait_for_nw_data_connection(log, ad, state, None, timeout_value)
+
+
+def wait_for_wifi_data_connection(
+ log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
+ """Wait for data connection status to be expected value and connection is by WiFi.
+
+ Args:
+ log: Log object.
+ ad: Android Device Object.
+ state: Expected status: True or False.
+ If True, it will wait for status to be DATA_STATE_CONNECTED.
+ If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
+ timeout_value: wait for network data timeout value.
+ This is optional, default value is MAX_WAIT_TIME_NW_SELECTION
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ad.log.info("wait_for_wifi_data_connection")
+ return _wait_for_nw_data_connection(
+ log, ad, state, NETWORK_CONNECTION_TYPE_WIFI, timeout_value)
+
+
+def _connection_state_change(_event, target_state, connection_type):
+ if connection_type:
+ if 'TypeName' not in _event['data']:
+ return False
+ connection_type_string_in_event = _event['data']['TypeName']
+ cur_type = connection_type_from_type_string(
+ connection_type_string_in_event)
+ if cur_type != connection_type:
+ logging.info(
+ "_connection_state_change expect: %s, received: %s <type %s>",
+ connection_type, connection_type_string_in_event, cur_type)
+ return False
+
+ if 'isConnected' in _event['data'] and _event['data']['isConnected'] == target_state:
+ return True
+ return False
+
+
+def _wait_for_nw_data_connection(
+ log,
+ ad,
+ is_connected,
+ connection_type=None,
+ timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
+ """Wait for data connection status to be expected value.
+
+ Wait for the data connection status to be DATA_STATE_CONNECTED
+ or DATA_STATE_DISCONNECTED.
+
+ Args:
+ log: Log object.
+ ad: Android Device Object.
+ is_connected: Expected connection status: True or False.
+ If True, it will wait for status to be DATA_STATE_CONNECTED.
+ If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
+ connection_type: expected connection type.
+ This is optional, if it is None, then any connection type will return True.
+ timeout_value: wait for network data timeout value.
+ This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
+
+ Returns:
+ True if success.
+ False if failed.
+ """
+ ad.ed.clear_events(EventConnectivityChanged)
+ ad.droid.connectivityStartTrackingConnectivityStateChange()
+ try:
+ cur_data_connection_state = ad.droid.connectivityNetworkIsConnected()
+ if is_connected == cur_data_connection_state:
+ current_type = get_internet_connection_type(log, ad)
+ ad.log.info("current data connection type: %s", current_type)
+ if not connection_type:
+ return True
+ else:
+ if not is_connected and current_type != connection_type:
+ ad.log.info("data connection not on %s!", connection_type)
+ return True
+ elif is_connected and current_type == connection_type:
+ ad.log.info("data connection on %s as expected",
+ connection_type)
+ return True
+ else:
+ ad.log.info("current data connection state: %s target: %s",
+ cur_data_connection_state, is_connected)
+
+ try:
+ event = ad.ed.wait_for_event(
+ EventConnectivityChanged, _connection_state_change,
+ timeout_value, is_connected, connection_type)
+ ad.log.info("Got event: %s", event)
+ except Empty:
+ pass
+
+ log.info(
+ "_wait_for_nw_data_connection: check connection after wait event.")
+ # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
+ # data connection state.
+ # Otherwise, the network state will not be correct.
+ # The bug is tracked here: b/20921915
+ if _wait_for_droid_in_state(log, ad, timeout_value,
+ _is_network_connected_state_match,
+ is_connected):
+ current_type = get_internet_connection_type(log, ad)
+ ad.log.info("current data connection type: %s", current_type)
+ if not connection_type:
+ return True
+ else:
+ if not is_connected and current_type != connection_type:
+ ad.log.info("data connection not on %s", connection_type)
+ return True
+ elif is_connected and current_type == connection_type:
+ ad.log.info("after event wait, data connection on %s",
+ connection_type)
+ return True
+ else:
+ return False
+ else:
+ return False
+ except Exception as e:
+ ad.log.error("Exception error %s", str(e))
+ return False
+ finally:
+ ad.droid.connectivityStopTrackingConnectivityStateChange()
+
+
+def check_curl_availability(ad):
+ if not hasattr(ad, "curl_capable"):
+ try:
+ out = ad.adb.shell("/data/curl --version")
+ if not out or "not found" in out:
+ setattr(ad, "curl_capable", False)
+ ad.log.info("curl is unavailable, use chrome to download file")
+ else:
+ setattr(ad, "curl_capable", True)
+ except Exception:
+ setattr(ad, "curl_capable", False)
+ ad.log.info("curl is unavailable, use chrome to download file")
+ return ad.curl_capable
+
+
+def start_youtube_video(ad, url="vnd.youtube:watch?v=pSJoP0LR8CQ"):
+ ad.log.info("Open an youtube video")
+ for _ in range(3):
+ ad.ensure_screen_on()
+ ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
+ if wait_for_state(ad.droid.audioIsMusicActive, True, 15, 1):
+ ad.log.info("Started a video in youtube, audio is in MUSIC state")
+ return True
+ ad.log.info("Audio is not in MUSIC state. Quit Youtube.")
+ for _ in range(3):
+ ad.send_keycode("BACK")
+ time.sleep(1)
+ time.sleep(3)
+ return False
+
+
+def http_file_download_by_sl4a(ad,
+ url,
+ out_path=None,
+ expected_file_size=None,
+ remove_file_after_check=True,
+ timeout=300):
+ """Download http file by sl4a RPC call.
+
+ Args:
+ ad: Android Device Object.
+ url: The url that file to be downloaded from".
+ out_path: Optional. Where to download file to.
+ out_path is /sdcard/Download/ by default.
+ expected_file_size: Optional. Provided if checking the download file meet
+ expected file size in unit of byte.
+ remove_file_after_check: Whether to remove the downloaded file after
+ check.
+ timeout: timeout for file download to complete.
+ """
+ file_folder, file_name = _generate_file_directory_and_file_name(
+ url, out_path)
+ file_path = os.path.join(file_folder, file_name)
+ ad.adb.shell("rm -f %s" % file_path)
+ accounting_apk = SL4A_APK_NAME
+ result = True
+ try:
+ if not getattr(ad, "data_droid", None):
+ ad.data_droid, ad.data_ed = ad.get_droid()
+ ad.data_ed.start()
+ else:
+ try:
+ if not ad.data_droid.is_live:
+ ad.data_droid, ad.data_ed = ad.get_droid()
+ ad.data_ed.start()
+ except Exception:
+ ad.log.info("Start new sl4a session for file download")
+ ad.data_droid, ad.data_ed = ad.get_droid()
+ ad.data_ed.start()
+ data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None),
+ "sl4a_mobile_data_usage":
+ get_mobile_data_usage(ad, None, accounting_apk)
+ }
+ ad.log.debug("Before downloading: %s", data_accounting)
+ ad.log.info("Download file from %s to %s by sl4a RPC call", url,
+ file_path)
+ try:
+ ad.data_droid.httpDownloadFile(url, file_path, timeout=timeout)
+ except Exception as e:
+ ad.log.warning("SL4A file download error: %s", e)
+ ad.data_droid.terminate()
+ return False
+ if _check_file_existence(ad, file_path, expected_file_size):
+ ad.log.info("%s is downloaded successfully", url)
+ new_data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None),
+ "sl4a_mobile_data_usage":
+ get_mobile_data_usage(ad, None, accounting_apk)
+ }
+ ad.log.debug("After downloading: %s", new_data_accounting)
+ accounting_diff = {
+ key: value - data_accounting[key]
+ for key, value in new_data_accounting.items()
+ }
+ ad.log.debug("Data accounting difference: %s", accounting_diff)
+ if getattr(ad, "on_mobile_data", False):
+ for key, value in accounting_diff.items():
+ if value < expected_file_size:
+ ad.log.debug("%s diff is %s less than %s", key,
+ value, expected_file_size)
+ ad.data_accounting["%s_failure"] += 1
+ else:
+ for key, value in accounting_diff.items():
+ if value >= expected_file_size:
+ ad.log.error("%s diff is %s. File download is "
+ "consuming mobile data", key, value)
+ result = False
+ return result
+ else:
+ ad.log.warning("Fail to download %s", url)
+ return False
+ except Exception as e:
+ ad.log.error("Download %s failed with exception %s", url, e)
+ raise
+ finally:
+ if remove_file_after_check:
+ ad.log.info("Remove the downloaded file %s", file_path)
+ ad.adb.shell("rm %s" % file_path, ignore_status=True)
+
+
+def http_file_download_by_curl(ad,
+ url,
+ out_path=None,
+ expected_file_size=None,
+ remove_file_after_check=True,
+ timeout=3600,
+ limit_rate=None,
+ retry=3):
+ """Download http file by adb curl.
+
+ Args:
+ ad: Android Device Object.
+ url: The url that file to be downloaded from".
+ out_path: Optional. Where to download file to.
+ out_path is /sdcard/Download/ by default.
+ expected_file_size: Optional. Provided if checking the download file meet
+ expected file size in unit of byte.
+ remove_file_after_check: Whether to remove the downloaded file after
+ check.
+ timeout: timeout for file download to complete.
+ limit_rate: download rate in bps. None, if do not apply rate limit.
+ retry: the retry request times provided in curl command.
+ """
+ file_directory, file_name = _generate_file_directory_and_file_name(
+ url, out_path)
+ file_path = os.path.join(file_directory, file_name)
+ curl_cmd = "/data/curl"
+ if limit_rate:
+ curl_cmd += " --limit-rate %s" % limit_rate
+ if retry:
+ curl_cmd += " --retry %s" % retry
+ curl_cmd += " --url %s > %s" % (url, file_path)
+ try:
+ ad.log.info("Download %s to %s by adb shell command %s", url,
+ file_path, curl_cmd)
+
+ ad.adb.shell(curl_cmd, timeout=timeout)
+ if _check_file_existence(ad, file_path, expected_file_size):
+ ad.log.info("%s is downloaded to %s successfully", url, file_path)
+ return True
+ else:
+ ad.log.warning("Fail to download %s", url)
+ return False
+ except Exception as e:
+ ad.log.warning("Download %s failed with exception %s", url, e)
+ return False
+ finally:
+ if remove_file_after_check:
+ ad.log.info("Remove the downloaded file %s", file_path)
+ ad.adb.shell("rm %s" % file_path, ignore_status=True)
+
+
+def open_url_by_adb(ad, url):
+ ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
+
+
+def http_file_download_by_chrome(ad,
+ url,
+ expected_file_size=None,
+ remove_file_after_check=True,
+ timeout=3600):
+ """Download http file by chrome.
+
+ Args:
+ ad: Android Device Object.
+ url: The url that file to be downloaded from".
+ expected_file_size: Optional. Provided if checking the download file meet
+ expected file size in unit of byte.
+ remove_file_after_check: Whether to remove the downloaded file after
+ check.
+ timeout: timeout for file download to complete.
+ """
+ chrome_apk = "com.android.chrome"
+ file_directory, file_name = _generate_file_directory_and_file_name(
+ url, "/sdcard/Download/")
+ file_path = os.path.join(file_directory, file_name)
+ # Remove pre-existing file
+ ad.force_stop_apk(chrome_apk)
+ file_to_be_delete = os.path.join(file_directory, "*%s*" % file_name)
+ ad.adb.shell("rm -f %s" % file_to_be_delete)
+ ad.adb.shell("rm -rf /sdcard/Download/.*")
+ ad.adb.shell("rm -f /sdcard/Download/.*")
+ data_accounting = {
+ "total_rx_bytes": ad.droid.getTotalRxBytes(),
+ "mobile_rx_bytes": ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage": get_mobile_data_usage(ad, None, None),
+ "chrome_mobile_data_usage": get_mobile_data_usage(
+ ad, None, chrome_apk)
+ }
+ ad.log.debug("Before downloading: %s", data_accounting)
+ ad.log.info("Download %s with timeout %s", url, timeout)
+ ad.ensure_screen_on()
+ open_url_by_adb(ad, url)
+ elapse_time = 0
+ result = True
+ while elapse_time < timeout:
+ time.sleep(30)
+ if _check_file_existence(ad, file_path, expected_file_size):
+ ad.log.info("%s is downloaded successfully", url)
+ if remove_file_after_check:
+ ad.log.info("Remove the downloaded file %s", file_path)
+ ad.adb.shell("rm -f %s" % file_to_be_delete)
+ ad.adb.shell("rm -rf /sdcard/Download/.*")
+ ad.adb.shell("rm -f /sdcard/Download/.*")
+ #time.sleep(30)
+ new_data_accounting = {
+ "mobile_rx_bytes":
+ ad.droid.getMobileRxBytes(),
+ "subscriber_mobile_data_usage":
+ get_mobile_data_usage(ad, None, None),
+ "chrome_mobile_data_usage":
+ get_mobile_data_usage(ad, None, chrome_apk)
+ }
+ ad.log.info("After downloading: %s", new_data_accounting)
+ accounting_diff = {
+ key: value - data_accounting[key]
+ for key, value in new_data_accounting.items()
+ }
+ ad.log.debug("Data accounting difference: %s", accounting_diff)
+ if getattr(ad, "on_mobile_data", False):
+ for key, value in accounting_diff.items():
+ if value < expected_file_size:
+ ad.log.warning("%s diff is %s less than %s", key,
+ value, expected_file_size)
+ ad.data_accounting["%s_failure" % key] += 1
+ else:
+ for key, value in accounting_diff.items():
+ if value >= expected_file_size:
+ ad.log.error("%s diff is %s. File download is "
+ "consuming mobile data", key, value)
+ result = False
+ return result
+ elif _check_file_existence(ad, "%s.crdownload" % file_path):
+ ad.log.info("Chrome is downloading %s", url)
+ elif elapse_time < 60:
+ # download not started, retry download wit chrome again
+ open_url_by_adb(ad, url)
+ else:
+ ad.log.error("Unable to download file from %s", url)
+ break
+ elapse_time += 30
+ ad.log.warning("Fail to download file from %s", url)
+ ad.force_stop_apk("com.android.chrome")
+ ad.adb.shell("rm -f %s" % file_to_be_delete)
+ ad.adb.shell("rm -rf /sdcard/Download/.*")
+ ad.adb.shell("rm -f /sdcard/Download/.*")
+ return False
+
+
+def get_mobile_data_usage(ad, sid=None, apk=None):
+ if not sid:
+ sid = ad.droid.subscriptionGetDefaultDataSubId()
+ current_time = int(time.time() * 1000)
+ begin_time = current_time - 10 * 24 * 60 * 60 * 1000
+ end_time = current_time + 10 * 24 * 60 * 60 * 1000
+
+ if apk:
+ uid = ad.get_apk_uid(apk)
+ ad.log.debug("apk %s uid = %s", apk, uid)
+ try:
+ usage_info = ad.droid.getMobileDataUsageInfoForUid(uid, sid)
+ ad.log.debug("Mobile data usage info for uid %s = %s", uid,
+ usage_info)
+ return usage_info["UsageLevel"]
+ except:
+ try:
+ return ad.droid.connectivityQueryDetailsForUid(
+ TYPE_MOBILE,
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time, uid)
+ except:
+ return ad.droid.connectivityQueryDetailsForUid(
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time, uid)
+ else:
+ try:
+ usage_info = ad.droid.getMobileDataUsageInfo(sid)
+ ad.log.debug("Mobile data usage info = %s", usage_info)
+ return usage_info["UsageLevel"]
+ except:
+ try:
+ return ad.droid.connectivityQuerySummaryForDevice(
+ TYPE_MOBILE,
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time)
+ except:
+ return ad.droid.connectivityQuerySummaryForDevice(
+ ad.droid.telephonyGetSubscriberIdForSubscription(sid),
+ begin_time, end_time)
+
+
+def set_mobile_data_usage_limit(ad, limit, subscriber_id=None):
+ if not subscriber_id:
+ subscriber_id = ad.droid.telephonyGetSubscriberId()
+ ad.log.debug("Set subscriber mobile data usage limit to %s", limit)
+ ad.droid.logV("Setting subscriber mobile data usage limit to %s" % limit)
+ try:
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, str(limit))
+ except:
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, limit)
+
+
+def remove_mobile_data_usage_limit(ad, subscriber_id=None):
+ if not subscriber_id:
+ subscriber_id = ad.droid.telephonyGetSubscriberId()
+ ad.log.debug("Remove subscriber mobile data usage limit")
+ ad.droid.logV(
+ "Setting subscriber mobile data usage limit to -1, unlimited")
+ try:
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, "-1")
+ except:
+ ad.droid.connectivitySetDataUsageLimit(subscriber_id, -1)
+
+
+def active_file_download_task(log, ad, file_name="5MB", method="curl"):
+ # files available for download on the same website:
+ # 1GB.zip, 512MB.zip, 200MB.zip, 50MB.zip, 20MB.zip, 10MB.zip, 5MB.zip
+ # download file by adb command, as phone call will use sl4a
+ file_size_map = {
+ '1MB': 1000000,
+ '5MB': 5000000,
+ '10MB': 10000000,
+ '20MB': 20000000,
+ '50MB': 50000000,
+ '100MB': 100000000,
+ '200MB': 200000000,
+ '512MB': 512000000
+ }
+ url_map = {
+ "1MB": [
+ "http://146.148.91.8/download/1MB.zip",
+ "http://ipv4.download.thinkbroadband.com/1MB.zip"
+ ],
+ "5MB": [
+ "http://146.148.91.8/download/5MB.zip",
+ "http://212.183.159.230/5MB.zip",
+ "http://ipv4.download.thinkbroadband.com/5MB.zip"
+ ],
+ "10MB": [
+ "http://146.148.91.8/download/10MB.zip",
+ "http://212.183.159.230/10MB.zip",
+ "http://ipv4.download.thinkbroadband.com/10MB.zip",
+ "http://lax.futurehosting.com/test.zip",
+ "http://ovh.net/files/10Mio.dat"
+ ],
+ "20MB": [
+ "http://146.148.91.8/download/20MB.zip",
+ "http://212.183.159.230/20MB.zip",
+ "http://ipv4.download.thinkbroadband.com/20MB.zip"
+ ],
+ "50MB": [
+ "http://146.148.91.8/download/50MB.zip",
+ "http://212.183.159.230/50MB.zip",
+ "http://ipv4.download.thinkbroadband.com/50MB.zip"
+ ],
+ "100MB": [
+ "http://146.148.91.8/download/100MB.zip",
+ "http://212.183.159.230/100MB.zip",
+ "http://ipv4.download.thinkbroadband.com/100MB.zip",
+ "http://speedtest-ca.turnkeyinternet.net/100mb.bin",
+ "http://ovh.net/files/100Mio.dat",
+ "http://lax.futurehosting.com/test100.zip"
+ ],
+ "200MB": [
+ "http://146.148.91.8/download/200MB.zip",
+ "http://212.183.159.230/200MB.zip",
+ "http://ipv4.download.thinkbroadband.com/200MB.zip"
+ ],
+ "512MB": [
+ "http://146.148.91.8/download/512MB.zip",
+ "http://212.183.159.230/512MB.zip",
+ "http://ipv4.download.thinkbroadband.com/512MB.zip"
+ ]
+ }
+
+ file_size = file_size_map.get(file_name)
+ file_urls = url_map.get(file_name)
+ file_url = None
+ for url in file_urls:
+ url_splits = url.split("/")
+ if verify_http_connection(log, ad, url=url, retry=1):
+ output_path = "/sdcard/Download/%s" % url_splits[-1]
+ file_url = url
+ break
+ if not file_url:
+ ad.log.error("No url is available to download %s", file_name)
+ return False
+ timeout = min(max(file_size / 100000, 600), 3600)
+ if method == "sl4a":
+ return (http_file_download_by_sl4a, (ad, file_url, output_path,
+ file_size, True, timeout))
+ if method == "curl" and check_curl_availability(ad):
+ return (http_file_download_by_curl, (ad, file_url, output_path,
+ file_size, True, timeout))
+ elif method == "sl4a" or method == "curl":
+ return (http_file_download_by_sl4a, (ad, file_url, output_path,
+ file_size, True, timeout))
+ else:
+ return (http_file_download_by_chrome, (ad, file_url, file_size, True,
+ timeout))
+
+
+def active_file_download_test(log, ad, file_name="5MB", method="sl4a"):
+ task = active_file_download_task(log, ad, file_name, method=method)
+ if not task:
+ return False
+ return task[0](*task[1])
+
+
+def check_data_stall_detection(ad, wait_time=WAIT_TIME_FOR_DATA_STALL):
+ data_stall_detected = False
+ time_var = 1
+ try:
+ while (time_var < wait_time):
+ out = ad.adb.shell("dumpsys network_stack " \
+ "| grep \"Suspecting data stall\"",
+ ignore_status=True)
+ ad.log.debug("Output is %s", out)
+ if out:
+ ad.log.info("NetworkMonitor detected - %s", out)
+ data_stall_detected = True
+ break
+ time.sleep(30)
+ time_var += 30
+ except Exception as e:
+ ad.log.error(e)
+ return data_stall_detected
+
+
+def check_network_validation_fail(ad, begin_time=None,
+ wait_time=WAIT_TIME_FOR_NW_VALID_FAIL):
+ network_validation_fail = False
+ time_var = 1
+ try:
+ while (time_var < wait_time):
+ time_var += 30
+ nw_valid = ad.search_logcat("validation failed",
+ begin_time)
+ if nw_valid:
+ ad.log.info("Validation Failed received here - %s",
+ nw_valid[0]["log_message"])
+ network_validation_fail = True
+ break
+ time.sleep(30)
+ except Exception as e:
+ ad.log.error(e)
+ return network_validation_fail
+
+
+def check_data_stall_recovery(ad, begin_time=None,
+ wait_time=WAIT_TIME_FOR_DATA_STALL_RECOVERY):
+ data_stall_recovery = False
+ time_var = 1
+ try:
+ while (time_var < wait_time):
+ time_var += 30
+ recovery = ad.search_logcat("doRecovery() cleanup all connections",
+ begin_time)
+ if recovery:
+ ad.log.info("Recovery Performed here - %s",
+ recovery[-1]["log_message"])
+ data_stall_recovery = True
+ break
+ time.sleep(30)
+ except Exception as e:
+ ad.log.error(e)
+ return data_stall_recovery
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_defines.py b/acts_tests/acts_contrib/test_utils/tel/tel_defines.py
index 94d03f1..f3fc75c 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_defines.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_defines.py
@@ -354,7 +354,6 @@
CARRIER_KDDI = 'kddi'
CARRIER_RAKUTEN = 'rakuten'
CARRIER_SBM = 'sbm'
-CARRIER_VZW = "Verizon"
CARRIER_SKT = 'skt'
CARRIER_KT = 'kt'
CARRIER_LG_UPLUS = 'lg_uplus'
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py
index 4459221..6b15886 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_dsds_utils.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2021 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,19 +14,25 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+from datetime import datetime, timedelta
import re
import time
-from datetime import datetime, timedelta
+from typing import Optional, Sequence
from acts import signals
+from acts import tracelogger
+from acts.controllers.android_device import AndroidDevice
from acts.utils import rand_ascii_str
from acts.libs.utils.multithread import multithread_func
from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
+from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import YOUTUBE_PACKAGE_NAME
+from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
+from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
from acts_contrib.test_utils.tel.tel_message_utils import log_messaging_screen_shot
from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify_for_subscription
@@ -35,46 +41,276 @@
from acts_contrib.test_utils.tel.tel_ss_utils import set_call_waiting
from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc_for_subscription
from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_on_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_idle
+from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_forwarding_short_seq
+from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_waiting_short_seq
from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot
from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import active_file_download_test
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import get_slot_index_from_subid
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
from acts_contrib.test_utils.tel.tel_test_utils import power_off_sim
from acts_contrib.test_utils.tel.tel_test_utils import power_on_sim
-from acts_contrib.test_utils.tel.tel_test_utils import start_youtube_video
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_reject_call_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_general
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_on_rat
-from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
-from acts_contrib.test_utils.tel.tel_voice_utils import three_phone_call_forwarding_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import three_phone_call_waiting_short_seq
-from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_msim_for_slot
-from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_network_idle
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_second_call_from_participant
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_wcdma_conference_merge_drop
from acts_contrib.test_utils.tel.tel_voice_conf_utils import _three_phone_call_mo_add_mt
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
+from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
+from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_msim_for_slot
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_reject_call_for_subscription
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
CallResult = TelephonyVoiceTestResult.CallResult.Value
+
+def dsds_long_call_streaming_test(
+ log: tracelogger.TraceLogger,
+ tel_logger: TelephonyMetricLogger.for_test_case,
+ ads: Sequence[AndroidDevice],
+ test_rat: list,
+ test_slot: int,
+ dds_slot: int,
+ direction: str = "mo",
+ duration: int = 360,
+ streaming: bool = True,
+ is_airplane_mode = False,
+ wfc_mode: list[str, str] = [
+ WFC_MODE_CELLULAR_PREFERRED,
+ WFC_MODE_CELLULAR_PREFERRED],
+ wifi_network_ssid: Optional[str] = None,
+ wifi_network_pass: Optional[str] = None,
+ turn_off_wifi_in_the_end: bool = False,
+ turn_off_airplane_mode_in_the_end: bool = False) -> bool:
+ """Make MO/MT call at specific slot in specific RAT with DDS at specific
+ slot for the given time.
+
+ Args:
+ log: Logger object.
+ tel_logger: Logger object for telephony proto.
+ ads: A list of Android device objects.
+ test_rat: RAT for both slots of primary device.
+ test_slot: The slot which make/receive MO/MT call of primary device.
+ dds_slot: Preferred data slot of primary device.
+ direction: The direction of call("mo" or "mt").
+ streaming: True for playing Youtube and False on the contrary.
+ is_airplane_mode: True or False for WFC setup
+ wfc_mode: Cellular preferred or Wi-Fi preferred.
+ wifi_network_ssid: SSID of Wi-Fi AP.
+ wifi_network_pass: Password of Wi-Fi AP SSID.
+ turn_off_wifi_in_the_end: True to turn off Wi-Fi and False not to turn
+ off Wi-Fi in the end of the function.
+ turn_off_airplane_mode_in_the_end: True to turn off airplane mode and
+ False not to turn off airplane mode in the end of the function.
+
+ Returns:
+ TestFailure if failed.
+ """
+ log.info("Step 1: Switch DDS.")
+ if not set_dds_on_slot(ads[0], dds_slot):
+ ads[0].log.error(
+ "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
+ return False
+
+ log.info("Step 2: Check HTTP connection after DDS switch.")
+ if not verify_http_connection(log, ads[0]):
+ ads[0].log.error("Failed to verify http connection.")
+ return False
+ else:
+ ads[0].log.info("Verify http connection successfully.")
+
+ log.info("Step 3: Set up phones in desired RAT.")
+ if direction == "mo":
+ # setup voice subid on primary device.
+ ad_mo = ads[0]
+ mo_sub_id = get_subid_from_slot_index(log, ad_mo, test_slot)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at slot %s.", test_slot)
+ return False
+ mo_other_sub_id = get_subid_from_slot_index(
+ log, ad_mo, 1-test_slot)
+ sub_id_list = [mo_sub_id, mo_other_sub_id]
+ set_voice_sub_id(ad_mo, mo_sub_id)
+ ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", test_slot,
+ get_outgoing_voice_sub_id(ad_mo))
+
+ # setup voice subid on secondary device.
+ ad_mt = ads[1]
+ _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at default voice slot.")
+ return False
+ mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
+ set_voice_sub_id(ad_mt, mt_sub_id)
+ ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
+ get_outgoing_voice_sub_id(ad_mt))
+
+ # setup the rat on non-test slot(primary device).
+ phone_setup_on_rat(
+ log,
+ ad_mo,
+ test_rat[1-test_slot],
+ mo_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[1-test_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+ # assign phone setup argv for test slot.
+ mo_phone_setup_func_argv = (
+ log,
+ ad_mo,
+ test_rat[test_slot],
+ mo_sub_id,
+ is_airplane_mode,
+ wfc_mode[test_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+ verify_caller_func = is_phone_in_call_on_rat(
+ log, ad_mo, test_rat[test_slot], only_return_fn=True)
+ mt_phone_setup_func_argv = (log, ad_mt, 'general')
+ verify_callee_func = is_phone_in_call_on_rat(
+ log, ad_mt, 'general', only_return_fn=True)
+ else:
+ # setup voice subid on primary device.
+ ad_mt = ads[0]
+ mt_sub_id = get_subid_from_slot_index(log, ad_mt, test_slot)
+ if mt_sub_id == INVALID_SUB_ID:
+ ad_mt.log.warning("Failed to get sub ID at slot %s.", test_slot)
+ return False
+ mt_other_sub_id = get_subid_from_slot_index(
+ log, ad_mt, 1-test_slot)
+ sub_id_list = [mt_sub_id, mt_other_sub_id]
+ set_voice_sub_id(ad_mt, mt_sub_id)
+ ad_mt.log.info("Sub ID for incoming call at slot %s: %s", test_slot,
+ get_outgoing_voice_sub_id(ad_mt))
+
+ # setup voice subid on secondary device.
+ ad_mo = ads[1]
+ _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
+ if mo_sub_id == INVALID_SUB_ID:
+ ad_mo.log.warning("Failed to get sub ID at default voice slot.")
+ return False
+ mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
+ set_voice_sub_id(ad_mo, mo_sub_id)
+ ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", mo_slot,
+ get_outgoing_voice_sub_id(ad_mo))
+
+ # setup the rat on non-test slot(primary device).
+ phone_setup_on_rat(
+ log,
+ ad_mt,
+ test_rat[1-test_slot],
+ mt_other_sub_id,
+ is_airplane_mode,
+ wfc_mode[1-test_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+ # assign phone setup argv for test slot.
+ mt_phone_setup_func_argv = (
+ log,
+ ad_mt,
+ test_rat[test_slot],
+ mt_sub_id,
+ is_airplane_mode,
+ wfc_mode[test_slot],
+ wifi_network_ssid,
+ wifi_network_pass)
+ verify_callee_func = is_phone_in_call_on_rat(
+ log, ad_mt, test_rat[test_slot], only_return_fn=True)
+ mo_phone_setup_func_argv = (log, ad_mo, 'general')
+ verify_caller_func = is_phone_in_call_on_rat(
+ log, ad_mo, 'general', only_return_fn=True)
+
+ tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
+ (phone_setup_on_rat, mt_phone_setup_func_argv)]
+ if not multithread_func(log, tasks):
+ log.error("Phone Failed to Set Up Properly.")
+ tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Phone Failed to Set Up Properly."})
+ if streaming:
+ log.info("Step 4-0: Start Youtube streaming.")
+ if not start_youtube_video(ads[0]):
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": "Fail to bring up youtube video."})
+ time.sleep(10)
+
+ log.info("Step 4: Make voice call.")
+ result = call_setup_teardown(log,
+ ad_mo,
+ ad_mt,
+ ad_hangup=ad_mo,
+ verify_caller_func=verify_caller_func,
+ verify_callee_func=verify_callee_func,
+ wait_time_in_call=duration)
+ tel_logger.set_result(result.result_value)
+
+ if not result:
+ log.error(
+ "Failed to make %s call from %s slot %s to %s slot %s",
+ direction, ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
+ raise signals.TestFailure("Failed",
+ extras={"fail_reason": str(result.result_value)})
+
+ log.info("Step 5: Verify RAT and HTTP connection.")
+ # For the tese cases related to WFC in which airplane mode will be turned
+ # off in the end.
+ if turn_off_airplane_mode_in_the_end:
+ log.info("Step 5-1: Turning off airplane mode......")
+ if not toggle_airplane_mode(log, ads[0], False):
+ ads[0].log.error('Failed to toggle off airplane mode.')
+
+ # For the tese cases related to WFC in which Wi-Fi will be turned off in the
+ # end.
+
+ rat_list = [test_rat[test_slot], test_rat[1-test_slot]]
+
+ if turn_off_wifi_in_the_end:
+ log.info("Step 5-2: Turning off Wi-Fi......")
+ if not wifi_toggle_state(log, ads[0], False):
+ ads[0].log.error('Failed to toggle off Wi-Fi.')
+ return False
+
+ for index, value in enumerate(rat_list):
+ if value == '5g_wfc':
+ rat_list[index] = '5g'
+ elif value == 'wfc':
+ rat_list[index] = '4g'
+
+ for rat, sub_id in zip(rat_list, sub_id_list):
+ if not wait_for_network_idle(log, ads[0], rat, sub_id):
+ raise signals.TestFailure(
+ "Failed",
+ extras={
+ "fail_reason": "Idle state of sub ID %s does not match the "
+ "given RAT %s." % (sub_id, rat)})
+
+ if not verify_http_connection(log, ads[0]):
+ ads[0].log.error("Failed to verify http connection.")
+ return False
+ else:
+ ads[0].log.info("Verify http connection successfully.")
+
+ if streaming:
+ ads[0].force_stop_apk(YOUTUBE_PACKAGE_NAME)
+
+
def dsds_voice_call_test(
log,
tel_logger,
@@ -257,11 +493,11 @@
result = two_phone_call_msim_for_slot(
log,
ad_mo,
- get_slot_index_from_subid(log, ad_mo, mo_sub_id),
+ get_slot_index_from_subid(ad_mo, mo_sub_id),
None,
is_mo_in_call,
ad_mt,
- get_slot_index_from_subid(log, ad_mt, mt_sub_id),
+ get_slot_index_from_subid(ad_mt, mt_sub_id),
None,
is_mt_in_call)
@@ -662,10 +898,8 @@
if call_or_sms_or_mms == "call":
log.info("Step 4: Make voice call.")
- mo_slot = get_slot_index_from_subid(
- log, ad_mo, mo_sub_id)
- mt_slot = get_slot_index_from_subid(
- log, ad_mt, mt_sub_id)
+ mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
+ mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
result = two_phone_call_msim_for_slot(
log,
ad_mo,
@@ -883,11 +1117,11 @@
result = two_phone_call_msim_for_slot(
log,
ad_mo,
- get_slot_index_from_subid(log, ad_mo, mo_sub_id),
+ get_slot_index_from_subid(ad_mo, mo_sub_id),
None,
is_mo_in_call,
ad_mt,
- get_slot_index_from_subid(log, ad_mt, mt_sub_id),
+ get_slot_index_from_subid(ad_mt, mt_sub_id),
None,
is_mt_in_call)
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py
index 499d7ee..1cb6bb5 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_logging_utils.py
@@ -20,6 +20,8 @@
import shutil
import time
+from acts import utils
+from acts.libs.proc import job
from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
from acts.controllers.android_device import DEFAULT_SDM_LOG_PATH
from acts.libs.utils.multithread import run_multithread_func
@@ -27,6 +29,21 @@
from acts.utils import start_standing_subprocess
+_LS_MASK_NAME = "Lassen default + TCP"
+
+_LS_ENABLE_LOG_SHELL = f"""\
+am broadcast -n com.android.pixellogger/.receiver.AlwaysOnLoggingReceiver \
+ -a com.android.pixellogger.service.logging.LoggingService.ACTION_CONFIGURE_ALWAYS_ON_LOGGING \
+ -e intent_key_enable "true" -e intent_key_config "{_LS_MASK_NAME}" \
+ --ei intent_key_max_log_size_mb 100 --ei intent_key_max_number_of_files 100
+"""
+_LS_DISABLE_LOG_SHELL = """\
+am broadcast -n com.android.pixellogger/.receiver.AlwaysOnLoggingReceiver \
+ -a com.android.pixellogger.service.logging.LoggingService.ACTION_CONFIGURE_ALWAYS_ON_LOGGING \
+ -e intent_key_enable "false"
+"""
+
+
def check_if_tensor_platform(ad):
"""Check if current platform belongs to the Tensor platform
@@ -72,32 +89,51 @@
def start_sdm_logger(ad):
"""Start SDM logger."""
if not getattr(ad, "sdm_log", True): return
+
# Delete existing SDM logs which were created 15 mins prior
ad.sdm_log_path = DEFAULT_SDM_LOG_PATH
file_count = ad.adb.shell(
- "find %s -type f -iname sbuff_[0-9]*.sdm* | wc -l" % ad.sdm_log_path)
+ f"find {ad.sdm_log_path} -type f -iname sbuff_[0-9]*.sdm* | wc -l")
if int(file_count) > 3:
seconds = 15 * 60
# Remove sdm logs modified more than specified seconds ago
ad.adb.shell(
- "find %s -type f -iname sbuff_[0-9]*.sdm* -not -mtime -%ss -delete" %
- (ad.sdm_log_path, seconds))
- # Disable any modem logging already running
- if not getattr(ad, "enable_always_on_modem_logger", False):
- ad.adb.shell("setprop persist.vendor.sys.modem.logging.enable false")
+ f"find {ad.sdm_log_path} -type f -iname sbuff_[0-9]*.sdm* "
+ f"-not -mtime -{seconds}s -delete")
+
+ # Disable modem logging already running
+ stop_sdm_logger(ad)
+
# start logging
- cmd = "setprop vendor.sys.modem.logging.enable true"
ad.log.debug("start sdm logging")
- ad.adb.shell(cmd, ignore_status=True)
- time.sleep(5)
+ while int(
+ ad.adb.shell(f"find {ad.sdm_log_path} -type f "
+ "-iname sbuff_profile.sdm | wc -l") == 0 or
+ int(
+ ad.adb.shell(f"find {ad.sdm_log_path} -type f "
+ "-iname sbuff_[0-9]*.sdm* | wc -l")) == 0):
+ ad.adb.shell(_LS_ENABLE_LOG_SHELL, ignore_status=True)
+ time.sleep(5)
def stop_sdm_logger(ad):
"""Stop SDM logger."""
- cmd = "setprop vendor.sys.modem.logging.enable false"
+ ad.sdm_log_path = DEFAULT_SDM_LOG_PATH
+ cycle = 1
+
ad.log.debug("stop sdm logging")
- ad.adb.shell(cmd, ignore_status=True)
- time.sleep(5)
+ while int(
+ ad.adb.shell(
+ f"find {ad.sdm_log_path} -type f -iname sbuff_profile.sdm -o "
+ "-iname sbuff_[0-9]*.sdm* | wc -l")) != 0:
+ if cycle == 1 and int(
+ ad.adb.shell(f"find {ad.sdm_log_path} -type f "
+ "-iname sbuff_profile.sdm | wc -l")) == 0:
+ ad.adb.shell(_LS_ENABLE_LOG_SHELL, ignore_status=True)
+ time.sleep(5)
+ ad.adb.shell(_LS_DISABLE_LOG_SHELL, ignore_status=True)
+ cycle += 1
+ time.sleep(15)
def start_sdm_loggers(log, ads):
@@ -492,4 +528,51 @@
stop_time = datetime.now()
passed_time = (stop_time - start_time).total_seconds()
if passed_time > max_wait_time:
- return
\ No newline at end of file
+ return
+
+
+def extract_test_log(log, src_file, dst_file, test_tag):
+ os.makedirs(os.path.dirname(dst_file), exist_ok=True)
+ cmd = "grep -n '%s' %s" % (test_tag, src_file)
+ result = job.run(cmd, ignore_status=True)
+ if not result.stdout or result.exit_status == 1:
+ log.warning("Command %s returns %s", cmd, result)
+ return
+ line_nums = re.findall(r"(\d+).*", result.stdout)
+ if line_nums:
+ begin_line = int(line_nums[0])
+ end_line = int(line_nums[-1])
+ if end_line - begin_line <= 5:
+ result = job.run("wc -l < %s" % src_file)
+ if result.stdout:
+ end_line = int(result.stdout)
+ log.info("Extract %s from line %s to line %s to %s", src_file,
+ begin_line, end_line, dst_file)
+ job.run("awk 'NR >= %s && NR <= %s' %s > %s" % (begin_line, end_line,
+ src_file, dst_file))
+
+
+def log_screen_shot(ad, test_name=""):
+ file_name = "/sdcard/Pictures/screencap"
+ if test_name:
+ file_name = "%s_%s" % (file_name, test_name)
+ file_name = "%s_%s.png" % (file_name, utils.get_current_epoch_time())
+ try:
+ ad.adb.shell("screencap -p %s" % file_name)
+ except:
+ ad.log.error("Fail to log screen shot to %s", file_name)
+
+
+def get_screen_shot_log(ad, test_name="", begin_time=None):
+ logs = ad.get_file_names("/sdcard/Pictures", begin_time=begin_time)
+ if logs:
+ ad.log.info("Pulling %s", logs)
+ log_path = os.path.join(ad.device_log_path, "Screenshot_%s" % ad.serial)
+ os.makedirs(log_path, exist_ok=True)
+ ad.pull_files(logs, log_path)
+ ad.adb.shell("rm -rf /sdcard/Pictures/screencap_*", ignore_status=True)
+
+
+def get_screen_shot_logs(ads, test_name="", begin_time=None):
+ for ad in ads:
+ get_screen_shot_log(ad, test_name=test_name, begin_time=begin_time)
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_lookup_tables.py b/acts_tests/acts_contrib/test_utils/tel/tel_lookup_tables.py
index 8304cdd..df3336b 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_lookup_tables.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_lookup_tables.py
@@ -287,6 +287,28 @@
'45004': tel_defines.CARRIER_KT,
'45008': tel_defines.CARRIER_KT,
+ #Softbank (Japan)
+ '44004': tel_defines.CARRIER_SBM,
+ '44006': tel_defines.CARRIER_SBM,
+ '44020': tel_defines.CARRIER_SBM,
+ '44040': tel_defines.CARRIER_SBM,
+ '44041': tel_defines.CARRIER_SBM,
+ '44042': tel_defines.CARRIER_SBM,
+ '44043': tel_defines.CARRIER_SBM,
+ '44044': tel_defines.CARRIER_SBM,
+ '44045': tel_defines.CARRIER_SBM,
+ '44046': tel_defines.CARRIER_SBM,
+ '44047': tel_defines.CARRIER_SBM,
+ '44048': tel_defines.CARRIER_SBM,
+ '44090': tel_defines.CARRIER_SBM,
+ '44092': tel_defines.CARRIER_SBM,
+ '44093': tel_defines.CARRIER_SBM,
+ '44094': tel_defines.CARRIER_SBM,
+ '44095': tel_defines.CARRIER_SBM,
+ '44096': tel_defines.CARRIER_SBM,
+ '44097': tel_defines.CARRIER_SBM,
+ '44098': tel_defines.CARRIER_SBM,
+
#SK Telecom (South Korea)
'45005': tel_defines.CARRIER_SKT,
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_message_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_message_utils.py
index 9a8e3ad..21c418f 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_message_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_message_utils.py
@@ -40,30 +40,31 @@
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts_contrib.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
-from acts_contrib.test_utils.tel.tel_test_utils import CallResult
-from acts_contrib.test_utils.tel.tel_test_utils import TelResultWrapper
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import check_phone_number_match
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import last_call_drop_reason
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_in_call_active
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_call_end
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_call_offhook_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_on_rat
from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_message_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_message
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_on_rat
+from acts_contrib.test_utils.tel.tel_test_utils import CallResult
+from acts_contrib.test_utils.tel.tel_test_utils import TelResultWrapper
+from acts_contrib.test_utils.tel.tel_test_utils import check_phone_number_match
+from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason
from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_in_call_active
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_end
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_offhook_for_subscription
from acts_contrib.test_utils.tel.tel_video_utils import is_phone_in_call_video_bidirectional
from acts_contrib.test_utils.tel.tel_video_utils import video_call_setup_teardown
from acts_contrib.test_utils.tel.tel_video_utils import phone_idle_video
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+
def send_message_with_random_message_body(
log, ad_mo, ad_mt, msg_type='sms', long_msg=False, mms_expected_result=True):
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_mms_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_mms_utils.py
index cd3f74e..d9d85a7 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_mms_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_mms_utils.py
@@ -18,12 +18,13 @@
from acts.utils import rand_ascii_str
from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
from acts_contrib.test_utils.tel.tel_message_utils import mms_receive_verify_after_call_hangup
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
message_lengths = (50, 160, 180)
long_message_lengths = (800, 1600)
+
def _mms_test_mo(log, ads, expected_result=True):
return _mms_test(log,
[ads[0], ads[1]], expected_result=expected_result)
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py
index e4366cd..118f912 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_parse_utils.py
@@ -63,6 +63,7 @@
ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT0 = r'ImsPhone: \[0\].*onImsMmTelConnected imsRadioTech=WLAN'
ON_IMS_MM_TEL_CONNECTED_IWLAN_SLOT1 = r'ImsPhone: \[1\].*onImsMmTelConnected imsRadioTech=WLAN'
+
def print_nested_dict(ad, d):
divider = "------"
for k, v in d.items():
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py
new file mode 100644
index 0000000..6077d9c
--- /dev/null
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_phone_setup_utils.py
@@ -0,0 +1,1758 @@
+#!/usr/bin/env python3
+#
+# Copyright 2021 - Google
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import time
+from acts import signals
+from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
+from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_FRE
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_TMO
+from acts_contrib.test_utils.tel.tel_defines import GEN_2G
+from acts_contrib.test_utils.tel.tel_defines import GEN_3G
+from acts_contrib.test_utils.tel.tel_defines import GEN_4G
+from acts_contrib.test_utils.tel.tel_defines import GEN_5G
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_DROP
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
+from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
+from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
+from acts_contrib.test_utils.tel.tel_defines import RAT_5G
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_CDMA2000
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WCDMA
+from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
+from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
+from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
+from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
+from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
+from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_enhanced_4g_lte_setting
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_volte_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_disabled
+from acts_contrib.test_utils.tel.tel_lookup_tables import network_preference_for_generation
+from acts_contrib.test_utils.tel.tel_lookup_tables import rat_families_for_network_preference
+from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_for_generation
+from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_from_rat
+from acts_contrib.test_utils.tel.tel_lookup_tables import rat_generation_from_rat
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
+from acts_contrib.test_utils.tel.tel_test_utils import _is_attached
+from acts_contrib.test_utils.tel.tel_test_utils import _is_attached_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import get_cell_data_roaming_state_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
+from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
+from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_network_generation_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_rat_family_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import is_droid_in_rat_family_list_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import reset_preferred_network_type_to_allowable_range
+from acts_contrib.test_utils.tel.tel_test_utils import set_cell_data_roaming_state_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
+from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import set_wifi_to_default
+from acts.libs.utils.multithread import multithread_func
+
+
+def phone_setup_iwlan(log,
+ ad,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid=None,
+ wifi_pwd=None,
+ nw_gen=None):
+ """Phone setup function for epdg call test.
+ Set WFC mode according to wfc_mode.
+ Set airplane mode according to is_airplane_mode.
+ Make sure phone connect to WiFi. (If wifi_ssid is not None.)
+ Wait for phone to be in iwlan data network type.
+ Wait for phone to report wfc enabled flag to be true.
+ Args:
+ log: Log object.
+ ad: Android device object.
+ is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode.
+ wfc_mode: WFC mode to set to.
+ wifi_ssid: WiFi network SSID. This is optional.
+ If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
+ wifi_pwd: WiFi network password. This is optional.
+ nw_gen: network type selection. This is optional.
+ GEN_4G for 4G, GEN_5G for 5G or None for doing nothing.
+ Returns:
+ True if success. False if fail.
+ """
+ return phone_setup_iwlan_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad),
+ is_airplane_mode, wfc_mode,
+ wifi_ssid, wifi_pwd, nw_gen)
+
+
+def phone_setup_iwlan_for_subscription(log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid=None,
+ wifi_pwd=None,
+ nw_gen=None,
+ nr_type=None):
+ """Phone setup function for epdg call test for subscription id.
+ Set WFC mode according to wfc_mode.
+ Set airplane mode according to is_airplane_mode.
+ Make sure phone connect to WiFi. (If wifi_ssid is not None.)
+ Wait for phone to be in iwlan data network type.
+ Wait for phone to report wfc enabled flag to be true.
+ Args:
+ log: Log object.
+ ad: Android device object.
+ sub_id: subscription id.
+ is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode.
+ wfc_mode: WFC mode to set to.
+ wifi_ssid: WiFi network SSID. This is optional.
+ If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
+ wifi_pwd: WiFi network password. This is optional.
+ nw_gen: network type selection. This is optional.
+ GEN_4G for 4G, GEN_5G for 5G or None for doing nothing.
+ nr_type: NR network type
+ Returns:
+ True if success. False if fail.
+ """
+ if not get_capability_for_subscription(ad, CAPABILITY_WFC, sub_id):
+ ad.log.error("WFC is not supported, abort test.")
+ raise signals.TestSkip("WFC is not supported, abort test.")
+
+ if nw_gen:
+ if not ensure_network_generation_for_subscription(
+ log, ad, sub_id, nw_gen, voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+ ad.log.error("Failed to set to %s data.", nw_gen)
+ return False
+ toggle_airplane_mode(log, ad, is_airplane_mode, strict_checking=False)
+
+ # Pause at least for 4 seconds is necessary after airplane mode was turned
+ # on due to the mechanism of deferring Wi-Fi (b/191481736)
+ if is_airplane_mode:
+ time.sleep(5)
+
+ # check if WFC supported phones
+ if wfc_mode != WFC_MODE_DISABLED and not ad.droid.imsIsWfcEnabledByPlatform(
+ ):
+ ad.log.error("WFC is not enabled on this device by checking "
+ "ImsManager.isWfcEnabledByPlatform")
+ return False
+ if wifi_ssid is not None:
+ if not ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd, apm=is_airplane_mode):
+ ad.log.error("Fail to bring up WiFi connection on %s.", wifi_ssid)
+ return False
+ else:
+ ad.log.info("WiFi network SSID not specified, available user "
+ "parameters are: wifi_network_ssid, wifi_network_ssid_2g, "
+ "wifi_network_ssid_5g")
+ if not set_wfc_mode_for_subscription(ad, wfc_mode, sub_id):
+ ad.log.error("Unable to set WFC mode to %s.", wfc_mode)
+ return False
+
+ if wfc_mode != WFC_MODE_DISABLED:
+ if not wait_for_wfc_enabled(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
+ ad.log.error("WFC is not enabled")
+ return False
+
+ return True
+
+
+def phone_setup_iwlan_cellular_preferred(log,
+ ad,
+ wifi_ssid=None,
+ wifi_pwd=None):
+ """Phone setup function for iwlan Non-APM CELLULAR_PREFERRED test.
+ Set WFC mode according to CELLULAR_PREFERRED.
+ Set airplane mode according to False.
+ Make sure phone connect to WiFi. (If wifi_ssid is not None.)
+ Make sure phone don't report iwlan data network type.
+ Make sure phone don't report wfc enabled flag to be true.
+
+ Args:
+ log: Log object.
+ ad: Android device object.
+ wifi_ssid: WiFi network SSID. This is optional.
+ If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
+ wifi_pwd: WiFi network password. This is optional.
+
+ Returns:
+ True if success. False if fail.
+ """
+ toggle_airplane_mode(log, ad, False, strict_checking=False)
+ try:
+ toggle_volte(log, ad, True)
+ if not wait_for_network_generation(
+ log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
+ if not ensure_network_generation(
+ log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
+ ad.log.error("Fail to ensure data in 4G")
+ return False
+ except Exception as e:
+ ad.log.error(e)
+ ad.droid.telephonyToggleDataConnection(True)
+ if wifi_ssid is not None:
+ if not ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd):
+ ad.log.error("Connect to WiFi failed.")
+ return False
+ if not set_wfc_mode(log, ad, WFC_MODE_CELLULAR_PREFERRED):
+ ad.log.error("Set WFC mode failed.")
+ return False
+ if not wait_for_not_network_rat(
+ log, ad, RAT_FAMILY_WLAN, voice_or_data=NETWORK_SERVICE_DATA):
+ ad.log.error("Data rat in iwlan mode.")
+ return False
+ elif not wait_for_wfc_disabled(log, ad, MAX_WAIT_TIME_WFC_ENABLED):
+ ad.log.error("Should report wifi calling disabled within %s.",
+ MAX_WAIT_TIME_WFC_ENABLED)
+ return False
+ return True
+
+
+def phone_setup_data_for_subscription(log, ad, sub_id, network_generation,
+ nr_type=None):
+ """Setup Phone <sub_id> Data to <network_generation>
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+ network_generation: network generation, e.g. GEN_2G, GEN_3G, GEN_4G, GEN_5G
+ nr_type: NR network type e.g. NSA, SA, MMWAVE
+
+ Returns:
+ True if success, False if fail.
+ """
+ toggle_airplane_mode(log, ad, False, strict_checking=False)
+ set_wifi_to_default(log, ad)
+ if not set_wfc_mode(log, ad, WFC_MODE_DISABLED):
+ ad.log.error("Disable WFC failed.")
+ return False
+ if not ensure_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ network_generation,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+ get_telephony_signal_strength(ad)
+ return False
+ return True
+
+
+def phone_setup_5g(log, ad, nr_type=None):
+ """Setup Phone default data sub_id data to 5G.
+
+ Args:
+ log: log object
+ ad: android device object
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_5g_for_subscription(log, ad,
+ get_default_data_sub_id(ad), nr_type=nr_type)
+
+
+def phone_setup_5g_for_subscription(log, ad, sub_id, nr_type=None):
+ """Setup Phone <sub_id> Data to 5G.
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+ nr_type: NR network type e.g. NSA, SA, MMWAVE
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_data_for_subscription(log, ad, sub_id, GEN_5G,
+ nr_type=nr_type)
+
+
+def phone_setup_4g(log, ad):
+ """Setup Phone default data sub_id data to 4G.
+
+ Args:
+ log: log object
+ ad: android device object
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_4g_for_subscription(log, ad,
+ get_default_data_sub_id(ad))
+
+
+def phone_setup_4g_for_subscription(log, ad, sub_id):
+ """Setup Phone <sub_id> Data to 4G.
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_data_for_subscription(log, ad, sub_id, GEN_4G)
+
+
+def phone_setup_3g(log, ad):
+ """Setup Phone default data sub_id data to 3G.
+
+ Args:
+ log: log object
+ ad: android device object
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_3g_for_subscription(log, ad,
+ get_default_data_sub_id(ad))
+
+
+def phone_setup_3g_for_subscription(log, ad, sub_id):
+ """Setup Phone <sub_id> Data to 3G.
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_data_for_subscription(log, ad, sub_id, GEN_3G)
+
+
+def phone_setup_2g(log, ad):
+ """Setup Phone default data sub_id data to 2G.
+
+ Args:
+ log: log object
+ ad: android device object
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_2g_for_subscription(log, ad,
+ get_default_data_sub_id(ad))
+
+
+def phone_setup_2g_for_subscription(log, ad, sub_id):
+ """Setup Phone <sub_id> Data to 3G.
+
+ Args:
+ log: log object
+ ad: android device object
+ sub_id: subscription id
+
+ Returns:
+ True if success, False if fail.
+ """
+ return phone_setup_data_for_subscription(log, ad, sub_id, GEN_2G)
+
+
+def phone_setup_csfb(log, ad, nw_gen=GEN_4G, nr_type=None):
+ """Setup phone for CSFB call test.
+
+ Setup Phone to be in 4G mode.
+ Disabled VoLTE.
+
+ Args:
+ log: log object
+ ad: Android device object.
+ nw_gen: GEN_4G or GEN_5G
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_csfb_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad), nw_gen, nr_type=nr_type)
+
+
+def phone_setup_csfb_for_subscription(log, ad, sub_id, nw_gen=GEN_4G, nr_type=None):
+ """Setup phone for CSFB call test for subscription id.
+
+ Setup Phone to be in 4G mode.
+ Disabled VoLTE.
+
+ Args:
+ log: log object
+ ad: Android device object.
+ sub_id: subscription id.
+ nw_gen: GEN_4G or GEN_5G
+ nr_type: NR network type e.g. NSA, SA, MMWAVE
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ capabilities = ad.telephony["subscription"][sub_id].get("capabilities", [])
+ if capabilities:
+ if "hide_enhanced_4g_lte" in capabilities:
+ show_enhanced_4g_lte_mode = getattr(ad, "show_enhanced_4g_lte_mode", False)
+ if show_enhanced_4g_lte_mode in ["false", "False", False]:
+ ad.log.warning("'VoLTE' option is hidden. Test will be skipped.")
+ raise signals.TestSkip("'VoLTE' option is hidden. Test will be skipped.")
+
+ if nw_gen == GEN_4G:
+ if not phone_setup_4g_for_subscription(log, ad, sub_id):
+ ad.log.error("Failed to set to 4G data.")
+ return False
+ elif nw_gen == GEN_5G:
+ if not phone_setup_5g_for_subscription(log, ad, sub_id, nr_type=nr_type):
+ ad.log.error("Failed to set to 5G data.")
+ return False
+
+ if not toggle_volte_for_subscription(log, ad, sub_id, False):
+ return False
+
+ if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ return False
+
+ return phone_idle_csfb_for_subscription(log, ad, sub_id, nw_gen)
+
+
+def phone_setup_volte(log, ad, nw_gen=GEN_4G, nr_type=None):
+ """Setup VoLTE enable.
+
+ Args:
+ log: log object
+ ad: android device object.
+ nw_gen: GEN_4G or GEN_5G
+
+ Returns:
+ True: if VoLTE is enabled successfully.
+ False: for errors
+ """
+ if not get_capability_for_subscription(ad, CAPABILITY_VOLTE,
+ get_outgoing_voice_sub_id(ad)):
+ ad.log.error("VoLTE is not supported, abort test.")
+ raise signals.TestSkip("VoLTE is not supported, abort test.")
+ return phone_setup_volte_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad), nw_gen, nr_type= nr_type)
+
+
+def phone_setup_volte_for_subscription(log, ad, sub_id, nw_gen=GEN_4G,
+ nr_type=None):
+ """Setup VoLTE enable for subscription id.
+ Args:
+ log: log object
+ ad: android device object.
+ sub_id: subscription id.
+ nw_gen: GEN_4G or GEN_5G.
+ nr_type: NR network type.
+
+ Returns:
+ True: if VoLTE is enabled successfully.
+ False: for errors
+ """
+ if not get_capability_for_subscription(ad, CAPABILITY_VOLTE,
+ get_outgoing_voice_sub_id(ad)):
+ ad.log.error("VoLTE is not supported, abort test.")
+ raise signals.TestSkip("VoLTE is not supported, abort test.")
+
+ if nw_gen == GEN_4G:
+ if not phone_setup_4g_for_subscription(log, ad, sub_id):
+ ad.log.error("Failed to set to 4G data.")
+ return False
+ elif nw_gen == GEN_5G:
+ if not phone_setup_5g_for_subscription(log, ad, sub_id,
+ nr_type=nr_type):
+ ad.log.error("Failed to set to 5G data.")
+ return False
+ operator_name = get_operator_name(log, ad, sub_id)
+ if operator_name == CARRIER_TMO:
+ return True
+ else:
+ if not wait_for_enhanced_4g_lte_setting(log, ad, sub_id):
+ ad.log.error("Enhanced 4G LTE setting is not available")
+ return False
+ toggle_volte_for_subscription(log, ad, sub_id, True)
+ return phone_idle_volte_for_subscription(log, ad, sub_id, nw_gen,
+ nr_type=nr_type)
+
+
+def phone_setup_voice_3g(log, ad):
+ """Setup phone voice to 3G.
+
+ Args:
+ log: log object
+ ad: Android device object.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_voice_3g_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_setup_voice_3g_for_subscription(log, ad, sub_id):
+ """Setup phone voice to 3G for subscription id.
+
+ Args:
+ log: log object
+ ad: Android device object.
+ sub_id: subscription id.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ if not phone_setup_3g_for_subscription(log, ad, sub_id):
+ ad.log.error("Failed to set to 3G data.")
+ return False
+ if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ return False
+ return phone_idle_3g_for_subscription(log, ad, sub_id)
+
+
+def phone_setup_voice_2g(log, ad):
+ """Setup phone voice to 2G.
+
+ Args:
+ log: log object
+ ad: Android device object.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_voice_2g_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_setup_voice_2g_for_subscription(log, ad, sub_id):
+ """Setup phone voice to 2G for subscription id.
+
+ Args:
+ log: log object
+ ad: Android device object.
+ sub_id: subscription id.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ if not phone_setup_2g_for_subscription(log, ad, sub_id):
+ ad.log.error("Failed to set to 2G data.")
+ return False
+ if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ return False
+ return phone_idle_2g_for_subscription(log, ad, sub_id)
+
+
+def phone_setup_voice_general(log, ad):
+ """Setup phone for voice general call test.
+
+ Make sure phone attached to voice.
+ Make necessary delay.
+
+ Args:
+ ad: Android device object.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_voice_general_for_subscription(
+ log, ad, get_outgoing_voice_sub_id(ad))
+
+
+def phone_setup_voice_general_for_slot(log,ad,slot_id):
+ return phone_setup_voice_general_for_subscription(
+ log, ad, get_subid_from_slot_index(log,ad,slot_id))
+
+
+def phone_setup_voice_general_for_subscription(log, ad, sub_id):
+ """Setup phone for voice general call test for subscription id.
+
+ Make sure phone attached to voice.
+ Make necessary delay.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ toggle_airplane_mode(log, ad, False, strict_checking=False)
+ if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ # if phone can not attach voice, try phone_setup_voice_3g
+ return phone_setup_voice_3g_for_subscription(log, ad, sub_id)
+ return True
+
+
+def phone_setup_data_general(log, ad):
+ """Setup phone for data general test.
+
+ Make sure phone attached to data.
+ Make necessary delay.
+
+ Args:
+ ad: Android device object.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ return phone_setup_data_general_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultDataSubId())
+
+
+def phone_setup_data_general_for_subscription(log, ad, sub_id):
+ """Setup phone for data general test for subscription id.
+
+ Make sure phone attached to data.
+ Make necessary delay.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+
+ Returns:
+ True if setup successfully.
+ False for errors.
+ """
+ toggle_airplane_mode(log, ad, False, strict_checking=False)
+ if not wait_for_data_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION):
+ # if phone can not attach data, try reset network preference settings
+ reset_preferred_network_type_to_allowable_range(log, ad)
+
+ return wait_for_data_attach_for_subscription(log, ad, sub_id,
+ MAX_WAIT_TIME_NW_SELECTION)
+
+
+def phone_setup_rat_for_subscription(log, ad, sub_id, network_preference,
+ rat_family):
+ toggle_airplane_mode(log, ad, False, strict_checking=False)
+ set_wifi_to_default(log, ad)
+ if not set_wfc_mode(log, ad, WFC_MODE_DISABLED):
+ ad.log.error("Disable WFC failed.")
+ return False
+ return ensure_network_rat_for_subscription(log, ad, sub_id,
+ network_preference, rat_family)
+
+
+def phone_setup_lte_gsm_wcdma(log, ad):
+ return phone_setup_lte_gsm_wcdma_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_lte_gsm_wcdma_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(
+ log, ad, sub_id, NETWORK_MODE_LTE_GSM_WCDMA, RAT_FAMILY_LTE)
+
+
+def phone_setup_gsm_umts(log, ad):
+ return phone_setup_gsm_umts_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_gsm_umts_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(
+ log, ad, sub_id, NETWORK_MODE_GSM_UMTS, RAT_FAMILY_WCDMA)
+
+
+def phone_setup_gsm_only(log, ad):
+ return phone_setup_gsm_only_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_gsm_only_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(
+ log, ad, sub_id, NETWORK_MODE_GSM_ONLY, RAT_FAMILY_GSM)
+
+
+def phone_setup_lte_cdma_evdo(log, ad):
+ return phone_setup_lte_cdma_evdo_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_lte_cdma_evdo_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(
+ log, ad, sub_id, NETWORK_MODE_LTE_CDMA_EVDO, RAT_FAMILY_LTE)
+
+
+def phone_setup_cdma(log, ad):
+ return phone_setup_cdma_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId())
+
+
+def phone_setup_cdma_for_subscription(log, ad, sub_id):
+ return phone_setup_rat_for_subscription(log, ad, sub_id, NETWORK_MODE_CDMA,
+ RAT_FAMILY_CDMA2000)
+
+
+def phone_idle_volte(log, ad):
+ """Return if phone is idle for VoLTE call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_volte_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_volte_for_subscription(log, ad, sub_id, nw_gen=GEN_4G,
+ nr_type=None):
+ """Return if phone is idle for VoLTE call test for subscription id.
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ nw_gen: GEN_4G or GEN_5G.
+ nr_type: NR network type e.g. NSA, SA, MMWAVE
+ """
+ if nw_gen == GEN_5G:
+ if not is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
+ ad.log.error("Not in 5G coverage.")
+ return False
+ else:
+ if not wait_for_network_rat_for_subscription(
+ log, ad, sub_id, RAT_FAMILY_LTE,
+ voice_or_data=NETWORK_SERVICE_VOICE):
+ ad.log.error("Voice rat not in LTE mode.")
+ return False
+ if not wait_for_volte_enabled(log, ad, MAX_WAIT_TIME_VOLTE_ENABLED, sub_id):
+ ad.log.error(
+ "Failed to <report volte enabled true> within %s seconds.",
+ MAX_WAIT_TIME_VOLTE_ENABLED)
+ return False
+ return True
+
+
+def phone_idle_iwlan(log, ad):
+ """Return if phone is idle for WiFi calling call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_iwlan_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_iwlan_for_subscription(log, ad, sub_id):
+ """Return if phone is idle for WiFi calling call test for subscription id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ if not wait_for_wfc_enabled(log, ad, MAX_WAIT_TIME_WFC_ENABLED):
+ ad.log.error("Failed to <report wfc enabled true> within %s seconds.",
+ MAX_WAIT_TIME_WFC_ENABLED)
+ return False
+ return True
+
+
+def phone_idle_not_iwlan(log, ad):
+ """Return if phone is idle for non WiFi calling call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_not_iwlan_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_not_iwlan_for_subscription(log, ad, sub_id):
+ """Return if phone is idle for non WiFi calling call test for sub id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ if not wait_for_not_network_rat_for_subscription(
+ log, ad, sub_id, RAT_FAMILY_WLAN,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ log.error("{} data rat in iwlan mode.".format(ad.serial))
+ return False
+ return True
+
+
+def phone_idle_csfb(log, ad):
+ """Return if phone is idle for CSFB call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_csfb_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_csfb_for_subscription(log, ad, sub_id, nw_gen=GEN_4G, nr_type=None):
+ """Return if phone is idle for CSFB call test for subscription id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ nw_gen: GEN_4G or GEN_5G
+ """
+ if nw_gen == GEN_5G:
+ if not is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
+ ad.log.error("Not in 5G coverage.")
+ return False
+ else:
+ if not wait_for_network_rat_for_subscription(
+ log, ad, sub_id, RAT_FAMILY_LTE,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ ad.log.error("Data rat not in lte mode.")
+ return False
+ return True
+
+
+def phone_idle_3g(log, ad):
+ """Return if phone is idle for 3G call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_3g_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_3g_for_subscription(log, ad, sub_id):
+ """Return if phone is idle for 3G call test for subscription id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ return wait_for_network_generation_for_subscription(
+ log, ad, sub_id, GEN_3G, voice_or_data=NETWORK_SERVICE_VOICE)
+
+
+def phone_idle_2g(log, ad):
+ """Return if phone is idle for 2G call test.
+
+ Args:
+ ad: Android device object.
+ """
+ return phone_idle_2g_for_subscription(log, ad,
+ get_outgoing_voice_sub_id(ad))
+
+
+def phone_idle_2g_for_subscription(log, ad, sub_id):
+ """Return if phone is idle for 2G call test for subscription id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ return wait_for_network_generation_for_subscription(
+ log, ad, sub_id, GEN_2G, voice_or_data=NETWORK_SERVICE_VOICE)
+
+
+def phone_setup_on_rat(
+ log,
+ ad,
+ rat='volte',
+ sub_id=None,
+ is_airplane_mode=False,
+ wfc_mode=None,
+ wifi_ssid=None,
+ wifi_pwd=None,
+ only_return_fn=None,
+ sub_id_type='voice',
+ nr_type='nsa'):
+
+ if sub_id is None:
+ if sub_id_type == 'sms':
+ sub_id = get_outgoing_message_sub_id(ad)
+ else:
+ sub_id = get_outgoing_voice_sub_id(ad)
+
+ if get_default_data_sub_id(ad) != sub_id and '5g' in rat.lower():
+ ad.log.warning('Default data sub ID is NOT given sub ID %s.', sub_id)
+ network_preference = network_preference_for_generation(
+ GEN_5G,
+ ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+
+ ad.log.info("Network preference for %s is %s", GEN_5G,
+ network_preference)
+
+ if not set_preferred_network_mode_pref(log, ad, sub_id,
+ network_preference):
+ return False
+
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_5G,
+ max_wait_time=30,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+
+ ad.log.warning('Non-DDS slot (sub ID: %s) cannot attach 5G network.', sub_id)
+ ad.log.info('Check if sub ID %s can attach LTE network.', sub_id)
+
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_4G,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ return False
+
+ if "volte" in rat.lower():
+ phone_setup_volte_for_subscription(log, ad, sub_id, None)
+ elif "wfc" in rat.lower():
+ return phone_setup_iwlan_for_subscription(
+ log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd)
+ elif "csfb" in rat.lower():
+ return phone_setup_csfb_for_subscription(log, ad, sub_id, None)
+ return True
+
+ if rat.lower() == '5g_volte':
+ if only_return_fn:
+ return phone_setup_volte_for_subscription
+ else:
+ return phone_setup_volte_for_subscription(log, ad, sub_id, GEN_5G, nr_type='nsa')
+
+ elif rat.lower() == '5g_nsa_mmw_volte':
+ if only_return_fn:
+ return phone_setup_volte_for_subscription
+ else:
+ return phone_setup_volte_for_subscription(log, ad, sub_id, GEN_5G,
+ nr_type='mmwave')
+
+ elif rat.lower() == '5g_csfb':
+ if only_return_fn:
+ return phone_setup_csfb_for_subscription
+ else:
+ return phone_setup_csfb_for_subscription(log, ad, sub_id, GEN_5G, nr_type='nsa')
+
+ elif rat.lower() == '5g_wfc':
+ if only_return_fn:
+ return phone_setup_iwlan_for_subscription
+ else:
+ return phone_setup_iwlan_for_subscription(
+ log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd,
+ GEN_5G,
+ nr_type='nsa')
+
+ elif rat.lower() == '5g_nsa_mmw_wfc':
+ if only_return_fn:
+ return phone_setup_iwlan_for_subscription
+ else:
+ return phone_setup_iwlan_for_subscription(
+ log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd,
+ GEN_5G,
+ nr_type='mmwave')
+
+ elif rat.lower() == 'volte':
+ if only_return_fn:
+ return phone_setup_volte_for_subscription
+ else:
+ return phone_setup_volte_for_subscription(log, ad, sub_id)
+
+ elif rat.lower() == 'csfb':
+ if only_return_fn:
+ return phone_setup_csfb_for_subscription
+ else:
+ return phone_setup_csfb_for_subscription(log, ad, sub_id)
+
+ elif rat.lower() == '5g':
+ if only_return_fn:
+ return phone_setup_5g_for_subscription
+ else:
+ return phone_setup_5g_for_subscription(log, ad, sub_id, nr_type='nsa')
+
+ elif rat.lower() == '5g_nsa_mmwave':
+ if only_return_fn:
+ return phone_setup_5g_for_subscription
+ else:
+ return phone_setup_5g_for_subscription(log, ad, sub_id,
+ nr_type='mmwave')
+
+ elif rat.lower() == '3g':
+ if only_return_fn:
+ return phone_setup_voice_3g_for_subscription
+ else:
+ return phone_setup_voice_3g_for_subscription(log, ad, sub_id)
+
+ elif rat.lower() == '2g':
+ if only_return_fn:
+ return phone_setup_voice_2g_for_subscription
+ else:
+ return phone_setup_voice_2g_for_subscription(log, ad, sub_id)
+
+ elif rat.lower() == 'wfc':
+ if only_return_fn:
+ return phone_setup_iwlan_for_subscription
+ else:
+ return phone_setup_iwlan_for_subscription(
+ log,
+ ad,
+ sub_id,
+ is_airplane_mode,
+ wfc_mode,
+ wifi_ssid,
+ wifi_pwd)
+ elif rat.lower() == 'default':
+ if only_return_fn:
+ return ensure_phone_default_state
+ else:
+ return ensure_phone_default_state(log, ad)
+ else:
+ if only_return_fn:
+ return phone_setup_voice_general_for_subscription
+ else:
+ return phone_setup_voice_general_for_subscription(log, ad, sub_id)
+
+
+def wait_for_network_idle(
+ log,
+ ad,
+ rat,
+ sub_id,
+ nr_type='nsa'):
+ """Wait for attaching to network with assigned RAT and IMS/WFC registration
+
+ This function can be used right after network service recovery after turning
+ off airplane mode or switching DDS. It will ensure DUT has attached to the
+ network with assigned RAT, and VoLTE/WFC has been ready.
+
+ Args:
+ log: log object
+ ad: Android object
+ rat: following RAT are supported:
+ - 5g
+ - 5g_volte
+ - 5g_csfb
+ - 5g_wfc
+ - 4g (LTE)
+ - volte (LTE)
+ - csfb (LTE)
+ - wfc (LTE)
+
+ Returns:
+ True or False
+ """
+ if get_default_data_sub_id(ad) != sub_id and '5g' in rat.lower():
+ ad.log.warning('Default data sub ID is NOT given sub ID %s.', sub_id)
+ network_preference = network_preference_for_generation(
+ GEN_5G,
+ ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+
+ ad.log.info("Network preference for %s is %s", GEN_5G,
+ network_preference)
+
+ if not set_preferred_network_mode_pref(log, ad, sub_id,
+ network_preference):
+ return False
+
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_5G,
+ max_wait_time=30,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+
+ ad.log.warning('Non-DDS slot (sub ID: %s) cannot attach 5G network.', sub_id)
+ ad.log.info('Check if sub ID %s can attach LTE network.', sub_id)
+
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_4G,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ return False
+
+ if rat.lower() == '5g':
+ rat = '4g'
+ elif rat.lower() == '5g_volte':
+ rat = 'volte'
+ elif rat.lower() == '5g_wfc':
+ rat = 'wfc'
+ elif rat.lower() == '5g_csfb':
+ rat = 'csfb'
+
+ if rat.lower() == '5g_volte':
+ if not phone_idle_volte_for_subscription(log, ad, sub_id, GEN_5G, nr_type=nr_type):
+ return False
+ elif rat.lower() == '5g_csfb':
+ if not phone_idle_csfb_for_subscription(log, ad, sub_id, GEN_5G, nr_type=nr_type):
+ return False
+ elif rat.lower() == '5g_wfc':
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_5G,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+ return False
+ if not wait_for_wfc_enabled(log, ad):
+ return False
+ elif rat.lower() == '5g':
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_5G,
+ voice_or_data=NETWORK_SERVICE_DATA,
+ nr_type=nr_type):
+ return False
+ elif rat.lower() == 'volte':
+ if not phone_idle_volte_for_subscription(log, ad, sub_id, GEN_4G):
+ return False
+ elif rat.lower() == 'csfb':
+ if not phone_idle_csfb_for_subscription(log, ad, sub_id, GEN_4G):
+ return False
+ elif rat.lower() == 'wfc':
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_4G,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ return False
+ if not wait_for_wfc_enabled(log, ad):
+ return False
+ elif rat.lower() == '4g':
+ if not wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ GEN_4G,
+ voice_or_data=NETWORK_SERVICE_DATA):
+ return False
+ return True
+
+
+def ensure_preferred_network_type_for_subscription(
+ ad,
+ network_preference
+ ):
+ sub_id = ad.droid.subscriptionGetDefaultSubId()
+ if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
+ network_preference, sub_id):
+ ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
+ sub_id, network_preference)
+ return True
+
+
+def ensure_network_rat(log,
+ ad,
+ network_preference,
+ rat_family,
+ voice_or_data=None,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ toggle_apm_after_setting=False):
+ """Ensure ad's current network is in expected rat_family.
+ """
+ return ensure_network_rat_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
+ rat_family, voice_or_data, max_wait_time, toggle_apm_after_setting)
+
+
+def ensure_network_rat_for_subscription(
+ log,
+ ad,
+ sub_id,
+ network_preference,
+ rat_family,
+ voice_or_data=None,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ toggle_apm_after_setting=False):
+ """Ensure ad's current network is in expected rat_family.
+ """
+ if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
+ network_preference, sub_id):
+ ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
+ sub_id, network_preference)
+ return False
+ if is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family,
+ voice_or_data):
+ ad.log.info("Sub_id %s in RAT %s for %s", sub_id, rat_family,
+ voice_or_data)
+ return True
+
+ if toggle_apm_after_setting:
+ toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ toggle_airplane_mode(log, ad, new_state=None, strict_checking=False)
+
+ result = wait_for_network_rat_for_subscription(
+ log, ad, sub_id, rat_family, max_wait_time, voice_or_data)
+
+ log.info(
+ "End of ensure_network_rat_for_subscription for %s. "
+ "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
+ "data: %s(family: %s)", ad.serial, network_preference, rat_family,
+ voice_or_data,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
+ rat_family_from_rat(
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
+ sub_id)),
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
+ rat_family_from_rat(
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
+ sub_id)))
+ return result
+
+
+def ensure_network_preference(log,
+ ad,
+ network_preference,
+ voice_or_data=None,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ toggle_apm_after_setting=False):
+ """Ensure that current rat is within the device's preferred network rats.
+ """
+ return ensure_network_preference_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
+ voice_or_data, max_wait_time, toggle_apm_after_setting)
+
+
+def ensure_network_preference_for_subscription(
+ log,
+ ad,
+ sub_id,
+ network_preference,
+ voice_or_data=None,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ toggle_apm_after_setting=False):
+ """Ensure ad's network preference is <network_preference> for sub_id.
+ """
+ rat_family_list = rat_families_for_network_preference(network_preference)
+ if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
+ network_preference, sub_id):
+ log.error("Set Preferred Networks failed.")
+ return False
+ if is_droid_in_rat_family_list_for_subscription(
+ log, ad, sub_id, rat_family_list, voice_or_data):
+ return True
+
+ if toggle_apm_after_setting:
+ toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
+
+ result = wait_for_preferred_network_for_subscription(
+ log, ad, sub_id, network_preference, max_wait_time, voice_or_data)
+
+ ad.log.info(
+ "End of ensure_network_preference_for_subscription. "
+ "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
+ "data: %s(family: %s)", network_preference, rat_family_list,
+ voice_or_data,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
+ rat_family_from_rat(
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
+ sub_id)),
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
+ rat_family_from_rat(
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
+ sub_id)))
+ return result
+
+
+def ensure_network_generation(log,
+ ad,
+ generation,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None,
+ toggle_apm_after_setting=False,
+ nr_type=None):
+ """Ensure ad's network is <network generation> for default subscription ID.
+
+ Set preferred network generation to <generation>.
+ Toggle ON/OFF airplane mode if necessary.
+ Wait for ad in expected network type.
+ """
+ return ensure_network_generation_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
+ max_wait_time, voice_or_data, toggle_apm_after_setting, nr_type=nr_type)
+
+
+def ensure_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ generation,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None,
+ toggle_apm_after_setting=False,
+ nr_type=None):
+ """Ensure ad's network is <network generation> for specified subscription ID.
+
+ Set preferred network generation to <generation>.
+ Toggle ON/OFF airplane mode if necessary.
+ Wait for ad in expected network type.
+
+ Args:
+ log: log object.
+ ad: android device object.
+ sub_id: subscription id.
+ generation: network generation, e.g. GEN_2G, GEN_3G, GEN_4G, GEN_5G.
+ max_wait_time: the time to wait for NW selection.
+ voice_or_data: check voice network generation or data network generation
+ This parameter is optional. If voice_or_data is None, then if
+ either voice or data in expected generation, function will return True.
+ toggle_apm_after_setting: Cycle airplane mode if True, otherwise do nothing.
+
+ Returns:
+ True if success, False if fail.
+ """
+ ad.log.info(
+ "RAT network type voice: %s, data: %s",
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id))
+
+ try:
+ ad.log.info("Finding the network preference for generation %s for "
+ "operator %s phone type %s", generation,
+ ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+ network_preference = network_preference_for_generation(
+ generation, ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+ if ad.telephony["subscription"][sub_id]["operator"] == CARRIER_FRE \
+ and generation == GEN_4G:
+ network_preference = NETWORK_MODE_LTE_ONLY
+ ad.log.info("Network preference for %s is %s", generation,
+ network_preference)
+ rat_family = rat_family_for_generation(
+ generation, ad.telephony["subscription"][sub_id]["operator"],
+ ad.telephony["subscription"][sub_id]["phone_type"])
+ except KeyError as e:
+ ad.log.error("Failed to find a rat_family entry for generation %s"
+ " for subscriber id %s with error %s", generation,
+ sub_id, e)
+ return False
+
+ if not set_preferred_network_mode_pref(log, ad, sub_id,
+ network_preference):
+ return False
+
+ if hasattr(ad, "dsds") and voice_or_data == "data" and sub_id != get_default_data_sub_id(ad):
+ ad.log.info("MSIM - Non DDS, ignore data RAT")
+ return True
+
+ if (generation == GEN_5G) or (generation == RAT_5G):
+ if is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
+ ad.log.info("Current network type is 5G.")
+ return True
+ else:
+ ad.log.error("Not in 5G coverage for Sub %s.", sub_id)
+ return False
+
+ if is_droid_in_network_generation_for_subscription(
+ log, ad, sub_id, generation, voice_or_data):
+ return True
+
+ if toggle_apm_after_setting:
+ toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
+
+ result = wait_for_network_generation_for_subscription(
+ log, ad, sub_id, generation, max_wait_time, voice_or_data)
+
+ ad.log.info(
+ "Ensure network %s %s %s. With network preference %s, "
+ "current: voice: %s(family: %s), data: %s(family: %s)", generation,
+ voice_or_data, result, network_preference,
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
+ rat_generation_from_rat(
+ ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
+ sub_id)),
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
+ rat_generation_from_rat(
+ ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
+ sub_id)))
+ if not result:
+ get_telephony_signal_strength(ad)
+ return result
+
+
+def wait_for_network_rat(log,
+ ad,
+ rat_family,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ return wait_for_network_rat_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
+ max_wait_time, voice_or_data)
+
+
+def wait_for_network_rat_for_subscription(
+ log,
+ ad,
+ sub_id,
+ rat_family,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ return _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_wait_time,
+ is_droid_in_rat_family_for_subscription, rat_family, voice_or_data)
+
+
+def wait_for_not_network_rat(log,
+ ad,
+ rat_family,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ return wait_for_not_network_rat_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
+ max_wait_time, voice_or_data)
+
+
+def wait_for_not_network_rat_for_subscription(
+ log,
+ ad,
+ sub_id,
+ rat_family,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ return _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_wait_time,
+ lambda log, ad, sub_id, *args, **kwargs: not is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family, voice_or_data)
+ )
+
+
+def wait_for_preferred_network(log,
+ ad,
+ network_preference,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ return wait_for_preferred_network_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
+ max_wait_time, voice_or_data)
+
+
+def wait_for_preferred_network_for_subscription(
+ log,
+ ad,
+ sub_id,
+ network_preference,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ rat_family_list = rat_families_for_network_preference(network_preference)
+ return _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_wait_time,
+ is_droid_in_rat_family_list_for_subscription, rat_family_list,
+ voice_or_data)
+
+
+def wait_for_network_generation(log,
+ ad,
+ generation,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None):
+ return wait_for_network_generation_for_subscription(
+ log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
+ max_wait_time, voice_or_data)
+
+
+def wait_for_network_generation_for_subscription(
+ log,
+ ad,
+ sub_id,
+ generation,
+ max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
+ voice_or_data=None,
+ nr_type=None):
+
+ if generation == GEN_5G:
+ if is_current_network_5g(ad, sub_id=sub_id, nr_type=nr_type):
+ ad.log.info("Current network type is 5G.")
+ return True
+ else:
+ ad.log.error("Not in 5G coverage for Sub %s.", sub_id)
+ return False
+
+ return _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_wait_time,
+ is_droid_in_network_generation_for_subscription, generation,
+ voice_or_data)
+
+
+def ensure_phones_idle(log, ads, max_time=MAX_WAIT_TIME_CALL_DROP):
+ """Ensure ads idle (not in call).
+ """
+ result = True
+ for ad in ads:
+ if not ensure_phone_idle(log, ad, max_time=max_time):
+ result = False
+ return result
+
+
+def ensure_phone_idle(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP, retry=2):
+ """Ensure ad idle (not in call).
+ """
+ while ad.droid.telecomIsInCall() and retry > 0:
+ ad.droid.telecomEndCall()
+ time.sleep(3)
+ retry -= 1
+ if not wait_for_droid_not_in_call(log, ad, max_time=max_time):
+ ad.log.error("Failed to end call")
+ return False
+ return True
+
+
+def ensure_phone_subscription(log, ad):
+ """Ensure Phone Subscription.
+ """
+ #check for sim and service
+ duration = 0
+ while duration < MAX_WAIT_TIME_NW_SELECTION:
+ subInfo = ad.droid.subscriptionGetAllSubInfoList()
+ if subInfo and len(subInfo) >= 1:
+ ad.log.debug("Find valid subcription %s", subInfo)
+ break
+ else:
+ ad.log.info("Did not find any subscription")
+ time.sleep(5)
+ duration += 5
+ else:
+ ad.log.error("Unable to find a valid subscription!")
+ return False
+ while duration < MAX_WAIT_TIME_NW_SELECTION:
+ data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
+ voice_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
+ if data_sub_id > INVALID_SUB_ID or voice_sub_id > INVALID_SUB_ID:
+ ad.log.debug("Find valid voice or data sub id")
+ break
+ else:
+ ad.log.info("Did not find valid data or voice sub id")
+ time.sleep(5)
+ duration += 5
+ else:
+ ad.log.error("Unable to find valid data or voice sub id")
+ return False
+ while duration < MAX_WAIT_TIME_NW_SELECTION:
+ data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
+ if data_sub_id > INVALID_SUB_ID:
+ data_rat = get_network_rat_for_subscription(
+ log, ad, data_sub_id, NETWORK_SERVICE_DATA)
+ else:
+ data_rat = RAT_UNKNOWN
+ if voice_sub_id > INVALID_SUB_ID:
+ voice_rat = get_network_rat_for_subscription(
+ log, ad, voice_sub_id, NETWORK_SERVICE_VOICE)
+ else:
+ voice_rat = RAT_UNKNOWN
+ if data_rat != RAT_UNKNOWN or voice_rat != RAT_UNKNOWN:
+ ad.log.info("Data sub_id %s in %s, voice sub_id %s in %s",
+ data_sub_id, data_rat, voice_sub_id, voice_rat)
+ return True
+ else:
+ ad.log.info("Did not attach for data or voice service")
+ time.sleep(5)
+ duration += 5
+ else:
+ ad.log.error("Did not attach for voice or data service")
+ return False
+
+
+def ensure_phone_default_state(log, ad, check_subscription=True, retry=2):
+ """Ensure ad in default state.
+ Phone not in call.
+ Phone have no stored WiFi network and WiFi disconnected.
+ Phone not in airplane mode.
+ """
+ result = True
+ if not toggle_airplane_mode(log, ad, False, False):
+ ad.log.error("Fail to turn off airplane mode")
+ result = False
+ try:
+ set_wifi_to_default(log, ad)
+ while ad.droid.telecomIsInCall() and retry > 0:
+ ad.droid.telecomEndCall()
+ time.sleep(3)
+ retry -= 1
+ if not wait_for_droid_not_in_call(log, ad):
+ ad.log.error("Failed to end call")
+ #ad.droid.telephonyFactoryReset()
+ data_roaming = getattr(ad, 'roaming', False)
+ if get_cell_data_roaming_state_by_adb(ad) != data_roaming:
+ set_cell_data_roaming_state_by_adb(ad, data_roaming)
+ #remove_mobile_data_usage_limit(ad)
+ if not wait_for_not_network_rat(
+ log, ad, RAT_FAMILY_WLAN, voice_or_data=NETWORK_SERVICE_DATA):
+ ad.log.error("%s still in %s", NETWORK_SERVICE_DATA,
+ RAT_FAMILY_WLAN)
+ result = False
+
+ if check_subscription and not ensure_phone_subscription(log, ad):
+ ad.log.error("Unable to find a valid subscription!")
+ result = False
+ except Exception as e:
+ ad.log.error("%s failure, toggle APM instead", e)
+ toggle_airplane_mode_by_adb(log, ad, True)
+ toggle_airplane_mode_by_adb(log, ad, False)
+ ad.send_keycode("ENDCALL")
+ ad.adb.shell("settings put global wfc_ims_enabled 0")
+ ad.adb.shell("settings put global mobile_data 1")
+
+ return result
+
+
+def ensure_phones_default_state(log, ads, check_subscription=True):
+ """Ensure ads in default state.
+ Phone not in call.
+ Phone have no stored WiFi network and WiFi disconnected.
+ Phone not in airplane mode.
+
+ Returns:
+ True if all steps of restoring default state succeed.
+ False if any of the steps to restore default state fails.
+ """
+ tasks = []
+ for ad in ads:
+ tasks.append((ensure_phone_default_state, (log, ad,
+ check_subscription)))
+ if not multithread_func(log, tasks):
+ log.error("Ensure_phones_default_state Fail.")
+ return False
+ return True
+
+
+def is_phone_not_in_call(log, ad):
+ """Return True if phone not in call.
+
+ Args:
+ log: log object.
+ ad: android device.
+ """
+ in_call = ad.droid.telecomIsInCall()
+ call_state = ad.droid.telephonyGetCallState()
+ if in_call:
+ ad.log.info("Device is In Call")
+ if call_state != TELEPHONY_STATE_IDLE:
+ ad.log.info("Call_state is %s, not %s", call_state,
+ TELEPHONY_STATE_IDLE)
+ return ((not in_call) and (call_state == TELEPHONY_STATE_IDLE))
+
+
+def wait_for_droid_not_in_call(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP):
+ """Wait for android to be not in call state.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+
+ Returns:
+ If phone become not in call state within max_time, return True.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(log, ad, max_time, is_phone_not_in_call)
+
+
+def wait_for_voice_attach(log, ad, max_time=MAX_WAIT_TIME_NW_SELECTION):
+ """Wait for android device to attach on voice.
+
+ Args:
+ log: log object.
+ ad: android device.
+ max_time: maximal wait time.
+
+ Returns:
+ Return True if device attach voice within max_time.
+ Return False if timeout.
+ """
+ return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
+ NETWORK_SERVICE_VOICE)
+
+
+def wait_for_voice_attach_for_subscription(
+ log, ad, sub_id, max_time=MAX_WAIT_TIME_NW_SELECTION):
+ """Wait for android device to attach on voice in subscription id.
+
+ Args:
+ log: log object.
+ ad: android device.
+ sub_id: subscription id.
+ max_time: maximal wait time.
+
+ Returns:
+ Return True if device attach voice within max_time.
+ Return False if timeout.
+ """
+ if not _wait_for_droid_in_state_for_subscription(
+ log, ad, sub_id, max_time, _is_attached_for_subscription,
+ NETWORK_SERVICE_VOICE):
+ return False
+
+ # TODO: b/26295983 if pone attach to 1xrtt from unknown, phone may not
+ # receive incoming call immediately.
+ if ad.droid.telephonyGetCurrentVoiceNetworkType() == RAT_1XRTT:
+ time.sleep(WAIT_TIME_1XRTT_VOICE_ATTACH)
+ return True
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_sms_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_sms_utils.py
index 408fee1..891e6b1 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_sms_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_sms_utils.py
@@ -18,13 +18,13 @@
import time
from acts.utils import rand_ascii_str
from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
-
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
message_lengths = (50, 160, 180)
+
def _sms_test(log, ads):
"""Test SMS between two phones.
Returns:
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_ss_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_ss_utils.py
index 702eadf..dafd078 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_ss_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_ss_utils.py
@@ -22,30 +22,32 @@
from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
from acts_contrib.test_utils.tel.tel_defines import NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
from acts_contrib.test_utils.tel.tel_test_utils import _phone_number_remove_prefix
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_ring_by_adb
from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_idle_by_adb
-from acts_contrib.test_utils.tel.tel_test_utils import dial_phone_number
-from acts_contrib.test_utils.tel.tel_test_utils import disconnect_call_by_id
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import get_slot_index_from_subid
from acts_contrib.test_utils.tel.tel_test_utils import get_user_config_profile
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import is_phone_in_call
-from acts_contrib.test_utils.tel.tel_test_utils import last_call_drop_reason
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_msim
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_call_id_clearing
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_call_offhook_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_in_call_active
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_ringing_call_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import dial_phone_number
+from acts_contrib.test_utils.tel.tel_voice_utils import disconnect_call_by_id
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
+from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
+from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_id_clearing
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_offhook_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_in_call_active
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_ringing_call_for_subscription
def call_setup_teardown_for_call_forwarding(
@@ -551,7 +553,7 @@
if call_forwarding_type != "unconditional":
return "unknown"
- slot_index_of_default_voice_subid = get_slot_index_from_subid(log, ad,
+ slot_index_of_default_voice_subid = get_slot_index_from_subid(ad,
get_incoming_voice_sub_id(ad))
output = ad.adb.shell("dumpsys telephony.registry | grep mCallForwarding")
if "mCallForwarding" in output:
@@ -1407,4 +1409,293 @@
else:
retry = retry + 1
- return False
\ No newline at end of file
+ return False
+
+
+def three_phone_call_forwarding_short_seq(log,
+ phone_a,
+ phone_a_idle_func,
+ phone_a_in_call_check_func,
+ phone_b,
+ phone_c,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ call_forwarding_type="unconditional",
+ retry=2):
+ """Short sequence of call process with call forwarding.
+ Test steps:
+ 1. Ensure all phones are initially in idle state.
+ 2. Enable call forwarding on Phone A.
+ 3. Make a call from Phone B to Phone A, The call should be forwarded to
+ PhoneC. Accept the call on Phone C.
+ 4. Ensure the call is connected and in correct phone state.
+ 5. Hang up the call on Phone B.
+ 6. Ensure all phones are in idle state.
+ 7. Disable call forwarding on Phone A.
+ 7. Make a call from Phone B to Phone A, The call should NOT be forwarded
+ to PhoneC. Accept the call on Phone A.
+ 8. Ensure the call is connected and in correct phone state.
+ 9. Hang up the call on Phone B.
+
+ Args:
+ phone_a: android object of Phone A
+ phone_a_idle_func: function to check idle state on Phone A
+ phone_a_in_call_check_func: function to check in-call state on Phone A
+ phone_b: android object of Phone B
+ phone_c: android object of Phone C
+ wait_time_in_call: time to wait in call.
+ This is optional, default is WAIT_TIME_IN_CALL
+ call_forwarding_type:
+ - "unconditional"
+ - "busy"
+ - "not_answered"
+ - "not_reachable"
+ retry: times of retry
+
+ Returns:
+ True: if call sequence succeed.
+ False: for errors
+ """
+ ads = [phone_a, phone_b, phone_c]
+
+ call_params = [
+ (ads[1], ads[0], ads[2], ads[1], phone_a_in_call_check_func, False)
+ ]
+
+ if call_forwarding_type != "unconditional":
+ call_params.append((
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ phone_a_in_call_check_func,
+ True))
+
+ for param in call_params:
+ ensure_phones_idle(log, ads)
+ if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
+ phone_a.log.error("Phone A Failed to Reselect")
+ return False
+
+ time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
+
+ log.info(
+ "---> Call forwarding %s (caller: %s, callee: %s, callee forwarded:"
+ " %s) <---",
+ call_forwarding_type,
+ param[0].serial,
+ param[1].serial,
+ param[2].serial)
+ while not call_setup_teardown_for_call_forwarding(
+ log,
+ *param,
+ wait_time_in_call=wait_time_in_call,
+ call_forwarding_type=call_forwarding_type) and retry >= 0:
+
+ if retry <= 0:
+ log.error("Call forwarding %s failed." % call_forwarding_type)
+ return False
+ else:
+ log.info(
+ "RERUN the test case: 'Call forwarding %s'" %
+ call_forwarding_type)
+
+ retry = retry - 1
+
+ return True
+
+def three_phone_call_waiting_short_seq(log,
+ phone_a,
+ phone_a_idle_func,
+ phone_a_in_call_check_func,
+ phone_b,
+ phone_c,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ call_waiting=True,
+ scenario=None,
+ retry=2):
+ """Short sequence of call process with call waiting.
+ Test steps:
+ 1. Ensure all phones are initially in idle state.
+ 2. Enable call waiting on Phone A.
+ 3. Make the 1st call from Phone B to Phone A. Accept the call on Phone B.
+ 4. Ensure the call is connected and in correct phone state.
+ 5. Make the 2nd call from Phone C to Phone A. The call should be able to
+ income correctly. Whether or not the 2nd call should be answered by
+ Phone A depends on the scenario listed in the next step.
+ 6. Following 8 scenarios will be tested:
+ - 1st call ended first by Phone B during 2nd call incoming. 2nd call
+ ended by Phone C
+ - 1st call ended first by Phone B during 2nd call incoming. 2nd call
+ ended by Phone A
+ - 1st call ended first by Phone A during 2nd call incoming. 2nd call
+ ended by Phone C
+ - 1st call ended first by Phone A during 2nd call incoming. 2nd call
+ ended by Phone A
+ - 1st call ended by Phone B. 2nd call ended by Phone C
+ - 1st call ended by Phone B. 2nd call ended by Phone A
+ - 1st call ended by Phone A. 2nd call ended by Phone C
+ - 1st call ended by Phone A. 2nd call ended by Phone A
+ 7. Ensure all phones are in idle state.
+
+ Args:
+ phone_a: android object of Phone A
+ phone_a_idle_func: function to check idle state on Phone A
+ phone_a_in_call_check_func: function to check in-call state on Phone A
+ phone_b: android object of Phone B
+ phone_c: android object of Phone C
+ wait_time_in_call: time to wait in call.
+ This is optional, default is WAIT_TIME_IN_CALL
+ call_waiting: True for call waiting enabled and False for disabled
+ scenario: 1-8 for scenarios listed above
+ retry: times of retry
+
+ Returns:
+ True: if call sequence succeed.
+ False: for errors
+ """
+ ads = [phone_a, phone_b, phone_c]
+
+ sub_test_cases = [
+ {
+ "description": "1st call ended first by caller1 during 2nd call"
+ " incoming. 2nd call ended by caller2",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ ads[2],
+ phone_a_in_call_check_func,
+ True)},
+ {
+ "description": "1st call ended first by caller1 during 2nd call"
+ " incoming. 2nd call ended by callee",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ ads[0],
+ phone_a_in_call_check_func,
+ True)},
+ {
+ "description": "1st call ended first by callee during 2nd call"
+ " incoming. 2nd call ended by caller2",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[2],
+ phone_a_in_call_check_func,
+ True)},
+ {
+ "description": "1st call ended first by callee during 2nd call"
+ " incoming. 2nd call ended by callee",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[0],
+ phone_a_in_call_check_func,
+ True)},
+ {
+ "description": "1st call ended by caller1. 2nd call ended by"
+ " caller2",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ ads[2],
+ phone_a_in_call_check_func,
+ False)},
+ {
+ "description": "1st call ended by caller1. 2nd call ended by callee",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[1],
+ ads[0],
+ phone_a_in_call_check_func,
+ False)},
+ {
+ "description": "1st call ended by callee. 2nd call ended by caller2",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[2],
+ phone_a_in_call_check_func,
+ False)},
+ {
+ "description": "1st call ended by callee. 2nd call ended by callee",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[0],
+ phone_a_in_call_check_func,
+ False)}
+ ]
+
+ if call_waiting:
+ if not scenario:
+ test_cases = sub_test_cases
+ else:
+ test_cases = [sub_test_cases[scenario-1]]
+ else:
+ test_cases = [
+ {
+ "description": "Call waiting deactivated",
+ "params": (
+ ads[1],
+ ads[0],
+ ads[2],
+ ads[0],
+ ads[0],
+ phone_a_in_call_check_func,
+ False)}
+ ]
+
+ results = []
+
+ for test_case in test_cases:
+ ensure_phones_idle(log, ads)
+ if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
+ phone_a.log.error("Phone A Failed to Reselect")
+ return False
+
+ time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
+
+ log.info(
+ "---> %s (caller1: %s, caller2: %s, callee: %s) <---",
+ test_case["description"],
+ test_case["params"][1].serial,
+ test_case["params"][2].serial,
+ test_case["params"][0].serial)
+
+ while not call_setup_teardown_for_call_waiting(
+ log,
+ *test_case["params"],
+ wait_time_in_call=wait_time_in_call,
+ call_waiting=call_waiting) and retry >= 0:
+
+ if retry <= 0:
+ log.error("Call waiting sub-case: '%s' failed." % test_case[
+ "description"])
+ results.append(False)
+ else:
+ log.info("RERUN the sub-case: '%s'" % test_case["description"])
+
+ retry = retry - 1
+
+ for result in results:
+ if not result:
+ return False
+
+ return True
\ No newline at end of file
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_subscription_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_subscription_utils.py
index 7e936df..6fd9e90 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_subscription_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_subscription_utils.py
@@ -20,6 +20,7 @@
import time
from acts_contrib.test_utils.tel.tel_defines import CHIPSET_MODELS_LIST
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SIM_SLOT_INDEX
from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
from future import standard_library
@@ -228,6 +229,7 @@
return info['carrierId']
return None
+
def get_isopportunistic_from_slot_index(ad, sim_slot_index):
""" Get the isOppotunistic field for a particular slot
@@ -244,6 +246,7 @@
return info['isOpportunistic']
return None
+
def set_subid_for_data(ad, sub_id, time_to_sleep=WAIT_TIME_CHANGE_DATA_SUB_ID):
"""Set subId for data
@@ -339,6 +342,7 @@
if hasattr(ad, "outgoing_voice_sub_id"):
ad.outgoing_voice_sub_id = sub_id
+
def set_default_sub_for_all_services(ad, slot_id=0):
"""Set subId for all services
@@ -559,6 +563,15 @@
return host_sub_id, p1_sub_id, p2_sub_id
+
+def get_slot_index_from_subid(ad, sub_id):
+ try:
+ info = ad.droid.subscriptionGetSubInfoForSubscriber(sub_id)
+ return info['simSlotIndex']
+ except KeyError:
+ return INVALID_SIM_SLOT_INDEX
+
+
def get_slot_index_from_data_sub_id(ad):
"""Get slot index from given sub ID for data
@@ -575,6 +588,7 @@
return info['simSlotIndex']
return INVALID_SUB_ID
+
def get_slot_index_from_voice_sub_id(ad):
"""Get slot index from the current voice sub ID.
@@ -593,6 +607,7 @@
return info['simSlotIndex']
return INVALID_SUB_ID
+
def get_all_sub_id(ad):
"""Return all valid subscription IDs.
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py
index 14e3209..3d7e935 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_test_utils.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2016 - Google
+# Copyright 2022 - Google
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -27,18 +27,15 @@
import struct
from acts import signals
-from acts import utils
from queue import Empty
from acts.asserts import abort_all
-from acts.controllers.adb_lib.error import AdbError
+from acts.controllers.adb_lib.error import AdbCommandError, AdbError
from acts.controllers.android_device import list_adb_devices
from acts.controllers.android_device import list_fastboot_devices
-from acts.controllers.android_device import SL4A_APK_NAME
-from acts.libs.proc import job
+from acts.libs.proc.job import TimeoutError
from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
-from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs, CARRIER_NTT_DOCOMO, CARRIER_KDDI, CARRIER_RAKUTEN, \
- CARRIER_SBM
+from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs
from acts_contrib.test_utils.tel.tel_defines import AOSP_PREFIX
from acts_contrib.test_utils.tel.tel_defines import CARD_POWER_DOWN
from acts_contrib.test_utils.tel.tel_defines import CARD_POWER_UP
@@ -51,50 +48,24 @@
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC_MODE_CHANGE
from acts_contrib.test_utils.tel.tel_defines import CARRIER_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import CARRIER_FRE
from acts_contrib.test_utils.tel.tel_defines import COUNTRY_CODE_LIST
from acts_contrib.test_utils.tel.tel_defines import DIALER_PACKAGE_NAME
-from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
-from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_DISCONNECTED
from acts_contrib.test_utils.tel.tel_defines import DATA_ROAMING_ENABLE
from acts_contrib.test_utils.tel.tel_defines import DATA_ROAMING_DISABLE
from acts_contrib.test_utils.tel.tel_defines import GEN_4G
-from acts_contrib.test_utils.tel.tel_defines import GEN_5G
from acts_contrib.test_utils.tel.tel_defines import GEN_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
-from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
from acts_contrib.test_utils.tel.tel_defines import INVALID_SIM_SLOT_INDEX
from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import MAX_SAVED_VOICE_MAIL
from acts_contrib.test_utils.tel.tel_defines import MAX_SCREEN_ON_TIME
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_AIRPLANEMODE_EVENT
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_DROP
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_INITIATION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALLEE_RINGING
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_DATA_SUB_CHANGE
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_IDLE_EVENT
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TELECOM_RINGING
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOICE_MAIL_COUNT
from acts_contrib.test_utils.tel.tel_defines import MESSAGE_PACKAGE_NAME
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_NW_VALID_FAIL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL_RECOVERY
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_CELL
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_WIFI
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_7_DIGIT
from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_10_DIGIT
from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_11_DIGIT
from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_12_DIGIT
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
-from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import RAT_5G
from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_MAPPING
@@ -106,78 +77,49 @@
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_READY
from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
-from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
-from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
-from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_LEAVE_VOICE_MAIL
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_REJECT_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_SYNC_DATE_TIME_FROM_NETWORK
-from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import TYPE_MOBILE
-from acts_contrib.test_utils.tel.tel_defines import TYPE_WIFI
-from acts_contrib.test_utils.tel.tel_defines import EventCallStateChanged
from acts_contrib.test_utils.tel.tel_defines import EventActiveDataSubIdChanged
from acts_contrib.test_utils.tel.tel_defines import EventDisplayInfoChanged
-from acts_contrib.test_utils.tel.tel_defines import EventConnectivityChanged
-from acts_contrib.test_utils.tel.tel_defines import EventDataConnectionStateChanged
-from acts_contrib.test_utils.tel.tel_defines import EventMessageWaitingIndicatorChanged
from acts_contrib.test_utils.tel.tel_defines import EventServiceStateChanged
-from acts_contrib.test_utils.tel.tel_defines import CallStateContainer
-from acts_contrib.test_utils.tel.tel_defines import DataConnectionStateContainer
-from acts_contrib.test_utils.tel.tel_defines import MessageWaitingIndicatorContainer
from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackContainer
from acts_contrib.test_utils.tel.tel_defines import ServiceStateContainer
from acts_contrib.test_utils.tel.tel_defines import DisplayInfoContainer
from acts_contrib.test_utils.tel.tel_defines import OverrideNetworkContainer
from acts_contrib.test_utils.tel.tel_logging_utils import disable_qxdm_logger
+from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_log
+from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
from acts_contrib.test_utils.tel.tel_lookup_tables import connection_type_from_type_string
from acts_contrib.test_utils.tel.tel_lookup_tables import is_valid_rat
from acts_contrib.test_utils.tel.tel_lookup_tables import get_allowable_network_preference
from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_count_check_function
from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_check_number
-from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_delete_digit
from acts_contrib.test_utils.tel.tel_lookup_tables import network_preference_for_generation
from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_network_name
from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
-from acts_contrib.test_utils.tel.tel_lookup_tables import rat_families_for_network_preference
-from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_for_generation
from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_from_rat
from acts_contrib.test_utils.tel.tel_lookup_tables import rat_generation_from_rat
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_by_adb
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import set_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_for_subscription
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g
-from acts_contrib.test_utils.wifi import wifi_test_utils
from acts.utils import adb_shell_ping
from acts.utils import load_config
from acts.logger import epoch_to_log_line_timestamp
from acts.utils import get_current_epoch_time
from acts.utils import exe_cmd
-from acts.libs.utils.multithread import multithread_func
-WIFI_SSID_KEY = wifi_test_utils.WifiEnums.SSID_KEY
-WIFI_PWD_KEY = wifi_test_utils.WifiEnums.PWD_KEY
-WIFI_CONFIG_APBAND_2G = 1
-WIFI_CONFIG_APBAND_5G = 2
-WIFI_CONFIG_APBAND_AUTO = wifi_test_utils.WifiEnums.WIFI_CONFIG_APBAND_AUTO
log = logging
STORY_LINE = "+19523521350"
CallResult = TelephonyVoiceTestResult.CallResult.Value
-voice_call_type = {}
-result_dict ={}
class TelResultWrapper(object):
@@ -492,14 +434,6 @@
}
-def get_slot_index_from_subid(log, ad, sub_id):
- try:
- info = ad.droid.subscriptionGetSubInfoForSubscriber(sub_id)
- return info['simSlotIndex']
- except KeyError:
- return INVALID_SIM_SLOT_INDEX
-
-
def get_num_active_sims(log, ad):
""" Get the number of active SIM cards by counting slots
@@ -588,12 +522,6 @@
return signal_strength
-def get_wifi_signal_strength(ad):
- signal_strength = ad.droid.wifiGetConnectionInfo()['rssi']
- ad.log.info("WiFi Signal Strength is %s" % signal_strength)
- return signal_strength
-
-
def get_lte_rsrp(ad):
try:
if ad.adb.getprop("ro.build.version.release")[0] in ("9", "P"):
@@ -618,66 +546,6 @@
return None
-def check_data_stall_detection(ad, wait_time=WAIT_TIME_FOR_DATA_STALL):
- data_stall_detected = False
- time_var = 1
- try:
- while (time_var < wait_time):
- out = ad.adb.shell("dumpsys network_stack " \
- "| grep \"Suspecting data stall\"",
- ignore_status=True)
- ad.log.debug("Output is %s", out)
- if out:
- ad.log.info("NetworkMonitor detected - %s", out)
- data_stall_detected = True
- break
- time.sleep(30)
- time_var += 30
- except Exception as e:
- ad.log.error(e)
- return data_stall_detected
-
-
-def check_network_validation_fail(ad, begin_time=None,
- wait_time=WAIT_TIME_FOR_NW_VALID_FAIL):
- network_validation_fail = False
- time_var = 1
- try:
- while (time_var < wait_time):
- time_var += 30
- nw_valid = ad.search_logcat("validation failed",
- begin_time)
- if nw_valid:
- ad.log.info("Validation Failed received here - %s",
- nw_valid[0]["log_message"])
- network_validation_fail = True
- break
- time.sleep(30)
- except Exception as e:
- ad.log.error(e)
- return network_validation_fail
-
-
-def check_data_stall_recovery(ad, begin_time=None,
- wait_time=WAIT_TIME_FOR_DATA_STALL_RECOVERY):
- data_stall_recovery = False
- time_var = 1
- try:
- while (time_var < wait_time):
- time_var += 30
- recovery = ad.search_logcat("doRecovery() cleanup all connections",
- begin_time)
- if recovery:
- ad.log.info("Recovery Performed here - %s",
- recovery[-1]["log_message"])
- data_stall_recovery = True
- break
- time.sleep(30)
- except Exception as e:
- ad.log.error(e)
- return data_stall_recovery
-
-
def break_internet_except_sl4a_port(ad, sl4a_port):
ad.log.info("Breaking internet using iptables rules")
ad.adb.shell("iptables -I INPUT 1 -p tcp --dport %s -j ACCEPT" % sl4a_port,
@@ -970,434 +838,6 @@
return True
-def wait_and_answer_call(log,
- ad,
- incoming_number=None,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- caller=None,
- video_state=None):
- """Wait for an incoming call on default voice subscription and
- accepts the call.
-
- Args:
- ad: android device object.
- incoming_number: Expected incoming number.
- Optional. Default is None
- incall_ui_display: after answer the call, bring in-call UI to foreground or
- background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- return wait_and_answer_call_for_subscription(
- log,
- ad,
- get_incoming_voice_sub_id(ad),
- incoming_number,
- incall_ui_display=incall_ui_display,
- caller=caller,
- video_state=video_state)
-
-
-def _wait_for_ringing_event(log, ad, wait_time):
- """Wait for ringing event.
-
- Args:
- log: log object.
- ad: android device object.
- wait_time: max time to wait for ringing event.
-
- Returns:
- event_ringing if received ringing event.
- otherwise return None.
- """
- event_ringing = None
-
- try:
- event_ringing = ad.ed.wait_for_event(
- EventCallStateChanged,
- is_event_match,
- timeout=wait_time,
- field=CallStateContainer.CALL_STATE,
- value=TELEPHONY_STATE_RINGING)
- ad.log.info("Receive ringing event")
- except Empty:
- ad.log.info("No Ringing Event")
- finally:
- return event_ringing
-
-
-def wait_for_ringing_call(log, ad, incoming_number=None):
- """Wait for an incoming call on default voice subscription and
- accepts the call.
-
- Args:
- log: log object.
- ad: android device object.
- incoming_number: Expected incoming number.
- Optional. Default is None
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- return wait_for_ringing_call_for_subscription(
- log, ad, get_incoming_voice_sub_id(ad), incoming_number)
-
-
-def wait_for_ringing_call_for_subscription(
- log,
- ad,
- sub_id,
- incoming_number=None,
- caller=None,
- event_tracking_started=False,
- timeout=MAX_WAIT_TIME_CALLEE_RINGING,
- interval=WAIT_TIME_BETWEEN_STATE_CHECK):
- """Wait for an incoming call on specified subscription.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription ID
- incoming_number: Expected incoming number. Default is None
- event_tracking_started: True if event tracking already state outside
- timeout: time to wait for ring
- interval: checking interval
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- if not event_tracking_started:
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- ring_event_received = False
- end_time = time.time() + timeout
- try:
- while time.time() < end_time:
- if not ring_event_received:
- event_ringing = _wait_for_ringing_event(log, ad, interval)
- if event_ringing:
- if incoming_number and not check_phone_number_match(
- event_ringing['data']
- [CallStateContainer.INCOMING_NUMBER], incoming_number):
- ad.log.error(
- "Incoming Number not match. Expected number:%s, actual number:%s",
- incoming_number, event_ringing['data'][
- CallStateContainer.INCOMING_NUMBER])
- return False
- ring_event_received = True
- telephony_state = ad.droid.telephonyGetCallStateForSubscription(
- sub_id)
- telecom_state = ad.droid.telecomGetCallState()
- if telephony_state == TELEPHONY_STATE_RINGING and (
- telecom_state == TELEPHONY_STATE_RINGING):
- ad.log.info("callee is in telephony and telecom RINGING state")
- if caller:
- if caller.droid.telecomIsInCall():
- caller.log.info("Caller telecom is in call state")
- return True
- else:
- caller.log.info("Caller telecom is NOT in call state")
- else:
- return True
- else:
- ad.log.info(
- "telephony in %s, telecom in %s, expecting RINGING state",
- telephony_state, telecom_state)
- time.sleep(interval)
- finally:
- if not event_tracking_started:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
- sub_id)
-
-
-def wait_for_call_offhook_for_subscription(
- log,
- ad,
- sub_id,
- event_tracking_started=False,
- timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
- interval=WAIT_TIME_BETWEEN_STATE_CHECK):
- """Wait for an incoming call on specified subscription.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription ID
- timeout: time to wait for ring
- interval: checking interval
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- if not event_tracking_started:
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- offhook_event_received = False
- end_time = time.time() + timeout
- try:
- while time.time() < end_time:
- if not offhook_event_received:
- if wait_for_call_offhook_event(log, ad, sub_id, True,
- interval):
- offhook_event_received = True
- telephony_state = ad.droid.telephonyGetCallStateForSubscription(
- sub_id)
- telecom_state = ad.droid.telecomGetCallState()
- if telephony_state == TELEPHONY_STATE_OFFHOOK and (
- telecom_state == TELEPHONY_STATE_OFFHOOK):
- ad.log.info("telephony and telecom are in OFFHOOK state")
- return True
- else:
- ad.log.info(
- "telephony in %s, telecom in %s, expecting OFFHOOK state",
- telephony_state, telecom_state)
- if offhook_event_received:
- time.sleep(interval)
- finally:
- if not event_tracking_started:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
- sub_id)
-
-
-def wait_for_call_offhook_event(
- log,
- ad,
- sub_id,
- event_tracking_started=False,
- timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT):
- """Wait for an incoming call on specified subscription.
-
- Args:
- log: log object.
- ad: android device object.
- event_tracking_started: True if event tracking already state outside
- timeout: time to wait for event
-
- Returns:
- True: if call offhook event is received.
- False: if call offhook event is not received.
- """
- if not event_tracking_started:
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- try:
- ad.ed.wait_for_event(
- EventCallStateChanged,
- is_event_match,
- timeout=timeout,
- field=CallStateContainer.CALL_STATE,
- value=TELEPHONY_STATE_OFFHOOK)
- ad.log.info("Got event %s", TELEPHONY_STATE_OFFHOOK)
- except Empty:
- ad.log.info("No event for call state change to OFFHOOK")
- return False
- finally:
- if not event_tracking_started:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
- sub_id)
- return True
-
-
-def wait_and_answer_call_for_subscription(
- log,
- ad,
- sub_id,
- incoming_number=None,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- timeout=MAX_WAIT_TIME_CALLEE_RINGING,
- caller=None,
- video_state=None):
- """Wait for an incoming call on specified subscription and
- accepts the call.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription ID
- incoming_number: Expected incoming number.
- Optional. Default is None
- incall_ui_display: after answer the call, bring in-call UI to foreground or
- background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
-
- Returns:
- True: if incoming call is received and answered successfully.
- False: for errors
- """
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- try:
- if not wait_for_ringing_call_for_subscription(
- log,
- ad,
- sub_id,
- incoming_number=incoming_number,
- caller=caller,
- event_tracking_started=True,
- timeout=timeout):
- ad.log.info("Incoming call ringing check failed.")
- return False
- ad.log.info("Accept the ring call")
- ad.droid.telecomAcceptRingingCall(video_state)
-
- if wait_for_call_offhook_for_subscription(
- log, ad, sub_id, event_tracking_started=True):
- return True
- else:
- ad.log.error("Could not answer the call.")
- return False
- except Exception as e:
- log.error(e)
- return False
- finally:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
- if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
- ad.droid.telecomShowInCallScreen()
- elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
- ad.droid.showHomeScreen()
-
-
-def wait_and_reject_call(log,
- ad,
- incoming_number=None,
- delay_reject=WAIT_TIME_REJECT_CALL,
- reject=True):
- """Wait for an incoming call on default voice subscription and
- reject the call.
-
- Args:
- log: log object.
- ad: android device object.
- incoming_number: Expected incoming number.
- Optional. Default is None
- delay_reject: time to wait before rejecting the call
- Optional. Default is WAIT_TIME_REJECT_CALL
-
- Returns:
- True: if incoming call is received and reject successfully.
- False: for errors
- """
- return wait_and_reject_call_for_subscription(log, ad,
- get_incoming_voice_sub_id(ad),
- incoming_number, delay_reject,
- reject)
-
-
-def wait_and_reject_call_for_subscription(log,
- ad,
- sub_id,
- incoming_number=None,
- delay_reject=WAIT_TIME_REJECT_CALL,
- reject=True):
- """Wait for an incoming call on specific subscription and
- reject the call.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription ID
- incoming_number: Expected incoming number.
- Optional. Default is None
- delay_reject: time to wait before rejecting the call
- Optional. Default is WAIT_TIME_REJECT_CALL
-
- Returns:
- True: if incoming call is received and reject successfully.
- False: for errors
- """
-
- if not wait_for_ringing_call_for_subscription(log, ad, sub_id,
- incoming_number):
- ad.log.error(
- "Could not reject a call: incoming call in ringing check failed.")
- return False
-
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- if reject is True:
- # Delay between ringing and reject.
- time.sleep(delay_reject)
- is_find = False
- # Loop the call list and find the matched one to disconnect.
- for call in ad.droid.telecomCallGetCallIds():
- if check_phone_number_match(
- get_number_from_tel_uri(get_call_uri(ad, call)),
- incoming_number):
- ad.droid.telecomCallDisconnect(call)
- ad.log.info("Callee reject the call")
- is_find = True
- if is_find is False:
- ad.log.error("Callee did not find matching call to reject.")
- return False
- else:
- # don't reject on callee. Just ignore the incoming call.
- ad.log.info("Callee received incoming call. Ignore it.")
- try:
- ad.ed.wait_for_event(
- EventCallStateChanged,
- is_event_match_for_list,
- timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
- field=CallStateContainer.CALL_STATE,
- value_list=[TELEPHONY_STATE_IDLE, TELEPHONY_STATE_OFFHOOK])
- except Empty:
- ad.log.error("No onCallStateChangedIdle event received.")
- return False
- finally:
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
- return True
-
-
-def hangup_call(log, ad, is_emergency=False):
- """Hang up ongoing active call.
-
- Args:
- log: log object.
- ad: android device object.
-
- Returns:
- True: if all calls are cleared
- False: for errors
- """
- # short circuit in case no calls are active
- if not ad.droid.telecomIsInCall():
- ad.log.warning("No active call exists.")
- return True
- ad.ed.clear_events(EventCallStateChanged)
- ad.droid.telephonyStartTrackingCallState()
- ad.log.info("Hangup call.")
- if is_emergency:
- for call in ad.droid.telecomCallGetCallIds():
- ad.droid.telecomCallDisconnect(call)
- else:
- ad.droid.telecomEndCall()
-
- try:
- ad.ed.wait_for_event(
- EventCallStateChanged,
- is_event_match,
- timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
- field=CallStateContainer.CALL_STATE,
- value=TELEPHONY_STATE_IDLE)
- except Empty:
- ad.log.warning("Call state IDLE event is not received after hang up.")
- finally:
- ad.droid.telephonyStopTrackingCallStateChange()
- if not wait_for_state(ad.droid.telecomIsInCall, False, 15, 1):
- ad.log.error("Telecom is in call, hangup call failed.")
- return False
- return True
-
-
def wait_for_cbrs_data_active_sub_change_event(
ad,
event_tracking_started=False,
@@ -1487,12 +927,6 @@
ad.droid.telephonyStopTrackingDisplayInfoChange()
return -1
-def disconnect_call_by_id(log, ad, call_id):
- """Disconnect call by call id.
- """
- ad.droid.telecomCallDisconnect(call_id)
- return True
-
def _phone_number_remove_prefix(number):
"""Remove the country code and other prefix from the input phone number.
@@ -1563,89 +997,8 @@
return False
-def initiate_call(log,
- ad,
- callee_number,
- emergency=False,
- timeout=MAX_WAIT_TIME_CALL_INITIATION,
- checking_interval=5,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- video=False,
- voice_type_init=None,
- call_stats_check=False,
- result_info=result_dict,
- nw_gen_5g=False,
- nr_type= None):
- """Make phone call from caller to callee.
-
- Args:
- ad_caller: Caller android device object.
- callee_number: Callee phone number.
- emergency : specify the call is emergency.
- Optional. Default value is False.
- incall_ui_display: show the dialer UI foreground or backgroud
- video: whether to initiate as video call
-
- Returns:
- result: if phone call is placed successfully.
- """
- ad.ed.clear_events(EventCallStateChanged)
- sub_id = get_outgoing_voice_sub_id(ad)
- begin_time = get_device_epoch_time(ad)
- ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
- try:
- # Make a Call
- ad.log.info("Make a phone call to %s", callee_number)
- if emergency:
- ad.droid.telecomCallEmergencyNumber(callee_number)
- else:
- ad.droid.telecomCallNumber(callee_number, video)
-
- # Verify OFFHOOK state
- if not wait_for_call_offhook_for_subscription(
- log, ad, sub_id, event_tracking_started=True):
- ad.log.info("sub_id %s not in call offhook state", sub_id)
- last_call_drop_reason(ad, begin_time=begin_time)
- return False
- else:
- return True
-
- if call_stats_check:
- voice_type_in_call = ad.droid.telephonyGetCurrentVoiceNetworkType()
- phone_call_type = check_call_status(ad,
- voice_type_init,
- voice_type_in_call)
- result_info["Call Stats"] = phone_call_type
- ad.log.debug("Voice Call Type: %s", phone_call_type)
-
- finally:
- if hasattr(ad, "sdm_log") and getattr(ad, "sdm_log"):
- ad.adb.shell("i2cset -fy 3 64 6 1 b", ignore_status=True)
- ad.adb.shell("i2cset -fy 3 65 6 1 b", ignore_status=True)
- ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
-
- if nw_gen_5g:
- if not is_current_network_5g(ad, nr_type= nr_type):
- ad.log.error("Phone is not attached on 5G")
-
- if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
- ad.droid.telecomShowInCallScreen()
- elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
- ad.droid.showHomeScreen()
-
-
-def dial_phone_number(ad, callee_number):
- for number in str(callee_number):
- if number == "#":
- ad.send_keycode("POUND")
- elif number == "*":
- ad.send_keycode("STAR")
- elif number in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]:
- ad.send_keycode("%s" % number)
-
-
def get_call_state_by_adb(ad):
- slot_index_of_default_voice_subid = get_slot_index_from_subid(ad.log, ad,
+ slot_index_of_default_voice_subid = get_slot_index_from_subid(ad,
get_incoming_voice_sub_id(ad))
output = ad.adb.shell("dumpsys telephony.registry | grep mCallState")
if "mCallState" in output:
@@ -1672,78 +1025,6 @@
return re.search(r"mCallIncomingNumber=(.*)", output).group(1)
-def emergency_dialer_call_by_keyevent(ad, callee_number):
- for i in range(3):
- if "EmergencyDialer" in ad.get_my_current_focus_window():
- ad.log.info("EmergencyDialer is the current focus window")
- break
- elif i <= 2:
- ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
- time.sleep(1)
- else:
- ad.log.error("Unable to bring up EmergencyDialer")
- return False
- ad.log.info("Make a phone call to %s", callee_number)
- dial_phone_number(ad, callee_number)
- ad.send_keycode("CALL")
-
-
-def initiate_emergency_dialer_call_by_adb(
- log,
- ad,
- callee_number,
- timeout=MAX_WAIT_TIME_CALL_INITIATION,
- checking_interval=5):
- """Make emergency call by EmergencyDialer.
-
- Args:
- ad: Caller android device object.
- callee_number: Callee phone number.
- emergency : specify the call is emergency.
- Optional. Default value is False.
-
- Returns:
- result: if phone call is placed successfully.
- """
- try:
- # Make a Call
- ad.wakeup_screen()
- ad.send_keycode("MENU")
- ad.log.info("Call %s", callee_number)
- ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
- ad.adb.shell(
- "am start -a android.intent.action.CALL_EMERGENCY -d tel:%s" %
- callee_number)
- if not timeout: return True
- ad.log.info("Check call state")
- # Verify Call State
- elapsed_time = 0
- while elapsed_time < timeout:
- time.sleep(checking_interval)
- elapsed_time += checking_interval
- if check_call_state_connected_by_adb(ad):
- ad.log.info("Call to %s is connected", callee_number)
- return True
- if check_call_state_idle_by_adb(ad):
- ad.log.info("Call to %s failed", callee_number)
- return False
- ad.log.info("Make call to %s failed", callee_number)
- return False
- except Exception as e:
- ad.log.error("initiate emergency call failed with error %s", e)
-
-
-def hangup_call_by_adb(ad):
- """Make emergency call by EmergencyDialer.
-
- Args:
- ad: Caller android device object.
- callee_number: Callee phone number.
- """
- ad.log.info("End call by adb")
- ad.send_keycode("ENDCALL")
-
-
def dumpsys_all_call_info(ad):
""" Get call information by dumpsys telecom. """
output = ad.adb.shell("dumpsys telecom")
@@ -1767,49 +1048,6 @@
return calls_info
-def dumpsys_last_call_info(ad):
- """ Get call information by dumpsys telecom. """
- num = dumpsys_last_call_number(ad)
- output = ad.adb.shell("dumpsys telecom")
- result = re.search(r"Call TC@%s: {(.*?)}" % num, output, re.DOTALL)
- call_info = {"TC": num}
- if result:
- result = result.group(1)
- for attr in ("startTime", "endTime", "direction", "isInterrupted",
- "callTechnologies", "callTerminationsReason",
- "isVideoCall", "callProperties"):
- match = re.search(r"%s: (.*)" % attr, result)
- if match:
- if attr in ("startTime", "endTime"):
- call_info[attr] = epoch_to_log_line_timestamp(
- int(match.group(1)))
- else:
- call_info[attr] = match.group(1)
- ad.log.debug("call_info = %s", call_info)
- return call_info
-
-
-def dumpsys_last_call_number(ad):
- output = ad.adb.shell("dumpsys telecom")
- call_nums = re.findall("Call TC@(\d+):", output)
- if not call_nums:
- return 0
- else:
- return int(call_nums[-1])
-
-
-def dumpsys_new_call_info(ad, last_tc_number, retries=3, interval=5):
- for i in range(retries):
- if dumpsys_last_call_number(ad) > last_tc_number:
- call_info = dumpsys_last_call_info(ad)
- ad.log.info("New call info = %s", sorted(call_info.items()))
- return call_info
- else:
- time.sleep(interval)
- ad.log.error("New call is not in sysdump telecom")
- return {}
-
-
def dumpsys_carrier_config(ad):
output = ad.adb.shell("dumpsys carrier_config").split("\n")
output_phone_id_0 = []
@@ -1966,616 +1204,6 @@
return False
-def call_reject(log, ad_caller, ad_callee, reject=True):
- """Caller call Callee, then reject on callee.
-
-
- """
- subid_caller = ad_caller.droid.subscriptionGetDefaultVoiceSubId()
- subid_callee = ad_callee.incoming_voice_sub_id
- ad_caller.log.info("Sub-ID Caller %s, Sub-ID Callee %s", subid_caller,
- subid_callee)
- return call_reject_for_subscription(log, ad_caller, ad_callee,
- subid_caller, subid_callee, reject)
-
-
-def call_reject_for_subscription(log,
- ad_caller,
- ad_callee,
- subid_caller,
- subid_callee,
- reject=True):
- """
- """
-
- caller_number = ad_caller.telephony['subscription'][subid_caller][
- 'phone_num']
- callee_number = ad_callee.telephony['subscription'][subid_callee][
- 'phone_num']
-
- ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
- if not initiate_call(log, ad_caller, callee_number):
- ad_caller.log.error("Initiate call failed")
- return False
-
- if not wait_and_reject_call_for_subscription(
- log, ad_callee, subid_callee, caller_number, WAIT_TIME_REJECT_CALL,
- reject):
- ad_callee.log.error("Reject call fail.")
- return False
- # Check if incoming call is cleared on callee or not.
- if ad_callee.droid.telephonyGetCallStateForSubscription(
- subid_callee) == TELEPHONY_STATE_RINGING:
- ad_callee.log.error("Incoming call is not cleared")
- return False
- # Hangup on caller
- hangup_call(log, ad_caller)
- return True
-
-
-def call_reject_leave_message(log,
- ad_caller,
- ad_callee,
- verify_caller_func=None,
- wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
- """On default voice subscription, Call from caller to callee,
- reject on callee, caller leave a voice mail.
-
- 1. Caller call Callee.
- 2. Callee reject incoming call.
- 3. Caller leave a voice mail.
- 4. Verify callee received the voice mail notification.
-
- Args:
- ad_caller: caller android device object.
- ad_callee: callee android device object.
- verify_caller_func: function to verify caller is in correct state while in-call.
- This is optional, default is None.
- wait_time_in_call: time to wait when leaving a voice mail.
- This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
-
- Returns:
- True: if voice message is received on callee successfully.
- False: for errors
- """
- subid_caller = get_outgoing_voice_sub_id(ad_caller)
- subid_callee = get_incoming_voice_sub_id(ad_callee)
- return call_reject_leave_message_for_subscription(
- log, ad_caller, ad_callee, subid_caller, subid_callee,
- verify_caller_func, wait_time_in_call)
-
-
-def check_reject_needed_for_voice_mail(log, ad_callee):
- """Check if the carrier requires reject call to receive voice mail or just keep ringing
- Requested in b//155935290
- Four Japan carriers do not need to reject
- SBM, KDDI, Ntt Docomo, Rakuten
- Args:
- log: log object
- ad_callee: android device object
- Returns:
- True if callee's carrier is not one of the four Japan carriers
- False if callee's carrier is one of the four Japan carriers
- """
-
- operators_no_reject = [CARRIER_NTT_DOCOMO,
- CARRIER_KDDI,
- CARRIER_RAKUTEN,
- CARRIER_SBM]
- operator_name = get_operator_name(log, ad_callee)
-
- return operator_name not in operators_no_reject
-
-
-def call_reject_leave_message_for_subscription(
- log,
- ad_caller,
- ad_callee,
- subid_caller,
- subid_callee,
- verify_caller_func=None,
- wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
- """On specific voice subscription, Call from caller to callee,
- reject on callee, caller leave a voice mail.
-
- 1. Caller call Callee.
- 2. Callee reject incoming call.
- 3. Caller leave a voice mail.
- 4. Verify callee received the voice mail notification.
-
- Args:
- ad_caller: caller android device object.
- ad_callee: callee android device object.
- subid_caller: caller's subscription id.
- subid_callee: callee's subscription id.
- verify_caller_func: function to verify caller is in correct state while in-call.
- This is optional, default is None.
- wait_time_in_call: time to wait when leaving a voice mail.
- This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
-
- Returns:
- True: if voice message is received on callee successfully.
- False: for errors
- """
-
- # Currently this test utility only works for TMO and ATT and SPT.
- # It does not work for VZW (see b/21559800)
- # "with VVM TelephonyManager APIs won't work for vm"
-
- caller_number = ad_caller.telephony['subscription'][subid_caller][
- 'phone_num']
- callee_number = ad_callee.telephony['subscription'][subid_callee][
- 'phone_num']
-
- ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
-
- try:
- voice_mail_count_before = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
- subid_callee)
- ad_callee.log.info("voice mail count is %s", voice_mail_count_before)
- # -1 means there are unread voice mail, but the count is unknown
- # 0 means either this API not working (VZW) or no unread voice mail.
- if voice_mail_count_before != 0:
- log.warning("--Pending new Voice Mail, please clear on phone.--")
-
- if not initiate_call(log, ad_caller, callee_number):
- ad_caller.log.error("Initiate call failed.")
- return False
- if check_reject_needed_for_voice_mail(log, ad_callee):
- carrier_specific_delay_reject = 30
- else:
- carrier_specific_delay_reject = 2
- carrier_reject_call = not check_reject_needed_for_voice_mail(log, ad_callee)
-
- if not wait_and_reject_call_for_subscription(
- log, ad_callee, subid_callee, incoming_number=caller_number, delay_reject=carrier_specific_delay_reject,
- reject=carrier_reject_call):
- ad_callee.log.error("Reject call fail.")
- return False
-
- ad_callee.droid.telephonyStartTrackingVoiceMailStateChangeForSubscription(
- subid_callee)
-
- # ensure that all internal states are updated in telecom
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- ad_callee.ed.clear_events(EventCallStateChanged)
-
- if verify_caller_func and not verify_caller_func(log, ad_caller):
- ad_caller.log.error("Caller not in correct state!")
- return False
-
- # TODO: b/26293512 Need to play some sound to leave message.
- # Otherwise carrier voice mail server may drop this voice mail.
- time.sleep(wait_time_in_call)
-
- if not verify_caller_func:
- caller_state_result = ad_caller.droid.telecomIsInCall()
- else:
- caller_state_result = verify_caller_func(log, ad_caller)
- if not caller_state_result:
- ad_caller.log.error("Caller not in correct state after %s seconds",
- wait_time_in_call)
-
- if not hangup_call(log, ad_caller):
- ad_caller.log.error("Error in Hanging-Up Call")
- return False
-
- ad_callee.log.info("Wait for voice mail indicator on callee.")
- try:
- event = ad_callee.ed.wait_for_event(
- EventMessageWaitingIndicatorChanged,
- _is_on_message_waiting_event_true)
- ad_callee.log.info("Got event %s", event)
- except Empty:
- ad_callee.log.warning("No expected event %s",
- EventMessageWaitingIndicatorChanged)
- return False
- voice_mail_count_after = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
- subid_callee)
- ad_callee.log.info(
- "telephonyGetVoiceMailCount output - before: %s, after: %s",
- voice_mail_count_before, voice_mail_count_after)
-
- # voice_mail_count_after should:
- # either equals to (voice_mail_count_before + 1) [For ATT and SPT]
- # or equals to -1 [For TMO]
- # -1 means there are unread voice mail, but the count is unknown
- if not check_voice_mail_count(log, ad_callee, voice_mail_count_before,
- voice_mail_count_after):
- log.error("before and after voice mail count is not incorrect.")
- return False
- finally:
- ad_callee.droid.telephonyStopTrackingVoiceMailStateChangeForSubscription(
- subid_callee)
- return True
-
-
-def call_voicemail_erase_all_pending_voicemail(log, ad):
- """Script for phone to erase all pending voice mail.
- This script only works for TMO and ATT and SPT currently.
- This script only works if phone have already set up voice mail options,
- and phone should disable password protection for voice mail.
-
- 1. If phone don't have pending voice message, return True.
- 2. Dial voice mail number.
- For TMO, the number is '123'
- For ATT, the number is phone's number
- For SPT, the number is phone's number
- 3. Wait for voice mail connection setup.
- 4. Wait for voice mail play pending voice message.
- 5. Send DTMF to delete one message.
- The digit is '7'.
- 6. Repeat steps 4 and 5 until voice mail server drop this call.
- (No pending message)
- 6. Check telephonyGetVoiceMailCount result. it should be 0.
-
- Args:
- log: log object
- ad: android device object
- Returns:
- False if error happens. True is succeed.
- """
- log.info("Erase all pending voice mail.")
- count = ad.droid.telephonyGetVoiceMailCount()
- if count == 0:
- ad.log.info("No Pending voice mail.")
- return True
- if count == -1:
- ad.log.info("There is pending voice mail, but the count is unknown")
- count = MAX_SAVED_VOICE_MAIL
- else:
- ad.log.info("There are %s voicemails", count)
-
- voice_mail_number = get_voice_mail_number(log, ad)
- delete_digit = get_voice_mail_delete_digit(get_operator_name(log, ad))
- if not initiate_call(log, ad, voice_mail_number):
- log.error("Initiate call to voice mail failed.")
- return False
- time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
- callId = ad.droid.telecomCallGetCallIds()[0]
- time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
- while (is_phone_in_call(log, ad) and (count > 0)):
- ad.log.info("Press %s to delete voice mail.", delete_digit)
- ad.droid.telecomCallPlayDtmfTone(callId, delete_digit)
- ad.droid.telecomCallStopDtmfTone(callId)
- time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
- count -= 1
- if is_phone_in_call(log, ad):
- hangup_call(log, ad)
-
- # wait for telephonyGetVoiceMailCount to update correct result
- remaining_time = MAX_WAIT_TIME_VOICE_MAIL_COUNT
- while ((remaining_time > 0)
- and (ad.droid.telephonyGetVoiceMailCount() != 0)):
- time.sleep(1)
- remaining_time -= 1
- current_voice_mail_count = ad.droid.telephonyGetVoiceMailCount()
- ad.log.info("telephonyGetVoiceMailCount: %s", current_voice_mail_count)
- return (current_voice_mail_count == 0)
-
-
-def _is_on_message_waiting_event_true(event):
- """Private function to return if the received EventMessageWaitingIndicatorChanged
- event MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING field is True.
- """
- return event['data'][MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING]
-
-
-def call_setup_teardown(log,
- ad_caller,
- ad_callee,
- ad_hangup=None,
- verify_caller_func=None,
- verify_callee_func=None,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- dialing_number_length=None,
- video_state=None,
- slot_id_callee=None,
- voice_type_init=None,
- call_stats_check=False,
- result_info=result_dict,
- nsa_5g_for_stress=False,
- nr_type= None):
- """ Call process, including make a phone call from caller,
- accept from callee, and hang up. The call is on default voice subscription
-
- In call process, call from <droid_caller> to <droid_callee>,
- accept the call, (optional)then hang up from <droid_hangup>.
-
- Args:
- ad_caller: Caller Android Device Object.
- ad_callee: Callee Android Device Object.
- ad_hangup: Android Device Object end the phone call.
- Optional. Default value is None, and phone call will continue.
- verify_call_mode_caller: func_ptr to verify caller in correct mode
- Optional. Default is None
- verify_call_mode_caller: func_ptr to verify caller in correct mode
- Optional. Default is None
- incall_ui_display: after answer the call, bring in-call UI to foreground or
- background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
- dialing_number_length: the number of digits used for dialing
- slot_id_callee : the slot if of the callee to call to
-
- Returns:
- True if call process without any error.
- False if error happened.
-
- """
- subid_caller = get_outgoing_voice_sub_id(ad_caller)
- if slot_id_callee is None:
- subid_callee = get_incoming_voice_sub_id(ad_callee)
- else:
- subid_callee = get_subid_from_slot_index(log, ad_callee, slot_id_callee)
-
- return call_setup_teardown_for_subscription(
- log, ad_caller, ad_callee, subid_caller, subid_callee, ad_hangup,
- verify_caller_func, verify_callee_func, wait_time_in_call,
- incall_ui_display, dialing_number_length, video_state,
- voice_type_init, call_stats_check, result_info, nsa_5g_for_stress,
- nr_type)
-
-
-def call_setup_teardown_for_subscription(
- log,
- ad_caller,
- ad_callee,
- subid_caller,
- subid_callee,
- ad_hangup=None,
- verify_caller_func=None,
- verify_callee_func=None,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
- dialing_number_length=None,
- video_state=None,
- voice_type_init=None,
- call_stats_check=False,
- result_info=result_dict,
- nsa_5g_for_stress=False,
- nr_type= None):
- """ Call process, including make a phone call from caller,
- accept from callee, and hang up. The call is on specified subscription
-
- In call process, call from <droid_caller> to <droid_callee>,
- accept the call, (optional)then hang up from <droid_hangup>.
-
- Args:
- ad_caller: Caller Android Device Object.
- ad_callee: Callee Android Device Object.
- subid_caller: Caller subscription ID
- subid_callee: Callee subscription ID
- ad_hangup: Android Device Object end the phone call.
- Optional. Default value is None, and phone call will continue.
- verify_call_mode_caller: func_ptr to verify caller in correct mode
- Optional. Default is None
- verify_call_mode_caller: func_ptr to verify caller in correct mode
- Optional. Default is None
- incall_ui_display: after answer the call, bring in-call UI to foreground or
- background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
- if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
- if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
- else, do nothing.
-
- Returns:
- TelResultWrapper which will evaluate as False if error.
-
- """
- CHECK_INTERVAL = 5
- begin_time = get_current_epoch_time()
- if not verify_caller_func:
- verify_caller_func = is_phone_in_call
- if not verify_callee_func:
- verify_callee_func = is_phone_in_call
-
- caller_number = ad_caller.telephony['subscription'][subid_caller][
- 'phone_num']
- callee_number = ad_callee.telephony['subscription'][subid_callee][
- 'phone_num']
- if dialing_number_length:
- skip_test = False
- trunc_position = 0 - int(dialing_number_length)
- try:
- caller_area_code = caller_number[:trunc_position]
- callee_area_code = callee_number[:trunc_position]
- callee_dial_number = callee_number[trunc_position:]
- except:
- skip_test = True
- if caller_area_code != callee_area_code:
- skip_test = True
- if skip_test:
- msg = "Cannot make call from %s to %s by %s digits" % (
- caller_number, callee_number, dialing_number_length)
- ad_caller.log.info(msg)
- raise signals.TestSkip(msg)
- else:
- callee_number = callee_dial_number
-
- tel_result_wrapper = TelResultWrapper(CallResult('SUCCESS'))
- msg = "Call from %s to %s" % (caller_number, callee_number)
- if video_state:
- msg = "Video %s" % msg
- video = True
- else:
- video = False
- if ad_hangup:
- msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
- ad_caller.log.info(msg)
-
- for ad in (ad_caller, ad_callee):
- call_ids = ad.droid.telecomCallGetCallIds()
- setattr(ad, "call_ids", call_ids)
- if call_ids:
- ad.log.info("Pre-exist CallId %s before making call", call_ids)
- try:
- if not initiate_call(
- log,
- ad_caller,
- callee_number,
- incall_ui_display=incall_ui_display,
- video=video):
- ad_caller.log.error("Initiate call failed.")
- tel_result_wrapper.result_value = CallResult('INITIATE_FAILED')
- return tel_result_wrapper
- else:
- ad_caller.log.info("Caller initate call successfully")
- if not wait_and_answer_call_for_subscription(
- log,
- ad_callee,
- subid_callee,
- incoming_number=caller_number,
- caller=ad_caller,
- incall_ui_display=incall_ui_display,
- video_state=video_state):
- ad_callee.log.error("Answer call fail.")
- tel_result_wrapper.result_value = CallResult(
- 'NO_RING_EVENT_OR_ANSWER_FAILED')
- return tel_result_wrapper
- else:
- ad_callee.log.info("Callee answered the call successfully")
-
- for ad, call_func in zip([ad_caller, ad_callee],
- [verify_caller_func, verify_callee_func]):
- call_ids = ad.droid.telecomCallGetCallIds()
- new_call_ids = set(call_ids) - set(ad.call_ids)
- if not new_call_ids:
- ad.log.error(
- "No new call ids are found after call establishment")
- ad.log.error("telecomCallGetCallIds returns %s",
- ad.droid.telecomCallGetCallIds())
- tel_result_wrapper.result_value = CallResult('NO_CALL_ID_FOUND')
- for new_call_id in new_call_ids:
- if not wait_for_in_call_active(ad, call_id=new_call_id):
- tel_result_wrapper.result_value = CallResult(
- 'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
- else:
- ad.log.info("callProperties = %s",
- ad.droid.telecomCallGetProperties(new_call_id))
-
- if not ad.droid.telecomCallGetAudioState():
- ad.log.error("Audio is not in call state")
- tel_result_wrapper.result_value = CallResult(
- 'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
-
- if call_func(log, ad):
- ad.log.info("Call is in %s state", call_func.__name__)
- else:
- ad.log.error("Call is not in %s state, voice in RAT %s",
- call_func.__name__,
- ad.droid.telephonyGetCurrentVoiceNetworkType())
- tel_result_wrapper.result_value = CallResult(
- 'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
- if not tel_result_wrapper:
- return tel_result_wrapper
-
- if call_stats_check:
- voice_type_in_call = check_voice_network_type([ad_caller, ad_callee], voice_init=False)
- phone_a_call_type = check_call_status(ad_caller,
- voice_type_init[0],
- voice_type_in_call[0])
- result_info["Call Stats"] = phone_a_call_type
- ad_caller.log.debug("Voice Call Type: %s", phone_a_call_type)
- phone_b_call_type = check_call_status(ad_callee,
- voice_type_init[1],
- voice_type_in_call[1])
- result_info["Call Stats"] = phone_b_call_type
- ad_callee.log.debug("Voice Call Type: %s", phone_b_call_type)
-
- elapsed_time = 0
- while (elapsed_time < wait_time_in_call):
- CHECK_INTERVAL = min(CHECK_INTERVAL,
- wait_time_in_call - elapsed_time)
- time.sleep(CHECK_INTERVAL)
- elapsed_time += CHECK_INTERVAL
- time_message = "at <%s>/<%s> second." % (elapsed_time,
- wait_time_in_call)
- for ad, call_func in [(ad_caller, verify_caller_func),
- (ad_callee, verify_callee_func)]:
- if not call_func(log, ad):
- ad.log.error(
- "NOT in correct %s state at %s, voice in RAT %s",
- call_func.__name__, time_message,
- ad.droid.telephonyGetCurrentVoiceNetworkType())
- tel_result_wrapper.result_value = CallResult(
- 'CALL_DROP_OR_WRONG_STATE_AFTER_CONNECTED')
- else:
- ad.log.info("In correct %s state at %s",
- call_func.__name__, time_message)
- if not ad.droid.telecomCallGetAudioState():
- ad.log.error("Audio is not in call state at %s",
- time_message)
- tel_result_wrapper.result_value = CallResult(
- 'AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED')
- if not tel_result_wrapper:
- return tel_result_wrapper
-
- if ad_hangup:
- if not hangup_call(log, ad_hangup):
- ad_hangup.log.info("Failed to hang up the call")
- tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
- return tel_result_wrapper
- finally:
- if not tel_result_wrapper:
- for ad in (ad_caller, ad_callee):
- last_call_drop_reason(ad, begin_time)
- try:
- if ad.droid.telecomIsInCall():
- ad.log.info("In call. End now.")
- ad.droid.telecomEndCall()
- except Exception as e:
- log.error(str(e))
-
- if nsa_5g_for_stress:
- for ad in (ad_caller, ad_callee):
- if not is_current_network_5g(ad, nr_type):
- ad.log.error("Phone not attached on 5G")
-
- if ad_hangup or not tel_result_wrapper:
- for ad in (ad_caller, ad_callee):
- if not wait_for_call_id_clearing(
- ad, getattr(ad, "caller_ids", [])):
- tel_result_wrapper.result_value = CallResult(
- 'CALL_ID_CLEANUP_FAIL')
- return tel_result_wrapper
-
-
-def wait_for_call_id_clearing(ad,
- previous_ids,
- timeout=MAX_WAIT_TIME_CALL_DROP):
- while timeout > 0:
- new_call_ids = ad.droid.telecomCallGetCallIds()
- if len(new_call_ids) <= len(previous_ids):
- return True
- time.sleep(5)
- timeout = timeout - 5
- ad.log.error("Call id clearing failed. Before: %s; After: %s",
- previous_ids, new_call_ids)
- return False
-
-
-def last_call_drop_reason(ad, begin_time=None):
- reasons = ad.search_logcat(
- "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause", begin_time)
- reason_string = ""
- if reasons:
- log_msg = "Logcat call drop reasons:"
- for reason in reasons:
- log_msg = "%s\n\t%s" % (log_msg, reason["log_message"])
- if "ril reason str" in reason["log_message"]:
- reason_string = reason["log_message"].split(":")[-1].strip()
- ad.log.info(log_msg)
- reasons = ad.search_logcat("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION",
- begin_time)
- if reasons:
- ad.log.warning("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION is seen")
- ad.log.info("last call dumpsys: %s",
- sorted(dumpsys_last_call_info(ad).items()))
- return reason_string
-
-
def phone_number_formatter(input_string, formatter=None):
"""Get expected format of input phone number string.
@@ -2708,7 +1336,7 @@
return file_directory, file_name
-def _check_file_existance(ad, file_path, expected_file_size=None):
+def _check_file_existence(ad, file_path, expected_file_size=None):
"""Check file existance by file_path. If expected_file_size
is provided, then also check if the file meet the file size requirement.
"""
@@ -2736,132 +1364,6 @@
return False
-def check_curl_availability(ad):
- if not hasattr(ad, "curl_capable"):
- try:
- out = ad.adb.shell("/data/curl --version")
- if not out or "not found" in out:
- setattr(ad, "curl_capable", False)
- ad.log.info("curl is unavailable, use chrome to download file")
- else:
- setattr(ad, "curl_capable", True)
- except Exception:
- setattr(ad, "curl_capable", False)
- ad.log.info("curl is unavailable, use chrome to download file")
- return ad.curl_capable
-
-
-def start_youtube_video(ad, url="vnd.youtube:watch?v=pSJoP0LR8CQ"):
- ad.log.info("Open an youtube video")
- for _ in range(3):
- ad.ensure_screen_on()
- ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
- if wait_for_state(ad.droid.audioIsMusicActive, True, 15, 1):
- ad.log.info("Started a video in youtube, audio is in MUSIC state")
- return True
- ad.log.info("Audio is not in MUSIC state. Quit Youtube.")
- for _ in range(3):
- ad.send_keycode("BACK")
- time.sleep(1)
- time.sleep(3)
- return False
-
-
-def active_file_download_task(log, ad, file_name="5MB", method="curl"):
- # files available for download on the same website:
- # 1GB.zip, 512MB.zip, 200MB.zip, 50MB.zip, 20MB.zip, 10MB.zip, 5MB.zip
- # download file by adb command, as phone call will use sl4a
- file_size_map = {
- '1MB': 1000000,
- '5MB': 5000000,
- '10MB': 10000000,
- '20MB': 20000000,
- '50MB': 50000000,
- '100MB': 100000000,
- '200MB': 200000000,
- '512MB': 512000000
- }
- url_map = {
- "1MB": [
- "http://146.148.91.8/download/1MB.zip",
- "http://ipv4.download.thinkbroadband.com/1MB.zip"
- ],
- "5MB": [
- "http://146.148.91.8/download/5MB.zip",
- "http://212.183.159.230/5MB.zip",
- "http://ipv4.download.thinkbroadband.com/5MB.zip"
- ],
- "10MB": [
- "http://146.148.91.8/download/10MB.zip",
- "http://212.183.159.230/10MB.zip",
- "http://ipv4.download.thinkbroadband.com/10MB.zip",
- "http://lax.futurehosting.com/test.zip",
- "http://ovh.net/files/10Mio.dat"
- ],
- "20MB": [
- "http://146.148.91.8/download/20MB.zip",
- "http://212.183.159.230/20MB.zip",
- "http://ipv4.download.thinkbroadband.com/20MB.zip"
- ],
- "50MB": [
- "http://146.148.91.8/download/50MB.zip",
- "http://212.183.159.230/50MB.zip",
- "http://ipv4.download.thinkbroadband.com/50MB.zip"
- ],
- "100MB": [
- "http://146.148.91.8/download/100MB.zip",
- "http://212.183.159.230/100MB.zip",
- "http://ipv4.download.thinkbroadband.com/100MB.zip",
- "http://speedtest-ca.turnkeyinternet.net/100mb.bin",
- "http://ovh.net/files/100Mio.dat",
- "http://lax.futurehosting.com/test100.zip"
- ],
- "200MB": [
- "http://146.148.91.8/download/200MB.zip",
- "http://212.183.159.230/200MB.zip",
- "http://ipv4.download.thinkbroadband.com/200MB.zip"
- ],
- "512MB": [
- "http://146.148.91.8/download/512MB.zip",
- "http://212.183.159.230/512MB.zip",
- "http://ipv4.download.thinkbroadband.com/512MB.zip"
- ]
- }
-
- file_size = file_size_map.get(file_name)
- file_urls = url_map.get(file_name)
- file_url = None
- for url in file_urls:
- url_splits = url.split("/")
- if verify_http_connection(log, ad, url=url, retry=1):
- output_path = "/sdcard/Download/%s" % url_splits[-1]
- file_url = url
- break
- if not file_url:
- ad.log.error("No url is available to download %s", file_name)
- return False
- timeout = min(max(file_size / 100000, 600), 3600)
- if method == "sl4a":
- return (http_file_download_by_sl4a, (ad, file_url, output_path,
- file_size, True, timeout))
- if method == "curl" and check_curl_availability(ad):
- return (http_file_download_by_curl, (ad, file_url, output_path,
- file_size, True, timeout))
- elif method == "sl4a" or method == "curl":
- return (http_file_download_by_sl4a, (ad, file_url, output_path,
- file_size, True, timeout))
- else:
- return (http_file_download_by_chrome, (ad, file_url, file_size, True,
- timeout))
-
-
-def active_file_download_test(log, ad, file_name="5MB", method="sl4a"):
- task = active_file_download_task(log, ad, file_name, method=method)
- if not task:
- return False
- return task[0](*task[1])
-
-
def verify_internet_connection_by_ping(log,
ad,
retries=1,
@@ -2964,7 +1466,7 @@
log_file_path=log_file_path)
return True
result, data = ad.run_iperf_client(
- iperf_server, iperf_option, timeout=timeout + 60)
+ iperf_server, iperf_option, timeout=timeout + 120)
ad.log.info("iperf test result with server %s is %s", iperf_server,
result)
if result:
@@ -3008,7 +1510,8 @@
ipv6=False,
rate_dict=None,
blocking=True,
- log_file_path=None):
+ log_file_path=None,
+ retry=5):
"""Iperf test by adb using UDP.
Args:
@@ -3024,29 +1527,36 @@
rate_dict: dictionary that can be passed in to save data
blocking: run iperf in blocking mode if True
log_file_path: location to save logs
+ retry: times of retry when the server is unavailable
"""
iperf_option = "-u -i 1 -t %s -O %s -J" % (timeout, omit)
if limit_rate:
iperf_option += " -b %s" % limit_rate
if pacing_timer:
iperf_option += " --pacing-timer %s" % pacing_timer
- if port_num:
- iperf_option += " -p %s" % port_num
if ipv6:
iperf_option += " -6"
if reverse:
iperf_option += " -R"
- try:
- return iperf_test_with_options(log,
- ad,
- iperf_server,
- iperf_option,
- timeout,
- rate_dict,
- blocking,
- log_file_path)
- except AdbError:
- return False
+ for _ in range(retry):
+ if port_num:
+ iperf_option_final = iperf_option + " -p %s" % port_num
+ port_num += 1
+ else:
+ iperf_option_final = iperf_option
+ try:
+ return iperf_test_with_options(log,
+ ad,
+ iperf_server,
+ iperf_option_final,
+ timeout,
+ rate_dict,
+ blocking,
+ log_file_path)
+ except (AdbCommandError, TimeoutError) as error:
+ continue
+ except AdbError:
+ return False
def iperf_test_by_adb(log,
@@ -3060,7 +1570,8 @@
ipv6=False,
rate_dict=None,
blocking=True,
- log_file_path=None):
+ log_file_path=None,
+ retry=5):
"""Iperf test by adb using TCP.
Args:
@@ -3076,368 +1587,34 @@
rate_dict: dictionary that can be passed in to save data
blocking: run iperf in blocking mode if True
log_file_path: location to save logs
+ retry: times of retry when the server is unavailable
"""
iperf_option = "-t %s -O %s -J" % (timeout, omit)
if limit_rate:
iperf_option += " -b %s" % limit_rate
- if port_num:
- iperf_option += " -p %s" % port_num
if ipv6:
iperf_option += " -6"
if reverse:
iperf_option += " -R"
- try:
- return iperf_test_with_options(log,
- ad,
- iperf_server,
- iperf_option,
- timeout,
- rate_dict,
- blocking,
- log_file_path)
- except AdbError:
- return False
-
-
-def http_file_download_by_curl(ad,
- url,
- out_path=None,
- expected_file_size=None,
- remove_file_after_check=True,
- timeout=3600,
- limit_rate=None,
- retry=3):
- """Download http file by adb curl.
-
- Args:
- ad: Android Device Object.
- url: The url that file to be downloaded from".
- out_path: Optional. Where to download file to.
- out_path is /sdcard/Download/ by default.
- expected_file_size: Optional. Provided if checking the download file meet
- expected file size in unit of byte.
- remove_file_after_check: Whether to remove the downloaded file after
- check.
- timeout: timeout for file download to complete.
- limit_rate: download rate in bps. None, if do not apply rate limit.
- retry: the retry request times provided in curl command.
- """
- file_directory, file_name = _generate_file_directory_and_file_name(
- url, out_path)
- file_path = os.path.join(file_directory, file_name)
- curl_cmd = "/data/curl"
- if limit_rate:
- curl_cmd += " --limit-rate %s" % limit_rate
- if retry:
- curl_cmd += " --retry %s" % retry
- curl_cmd += " --url %s > %s" % (url, file_path)
- try:
- ad.log.info("Download %s to %s by adb shell command %s", url,
- file_path, curl_cmd)
-
- ad.adb.shell(curl_cmd, timeout=timeout)
- if _check_file_existance(ad, file_path, expected_file_size):
- ad.log.info("%s is downloaded to %s successfully", url, file_path)
- return True
+ for _ in range(retry):
+ if port_num:
+ iperf_option_final = iperf_option + " -p %s" % port_num
+ port_num += 1
else:
- ad.log.warning("Fail to download %s", url)
+ iperf_option_final = iperf_option
+ try:
+ return iperf_test_with_options(log,
+ ad,
+ iperf_server,
+ iperf_option_final,
+ timeout,
+ rate_dict=rate_dict,
+ blocking=blocking,
+ log_file_path=log_file_path)
+ except (AdbCommandError, TimeoutError) as error:
+ continue
+ except AdbError:
return False
- except Exception as e:
- ad.log.warning("Download %s failed with exception %s", url, e)
- return False
- finally:
- if remove_file_after_check:
- ad.log.info("Remove the downloaded file %s", file_path)
- ad.adb.shell("rm %s" % file_path, ignore_status=True)
-
-
-def open_url_by_adb(ad, url):
- ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
-
-
-def http_file_download_by_chrome(ad,
- url,
- expected_file_size=None,
- remove_file_after_check=True,
- timeout=3600):
- """Download http file by chrome.
-
- Args:
- ad: Android Device Object.
- url: The url that file to be downloaded from".
- expected_file_size: Optional. Provided if checking the download file meet
- expected file size in unit of byte.
- remove_file_after_check: Whether to remove the downloaded file after
- check.
- timeout: timeout for file download to complete.
- """
- chrome_apk = "com.android.chrome"
- file_directory, file_name = _generate_file_directory_and_file_name(
- url, "/sdcard/Download/")
- file_path = os.path.join(file_directory, file_name)
- # Remove pre-existing file
- ad.force_stop_apk(chrome_apk)
- file_to_be_delete = os.path.join(file_directory, "*%s*" % file_name)
- ad.adb.shell("rm -f %s" % file_to_be_delete)
- ad.adb.shell("rm -rf /sdcard/Download/.*")
- ad.adb.shell("rm -f /sdcard/Download/.*")
- data_accounting = {
- "total_rx_bytes": ad.droid.getTotalRxBytes(),
- "mobile_rx_bytes": ad.droid.getMobileRxBytes(),
- "subscriber_mobile_data_usage": get_mobile_data_usage(ad, None, None),
- "chrome_mobile_data_usage": get_mobile_data_usage(
- ad, None, chrome_apk)
- }
- ad.log.debug("Before downloading: %s", data_accounting)
- ad.log.info("Download %s with timeout %s", url, timeout)
- ad.ensure_screen_on()
- open_url_by_adb(ad, url)
- elapse_time = 0
- result = True
- while elapse_time < timeout:
- time.sleep(30)
- if _check_file_existance(ad, file_path, expected_file_size):
- ad.log.info("%s is downloaded successfully", url)
- if remove_file_after_check:
- ad.log.info("Remove the downloaded file %s", file_path)
- ad.adb.shell("rm -f %s" % file_to_be_delete)
- ad.adb.shell("rm -rf /sdcard/Download/.*")
- ad.adb.shell("rm -f /sdcard/Download/.*")
- #time.sleep(30)
- new_data_accounting = {
- "mobile_rx_bytes":
- ad.droid.getMobileRxBytes(),
- "subscriber_mobile_data_usage":
- get_mobile_data_usage(ad, None, None),
- "chrome_mobile_data_usage":
- get_mobile_data_usage(ad, None, chrome_apk)
- }
- ad.log.info("After downloading: %s", new_data_accounting)
- accounting_diff = {
- key: value - data_accounting[key]
- for key, value in new_data_accounting.items()
- }
- ad.log.debug("Data accounting difference: %s", accounting_diff)
- if getattr(ad, "on_mobile_data", False):
- for key, value in accounting_diff.items():
- if value < expected_file_size:
- ad.log.warning("%s diff is %s less than %s", key,
- value, expected_file_size)
- ad.data_accounting["%s_failure" % key] += 1
- else:
- for key, value in accounting_diff.items():
- if value >= expected_file_size:
- ad.log.error("%s diff is %s. File download is "
- "consuming mobile data", key, value)
- result = False
- return result
- elif _check_file_existance(ad, "%s.crdownload" % file_path):
- ad.log.info("Chrome is downloading %s", url)
- elif elapse_time < 60:
- # download not started, retry download wit chrome again
- open_url_by_adb(ad, url)
- else:
- ad.log.error("Unable to download file from %s", url)
- break
- elapse_time += 30
- ad.log.warning("Fail to download file from %s", url)
- ad.force_stop_apk("com.android.chrome")
- ad.adb.shell("rm -f %s" % file_to_be_delete)
- ad.adb.shell("rm -rf /sdcard/Download/.*")
- ad.adb.shell("rm -f /sdcard/Download/.*")
- return False
-
-
-def http_file_download_by_sl4a(ad,
- url,
- out_path=None,
- expected_file_size=None,
- remove_file_after_check=True,
- timeout=300):
- """Download http file by sl4a RPC call.
-
- Args:
- ad: Android Device Object.
- url: The url that file to be downloaded from".
- out_path: Optional. Where to download file to.
- out_path is /sdcard/Download/ by default.
- expected_file_size: Optional. Provided if checking the download file meet
- expected file size in unit of byte.
- remove_file_after_check: Whether to remove the downloaded file after
- check.
- timeout: timeout for file download to complete.
- """
- file_folder, file_name = _generate_file_directory_and_file_name(
- url, out_path)
- file_path = os.path.join(file_folder, file_name)
- ad.adb.shell("rm -f %s" % file_path)
- accounting_apk = SL4A_APK_NAME
- result = True
- try:
- if not getattr(ad, "data_droid", None):
- ad.data_droid, ad.data_ed = ad.get_droid()
- ad.data_ed.start()
- else:
- try:
- if not ad.data_droid.is_live:
- ad.data_droid, ad.data_ed = ad.get_droid()
- ad.data_ed.start()
- except Exception:
- ad.log.info("Start new sl4a session for file download")
- ad.data_droid, ad.data_ed = ad.get_droid()
- ad.data_ed.start()
- data_accounting = {
- "mobile_rx_bytes":
- ad.droid.getMobileRxBytes(),
- "subscriber_mobile_data_usage":
- get_mobile_data_usage(ad, None, None),
- "sl4a_mobile_data_usage":
- get_mobile_data_usage(ad, None, accounting_apk)
- }
- ad.log.debug("Before downloading: %s", data_accounting)
- ad.log.info("Download file from %s to %s by sl4a RPC call", url,
- file_path)
- try:
- ad.data_droid.httpDownloadFile(url, file_path, timeout=timeout)
- except Exception as e:
- ad.log.warning("SL4A file download error: %s", e)
- ad.data_droid.terminate()
- return False
- if _check_file_existance(ad, file_path, expected_file_size):
- ad.log.info("%s is downloaded successfully", url)
- new_data_accounting = {
- "mobile_rx_bytes":
- ad.droid.getMobileRxBytes(),
- "subscriber_mobile_data_usage":
- get_mobile_data_usage(ad, None, None),
- "sl4a_mobile_data_usage":
- get_mobile_data_usage(ad, None, accounting_apk)
- }
- ad.log.debug("After downloading: %s", new_data_accounting)
- accounting_diff = {
- key: value - data_accounting[key]
- for key, value in new_data_accounting.items()
- }
- ad.log.debug("Data accounting difference: %s", accounting_diff)
- if getattr(ad, "on_mobile_data", False):
- for key, value in accounting_diff.items():
- if value < expected_file_size:
- ad.log.debug("%s diff is %s less than %s", key,
- value, expected_file_size)
- ad.data_accounting["%s_failure"] += 1
- else:
- for key, value in accounting_diff.items():
- if value >= expected_file_size:
- ad.log.error("%s diff is %s. File download is "
- "consuming mobile data", key, value)
- result = False
- return result
- else:
- ad.log.warning("Fail to download %s", url)
- return False
- except Exception as e:
- ad.log.error("Download %s failed with exception %s", url, e)
- raise
- finally:
- if remove_file_after_check:
- ad.log.info("Remove the downloaded file %s", file_path)
- ad.adb.shell("rm %s" % file_path, ignore_status=True)
-
-
-def get_wifi_usage(ad, sid=None, apk=None):
- if not sid:
- sid = ad.droid.subscriptionGetDefaultDataSubId()
- current_time = int(time.time() * 1000)
- begin_time = current_time - 10 * 24 * 60 * 60 * 1000
- end_time = current_time + 10 * 24 * 60 * 60 * 1000
-
- if apk:
- uid = ad.get_apk_uid(apk)
- ad.log.debug("apk %s uid = %s", apk, uid)
- try:
- return ad.droid.connectivityQueryDetailsForUid(
- TYPE_WIFI,
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time, uid)
- except:
- return ad.droid.connectivityQueryDetailsForUid(
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time, uid)
- else:
- try:
- return ad.droid.connectivityQuerySummaryForDevice(
- TYPE_WIFI,
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time)
- except:
- return ad.droid.connectivityQuerySummaryForDevice(
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time)
-
-
-def get_mobile_data_usage(ad, sid=None, apk=None):
- if not sid:
- sid = ad.droid.subscriptionGetDefaultDataSubId()
- current_time = int(time.time() * 1000)
- begin_time = current_time - 10 * 24 * 60 * 60 * 1000
- end_time = current_time + 10 * 24 * 60 * 60 * 1000
-
- if apk:
- uid = ad.get_apk_uid(apk)
- ad.log.debug("apk %s uid = %s", apk, uid)
- try:
- usage_info = ad.droid.getMobileDataUsageInfoForUid(uid, sid)
- ad.log.debug("Mobile data usage info for uid %s = %s", uid,
- usage_info)
- return usage_info["UsageLevel"]
- except:
- try:
- return ad.droid.connectivityQueryDetailsForUid(
- TYPE_MOBILE,
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time, uid)
- except:
- return ad.droid.connectivityQueryDetailsForUid(
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time, uid)
- else:
- try:
- usage_info = ad.droid.getMobileDataUsageInfo(sid)
- ad.log.debug("Mobile data usage info = %s", usage_info)
- return usage_info["UsageLevel"]
- except:
- try:
- return ad.droid.connectivityQuerySummaryForDevice(
- TYPE_MOBILE,
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time)
- except:
- return ad.droid.connectivityQuerySummaryForDevice(
- ad.droid.telephonyGetSubscriberIdForSubscription(sid),
- begin_time, end_time)
-
-
-def set_mobile_data_usage_limit(ad, limit, subscriber_id=None):
- if not subscriber_id:
- subscriber_id = ad.droid.telephonyGetSubscriberId()
- ad.log.debug("Set subscriber mobile data usage limit to %s", limit)
- ad.droid.logV("Setting subscriber mobile data usage limit to %s" % limit)
- try:
- ad.droid.connectivitySetDataUsageLimit(subscriber_id, str(limit))
- except:
- ad.droid.connectivitySetDataUsageLimit(subscriber_id, limit)
-
-
-def remove_mobile_data_usage_limit(ad, subscriber_id=None):
- if not subscriber_id:
- subscriber_id = ad.droid.telephonyGetSubscriberId()
- ad.log.debug("Remove subscriber mobile data usage limit")
- ad.droid.logV(
- "Setting subscriber mobile data usage limit to -1, unlimited")
- try:
- ad.droid.connectivitySetDataUsageLimit(subscriber_id, "-1")
- except:
- ad.droid.connectivitySetDataUsageLimit(subscriber_id, -1)
def trigger_modem_crash(ad, timeout=120):
@@ -3593,276 +1770,6 @@
reboot_device(ad)
-def _connection_state_change(_event, target_state, connection_type):
- if connection_type:
- if 'TypeName' not in _event['data']:
- return False
- connection_type_string_in_event = _event['data']['TypeName']
- cur_type = connection_type_from_type_string(
- connection_type_string_in_event)
- if cur_type != connection_type:
- log.info(
- "_connection_state_change expect: %s, received: %s <type %s>",
- connection_type, connection_type_string_in_event, cur_type)
- return False
-
- if 'isConnected' in _event['data'] and _event['data']['isConnected'] == target_state:
- return True
- return False
-
-
-def wait_for_cell_data_connection(
- log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
- """Wait for data connection status to be expected value for default
- data subscription.
-
- Wait for the data connection status to be DATA_STATE_CONNECTED
- or DATA_STATE_DISCONNECTED.
-
- Args:
- log: Log object.
- ad: Android Device Object.
- state: Expected status: True or False.
- If True, it will wait for status to be DATA_STATE_CONNECTED.
- If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
- timeout_value: wait for cell data timeout value.
- This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-
- Returns:
- True if success.
- False if failed.
- """
- sub_id = get_default_data_sub_id(ad)
- return wait_for_cell_data_connection_for_subscription(
- log, ad, sub_id, state, timeout_value)
-
-
-def _is_data_connection_state_match(log, ad, expected_data_connection_state):
- return (expected_data_connection_state ==
- ad.droid.telephonyGetDataConnectionState())
-
-
-def _is_network_connected_state_match(log, ad,
- expected_network_connected_state):
- return (expected_network_connected_state ==
- ad.droid.connectivityNetworkIsConnected())
-
-
-def wait_for_cell_data_connection_for_subscription(
- log,
- ad,
- sub_id,
- state,
- timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
- """Wait for data connection status to be expected value for specified
- subscrption id.
-
- Wait for the data connection status to be DATA_STATE_CONNECTED
- or DATA_STATE_DISCONNECTED.
-
- Args:
- log: Log object.
- ad: Android Device Object.
- sub_id: subscription Id
- state: Expected status: True or False.
- If True, it will wait for status to be DATA_STATE_CONNECTED.
- If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
- timeout_value: wait for cell data timeout value.
- This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-
- Returns:
- True if success.
- False if failed.
- """
- state_str = {
- True: DATA_STATE_CONNECTED,
- False: DATA_STATE_DISCONNECTED
- }[state]
-
- data_state = ad.droid.telephonyGetDataConnectionState()
- if not state and ad.droid.telephonyGetDataConnectionState() == state_str:
- return True
-
- ad.ed.clear_events(EventDataConnectionStateChanged)
- ad.droid.telephonyStartTrackingDataConnectionStateChangeForSubscription(
- sub_id)
- ad.droid.connectivityStartTrackingConnectivityStateChange()
- try:
- ad.log.info("User data enabled for sub_id %s: %s", sub_id,
- ad.droid.telephonyIsDataEnabledForSubscription(sub_id))
- data_state = ad.droid.telephonyGetDataConnectionState()
- ad.log.info("Data connection state is %s", data_state)
- ad.log.info("Network is connected: %s",
- ad.droid.connectivityNetworkIsConnected())
- if data_state == state_str:
- return _wait_for_nw_data_connection(
- log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
-
- try:
- ad.ed.wait_for_event(
- EventDataConnectionStateChanged,
- is_event_match,
- timeout=timeout_value,
- field=DataConnectionStateContainer.DATA_CONNECTION_STATE,
- value=state_str)
- except Empty:
- ad.log.info("No expected event EventDataConnectionStateChanged %s",
- state_str)
-
- # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
- # data connection state.
- # Otherwise, the network state will not be correct.
- # The bug is tracked here: b/20921915
-
- # Previously we use _is_data_connection_state_match,
- # but telephonyGetDataConnectionState sometimes return wrong value.
- # The bug is tracked here: b/22612607
- # So we use _is_network_connected_state_match.
-
- if _wait_for_droid_in_state(log, ad, timeout_value,
- _is_network_connected_state_match, state):
- return _wait_for_nw_data_connection(
- log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
- else:
- return False
-
- finally:
- ad.droid.telephonyStopTrackingDataConnectionStateChangeForSubscription(
- sub_id)
-
-
-def wait_for_wifi_data_connection(
- log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
- """Wait for data connection status to be expected value and connection is by WiFi.
-
- Args:
- log: Log object.
- ad: Android Device Object.
- state: Expected status: True or False.
- If True, it will wait for status to be DATA_STATE_CONNECTED.
- If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
- timeout_value: wait for network data timeout value.
- This is optional, default value is MAX_WAIT_TIME_NW_SELECTION
-
- Returns:
- True if success.
- False if failed.
- """
- ad.log.info("wait_for_wifi_data_connection")
- return _wait_for_nw_data_connection(
- log, ad, state, NETWORK_CONNECTION_TYPE_WIFI, timeout_value)
-
-
-def wait_for_data_connection(
- log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
- """Wait for data connection status to be expected value.
-
- Wait for the data connection status to be DATA_STATE_CONNECTED
- or DATA_STATE_DISCONNECTED.
-
- Args:
- log: Log object.
- ad: Android Device Object.
- state: Expected status: True or False.
- If True, it will wait for status to be DATA_STATE_CONNECTED.
- If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
- timeout_value: wait for network data timeout value.
- This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-
- Returns:
- True if success.
- False if failed.
- """
- return _wait_for_nw_data_connection(log, ad, state, None, timeout_value)
-
-
-def _wait_for_nw_data_connection(
- log,
- ad,
- is_connected,
- connection_type=None,
- timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
- """Wait for data connection status to be expected value.
-
- Wait for the data connection status to be DATA_STATE_CONNECTED
- or DATA_STATE_DISCONNECTED.
-
- Args:
- log: Log object.
- ad: Android Device Object.
- is_connected: Expected connection status: True or False.
- If True, it will wait for status to be DATA_STATE_CONNECTED.
- If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
- connection_type: expected connection type.
- This is optional, if it is None, then any connection type will return True.
- timeout_value: wait for network data timeout value.
- This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
-
- Returns:
- True if success.
- False if failed.
- """
- ad.ed.clear_events(EventConnectivityChanged)
- ad.droid.connectivityStartTrackingConnectivityStateChange()
- try:
- cur_data_connection_state = ad.droid.connectivityNetworkIsConnected()
- if is_connected == cur_data_connection_state:
- current_type = get_internet_connection_type(log, ad)
- ad.log.info("current data connection type: %s", current_type)
- if not connection_type:
- return True
- else:
- if not is_connected and current_type != connection_type:
- ad.log.info("data connection not on %s!", connection_type)
- return True
- elif is_connected and current_type == connection_type:
- ad.log.info("data connection on %s as expected",
- connection_type)
- return True
- else:
- ad.log.info("current data connection state: %s target: %s",
- cur_data_connection_state, is_connected)
-
- try:
- event = ad.ed.wait_for_event(
- EventConnectivityChanged, _connection_state_change,
- timeout_value, is_connected, connection_type)
- ad.log.info("Got event: %s", event)
- except Empty:
- pass
-
- log.info(
- "_wait_for_nw_data_connection: check connection after wait event.")
- # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
- # data connection state.
- # Otherwise, the network state will not be correct.
- # The bug is tracked here: b/20921915
- if _wait_for_droid_in_state(log, ad, timeout_value,
- _is_network_connected_state_match,
- is_connected):
- current_type = get_internet_connection_type(log, ad)
- ad.log.info("current data connection type: %s", current_type)
- if not connection_type:
- return True
- else:
- if not is_connected and current_type != connection_type:
- ad.log.info("data connection not on %s", connection_type)
- return True
- elif is_connected and current_type == connection_type:
- ad.log.info("after event wait, data connection on %s",
- connection_type)
- return True
- else:
- return False
- else:
- return False
- except Exception as e:
- ad.log.error("Exception error %s", str(e))
- return False
- finally:
- ad.droid.connectivityStopTrackingConnectivityStateChange()
-
-
def get_cell_data_roaming_state_by_adb(ad):
"""Get Cell Data Roaming state. True for enabled, False for disabled"""
state_mapping = {"1": True, "0": False}
@@ -4028,125 +1935,6 @@
return False
-def is_phone_in_call(log, ad):
- """Return True if phone in call.
-
- Args:
- log: log object.
- ad: android device.
- """
- try:
- return ad.droid.telecomIsInCall()
- except:
- return "mCallState=2" in ad.adb.shell(
- "dumpsys telephony.registry | grep mCallState")
-
-
-def is_phone_not_in_call(log, ad):
- """Return True if phone not in call.
-
- Args:
- log: log object.
- ad: android device.
- """
- in_call = ad.droid.telecomIsInCall()
- call_state = ad.droid.telephonyGetCallState()
- if in_call:
- ad.log.info("Device is In Call")
- if call_state != TELEPHONY_STATE_IDLE:
- ad.log.info("Call_state is %s, not %s", call_state,
- TELEPHONY_STATE_IDLE)
- return ((not in_call) and (call_state == TELEPHONY_STATE_IDLE))
-
-
-def wait_for_droid_in_call(log, ad, max_time):
- """Wait for android to be in call state.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- If phone become in call state within max_time, return True.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(log, ad, max_time, is_phone_in_call)
-
-
-def is_phone_in_call_active(ad, call_id=None):
- """Return True if phone in active call.
-
- Args:
- log: log object.
- ad: android device.
- call_id: the call id
- """
- if ad.droid.telecomIsInCall():
- if not call_id:
- call_id = ad.droid.telecomCallGetCallIds()[0]
- call_state = ad.droid.telecomCallGetCallState(call_id)
- ad.log.info("%s state is %s", call_id, call_state)
- return call_state == "ACTIVE"
- else:
- ad.log.info("Not in telecomIsInCall")
- return False
-
-
-def wait_for_in_call_active(ad,
- timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
- interval=WAIT_TIME_BETWEEN_STATE_CHECK,
- call_id=None):
- """Wait for call reach active state.
-
- Args:
- log: log object.
- ad: android device.
- call_id: the call id
- """
- if not call_id:
- call_id = ad.droid.telecomCallGetCallIds()[0]
- args = [ad, call_id]
- if not wait_for_state(is_phone_in_call_active, True, timeout, interval,
- *args):
- ad.log.error("Call did not reach ACTIVE state")
- return False
- else:
- return True
-
-
-def wait_for_telecom_ringing(log, ad, max_time=MAX_WAIT_TIME_TELECOM_RINGING):
- """Wait for android to be in telecom ringing state.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time. This is optional.
- Default Value is MAX_WAIT_TIME_TELECOM_RINGING.
-
- Returns:
- If phone become in telecom ringing state within max_time, return True.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(
- log, ad, max_time, lambda log, ad: ad.droid.telecomIsRinging())
-
-
-def wait_for_droid_not_in_call(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP):
- """Wait for android to be not in call state.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- If phone become not in call state within max_time, return True.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(log, ad, max_time, is_phone_not_in_call)
-
-
def _is_attached(log, ad, voice_or_data):
return _is_attached_for_subscription(
log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
@@ -4164,48 +1952,6 @@
log, ad, ad.droid.subscriptionGetDefaultSubId(), NETWORK_SERVICE_VOICE)
-def wait_for_voice_attach(log, ad, max_time=MAX_WAIT_TIME_NW_SELECTION):
- """Wait for android device to attach on voice.
-
- Args:
- log: log object.
- ad: android device.
- max_time: maximal wait time.
-
- Returns:
- Return True if device attach voice within max_time.
- Return False if timeout.
- """
- return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
- NETWORK_SERVICE_VOICE)
-
-
-def wait_for_voice_attach_for_subscription(
- log, ad, sub_id, max_time=MAX_WAIT_TIME_NW_SELECTION):
- """Wait for android device to attach on voice in subscription id.
-
- Args:
- log: log object.
- ad: android device.
- sub_id: subscription id.
- max_time: maximal wait time.
-
- Returns:
- Return True if device attach voice within max_time.
- Return False if timeout.
- """
- if not _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_time, _is_attached_for_subscription,
- NETWORK_SERVICE_VOICE):
- return False
-
- # TODO: b/26295983 if pone attach to 1xrtt from unknown, phone may not
- # receive incoming call immediately.
- if ad.droid.telephonyGetCurrentVoiceNetworkType() == RAT_1XRTT:
- time.sleep(WAIT_TIME_1XRTT_VOICE_ATTACH)
- return True
-
-
def wait_for_data_attach(log, ad, max_time):
"""Wait for android device to attach on data.
@@ -4356,356 +2102,6 @@
return model
-def ensure_preferred_network_type_for_subscription(
- ad,
- network_preference
- ):
- sub_id = ad.droid.subscriptionGetDefaultSubId()
- if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
- network_preference, sub_id):
- ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
- sub_id, network_preference)
- return True
-
-
-def ensure_network_rat(log,
- ad,
- network_preference,
- rat_family,
- voice_or_data=None,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- toggle_apm_after_setting=False):
- """Ensure ad's current network is in expected rat_family.
- """
- return ensure_network_rat_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
- rat_family, voice_or_data, max_wait_time, toggle_apm_after_setting)
-
-
-def ensure_network_rat_for_subscription(
- log,
- ad,
- sub_id,
- network_preference,
- rat_family,
- voice_or_data=None,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- toggle_apm_after_setting=False):
- """Ensure ad's current network is in expected rat_family.
- """
- if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
- network_preference, sub_id):
- ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
- sub_id, network_preference)
- return False
- if is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family,
- voice_or_data):
- ad.log.info("Sub_id %s in RAT %s for %s", sub_id, rat_family,
- voice_or_data)
- return True
-
- if toggle_apm_after_setting:
- toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- toggle_airplane_mode(log, ad, new_state=None, strict_checking=False)
-
- result = wait_for_network_rat_for_subscription(
- log, ad, sub_id, rat_family, max_wait_time, voice_or_data)
-
- log.info(
- "End of ensure_network_rat_for_subscription for %s. "
- "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
- "data: %s(family: %s)", ad.serial, network_preference, rat_family,
- voice_or_data,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
- rat_family_from_rat(
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
- sub_id)),
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
- rat_family_from_rat(
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
- sub_id)))
- return result
-
-
-def ensure_network_preference(log,
- ad,
- network_preference,
- voice_or_data=None,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- toggle_apm_after_setting=False):
- """Ensure that current rat is within the device's preferred network rats.
- """
- return ensure_network_preference_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
- voice_or_data, max_wait_time, toggle_apm_after_setting)
-
-
-def ensure_network_preference_for_subscription(
- log,
- ad,
- sub_id,
- network_preference,
- voice_or_data=None,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- toggle_apm_after_setting=False):
- """Ensure ad's network preference is <network_preference> for sub_id.
- """
- rat_family_list = rat_families_for_network_preference(network_preference)
- if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
- network_preference, sub_id):
- log.error("Set Preferred Networks failed.")
- return False
- if is_droid_in_rat_family_list_for_subscription(
- log, ad, sub_id, rat_family_list, voice_or_data):
- return True
-
- if toggle_apm_after_setting:
- toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
-
- result = wait_for_preferred_network_for_subscription(
- log, ad, sub_id, network_preference, max_wait_time, voice_or_data)
-
- ad.log.info(
- "End of ensure_network_preference_for_subscription. "
- "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
- "data: %s(family: %s)", network_preference, rat_family_list,
- voice_or_data,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
- rat_family_from_rat(
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
- sub_id)),
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
- rat_family_from_rat(
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
- sub_id)))
- return result
-
-
-def ensure_network_generation(log,
- ad,
- generation,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None,
- toggle_apm_after_setting=False,
- nr_type=None):
- """Ensure ad's network is <network generation> for default subscription ID.
-
- Set preferred network generation to <generation>.
- Toggle ON/OFF airplane mode if necessary.
- Wait for ad in expected network type.
- """
- return ensure_network_generation_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
- max_wait_time, voice_or_data, toggle_apm_after_setting, nr_type=nr_type)
-
-
-def ensure_network_generation_for_subscription(
- log,
- ad,
- sub_id,
- generation,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None,
- toggle_apm_after_setting=False,
- nr_type=None):
- """Ensure ad's network is <network generation> for specified subscription ID.
-
- Set preferred network generation to <generation>.
- Toggle ON/OFF airplane mode if necessary.
- Wait for ad in expected network type.
-
- Args:
- log: log object.
- ad: android device object.
- sub_id: subscription id.
- generation: network generation, e.g. GEN_2G, GEN_3G, GEN_4G, GEN_5G.
- max_wait_time: the time to wait for NW selection.
- voice_or_data: check voice network generation or data network generation
- This parameter is optional. If voice_or_data is None, then if
- either voice or data in expected generation, function will return True.
- toggle_apm_after_setting: Cycle airplane mode if True, otherwise do nothing.
-
- Returns:
- True if success, False if fail.
- """
- ad.log.info(
- "RAT network type voice: %s, data: %s",
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id))
-
- try:
- ad.log.info("Finding the network preference for generation %s for "
- "operator %s phone type %s", generation,
- ad.telephony["subscription"][sub_id]["operator"],
- ad.telephony["subscription"][sub_id]["phone_type"])
- network_preference = network_preference_for_generation(
- generation, ad.telephony["subscription"][sub_id]["operator"],
- ad.telephony["subscription"][sub_id]["phone_type"])
- if ad.telephony["subscription"][sub_id]["operator"] == CARRIER_FRE \
- and generation == GEN_4G:
- network_preference = NETWORK_MODE_LTE_ONLY
- ad.log.info("Network preference for %s is %s", generation,
- network_preference)
- rat_family = rat_family_for_generation(
- generation, ad.telephony["subscription"][sub_id]["operator"],
- ad.telephony["subscription"][sub_id]["phone_type"])
- except KeyError as e:
- ad.log.error("Failed to find a rat_family entry for generation %s"
- " for subscriber id %s with error %s", generation,
- sub_id, e)
- return False
-
- if not set_preferred_network_mode_pref(log, ad, sub_id,
- network_preference):
- return False
-
- if hasattr(ad, "dsds") and voice_or_data == "data" and sub_id != get_default_data_sub_id(ad):
- ad.log.info("MSIM - Non DDS, ignore data RAT")
- return True
-
- if (generation == GEN_5G) or (generation == RAT_5G):
- if is_current_network_5g_for_subscription(ad, sub_id=sub_id,
- nr_type=nr_type):
- ad.log.info("Current network type is 5G.")
- return True
- else:
- ad.log.error("Not in 5G coverage for Sub %s.", sub_id)
- return False
-
- if is_droid_in_network_generation_for_subscription(
- log, ad, sub_id, generation, voice_or_data):
- return True
-
- if toggle_apm_after_setting:
- toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
-
- result = wait_for_network_generation_for_subscription(
- log, ad, sub_id, generation, max_wait_time, voice_or_data)
-
- ad.log.info(
- "Ensure network %s %s %s. With network preference %s, "
- "current: voice: %s(family: %s), data: %s(family: %s)", generation,
- voice_or_data, result, network_preference,
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
- rat_generation_from_rat(
- ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
- sub_id)),
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
- rat_generation_from_rat(
- ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
- sub_id)))
- if not result:
- get_telephony_signal_strength(ad)
- return result
-
-
-def wait_for_network_rat(log,
- ad,
- rat_family,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- return wait_for_network_rat_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
- max_wait_time, voice_or_data)
-
-
-def wait_for_network_rat_for_subscription(
- log,
- ad,
- sub_id,
- rat_family,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- return _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_wait_time,
- is_droid_in_rat_family_for_subscription, rat_family, voice_or_data)
-
-
-def wait_for_not_network_rat(log,
- ad,
- rat_family,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- return wait_for_not_network_rat_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
- max_wait_time, voice_or_data)
-
-
-def wait_for_not_network_rat_for_subscription(
- log,
- ad,
- sub_id,
- rat_family,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- return _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_wait_time,
- lambda log, ad, sub_id, *args, **kwargs: not is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family, voice_or_data)
- )
-
-
-def wait_for_preferred_network(log,
- ad,
- network_preference,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- return wait_for_preferred_network_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
- max_wait_time, voice_or_data)
-
-
-def wait_for_preferred_network_for_subscription(
- log,
- ad,
- sub_id,
- network_preference,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- rat_family_list = rat_families_for_network_preference(network_preference)
- return _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_wait_time,
- is_droid_in_rat_family_list_for_subscription, rat_family_list,
- voice_or_data)
-
-
-def wait_for_network_generation(log,
- ad,
- generation,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None):
- return wait_for_network_generation_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
- max_wait_time, voice_or_data)
-
-
-def wait_for_network_generation_for_subscription(
- log,
- ad,
- sub_id,
- generation,
- max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
- voice_or_data=None,
- nr_type=None):
-
- if generation == GEN_5G:
- if is_current_network_5g_for_subscription(ad, sub_id=sub_id, nr_type=nr_type):
- ad.log.info("Current network type is 5G.")
- return True
- else:
- ad.log.error("Not in 5G coverage for Sub %s.", sub_id)
- return False
-
- return _wait_for_droid_in_state_for_subscription(
- log, ad, sub_id, max_wait_time,
- is_droid_in_network_generation_for_subscription, generation,
- voice_or_data)
-
-
def is_droid_in_rat_family(log, ad, rat_family, voice_or_data=None):
return is_droid_in_rat_family_for_subscription(
log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
@@ -4898,324 +2294,6 @@
return voice_mail_number
-def ensure_phones_idle(log, ads, max_time=MAX_WAIT_TIME_CALL_DROP):
- """Ensure ads idle (not in call).
- """
- result = True
- for ad in ads:
- if not ensure_phone_idle(log, ad, max_time=max_time):
- result = False
- return result
-
-
-def ensure_phone_idle(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP, retry=2):
- """Ensure ad idle (not in call).
- """
- while ad.droid.telecomIsInCall() and retry > 0:
- ad.droid.telecomEndCall()
- time.sleep(3)
- retry -= 1
- if not wait_for_droid_not_in_call(log, ad, max_time=max_time):
- ad.log.error("Failed to end call")
- return False
- return True
-
-
-def ensure_phone_subscription(log, ad):
- """Ensure Phone Subscription.
- """
- #check for sim and service
- duration = 0
- while duration < MAX_WAIT_TIME_NW_SELECTION:
- subInfo = ad.droid.subscriptionGetAllSubInfoList()
- if subInfo and len(subInfo) >= 1:
- ad.log.debug("Find valid subcription %s", subInfo)
- break
- else:
- ad.log.info("Did not find any subscription")
- time.sleep(5)
- duration += 5
- else:
- ad.log.error("Unable to find a valid subscription!")
- return False
- while duration < MAX_WAIT_TIME_NW_SELECTION:
- data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
- voice_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
- if data_sub_id > INVALID_SUB_ID or voice_sub_id > INVALID_SUB_ID:
- ad.log.debug("Find valid voice or data sub id")
- break
- else:
- ad.log.info("Did not find valid data or voice sub id")
- time.sleep(5)
- duration += 5
- else:
- ad.log.error("Unable to find valid data or voice sub id")
- return False
- while duration < MAX_WAIT_TIME_NW_SELECTION:
- data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
- if data_sub_id > INVALID_SUB_ID:
- data_rat = get_network_rat_for_subscription(
- log, ad, data_sub_id, NETWORK_SERVICE_DATA)
- else:
- data_rat = RAT_UNKNOWN
- if voice_sub_id > INVALID_SUB_ID:
- voice_rat = get_network_rat_for_subscription(
- log, ad, voice_sub_id, NETWORK_SERVICE_VOICE)
- else:
- voice_rat = RAT_UNKNOWN
- if data_rat != RAT_UNKNOWN or voice_rat != RAT_UNKNOWN:
- ad.log.info("Data sub_id %s in %s, voice sub_id %s in %s",
- data_sub_id, data_rat, voice_sub_id, voice_rat)
- return True
- else:
- ad.log.info("Did not attach for data or voice service")
- time.sleep(5)
- duration += 5
- else:
- ad.log.error("Did not attach for voice or data service")
- return False
-
-
-def ensure_phone_default_state(log, ad, check_subscription=True, retry=2):
- """Ensure ad in default state.
- Phone not in call.
- Phone have no stored WiFi network and WiFi disconnected.
- Phone not in airplane mode.
- """
- result = True
- if not toggle_airplane_mode(log, ad, False, False):
- ad.log.error("Fail to turn off airplane mode")
- result = False
- try:
- set_wifi_to_default(log, ad)
- while ad.droid.telecomIsInCall() and retry > 0:
- ad.droid.telecomEndCall()
- time.sleep(3)
- retry -= 1
- if not wait_for_droid_not_in_call(log, ad):
- ad.log.error("Failed to end call")
- #ad.droid.telephonyFactoryReset()
- data_roaming = getattr(ad, 'roaming', False)
- if get_cell_data_roaming_state_by_adb(ad) != data_roaming:
- set_cell_data_roaming_state_by_adb(ad, data_roaming)
- #remove_mobile_data_usage_limit(ad)
- if not wait_for_not_network_rat(
- log, ad, RAT_FAMILY_WLAN, voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("%s still in %s", NETWORK_SERVICE_DATA,
- RAT_FAMILY_WLAN)
- result = False
-
- if check_subscription and not ensure_phone_subscription(log, ad):
- ad.log.error("Unable to find a valid subscription!")
- result = False
- except Exception as e:
- ad.log.error("%s failure, toggle APM instead", e)
- toggle_airplane_mode_by_adb(log, ad, True)
- toggle_airplane_mode_by_adb(log, ad, False)
- ad.send_keycode("ENDCALL")
- ad.adb.shell("settings put global wfc_ims_enabled 0")
- ad.adb.shell("settings put global mobile_data 1")
-
- return result
-
-
-def ensure_phones_default_state(log, ads, check_subscription=True):
- """Ensure ads in default state.
- Phone not in call.
- Phone have no stored WiFi network and WiFi disconnected.
- Phone not in airplane mode.
-
- Returns:
- True if all steps of restoring default state succeed.
- False if any of the steps to restore default state fails.
- """
- tasks = []
- for ad in ads:
- tasks.append((ensure_phone_default_state, (log, ad,
- check_subscription)))
- if not multithread_func(log, tasks):
- log.error("Ensure_phones_default_state Fail.")
- return False
- return True
-
-
-def check_is_wifi_connected(log, ad, wifi_ssid):
- """Check if ad is connected to wifi wifi_ssid.
-
- Args:
- log: Log object.
- ad: Android device object.
- wifi_ssid: WiFi network SSID.
-
- Returns:
- True if wifi is connected to wifi_ssid
- False if wifi is not connected to wifi_ssid
- """
- wifi_info = ad.droid.wifiGetConnectionInfo()
- if wifi_info["supplicant_state"] == "completed" and wifi_info["SSID"] == wifi_ssid:
- ad.log.info("Wifi is connected to %s", wifi_ssid)
- ad.on_mobile_data = False
- return True
- else:
- ad.log.info("Wifi is not connected to %s", wifi_ssid)
- ad.log.debug("Wifi connection_info=%s", wifi_info)
- ad.on_mobile_data = True
- return False
-
-
-def ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd=None, retries=3, apm=False):
- """Ensure ad connected to wifi on network wifi_ssid.
-
- Args:
- log: Log object.
- ad: Android device object.
- wifi_ssid: WiFi network SSID.
- wifi_pwd: optional secure network password.
- retries: the number of retries.
-
- Returns:
- True if wifi is connected to wifi_ssid
- False if wifi is not connected to wifi_ssid
- """
- if not toggle_airplane_mode(log, ad, apm, strict_checking=False):
- return False
-
- network = {WIFI_SSID_KEY: wifi_ssid}
- if wifi_pwd:
- network[WIFI_PWD_KEY] = wifi_pwd
- for i in range(retries):
- if not ad.droid.wifiCheckState():
- ad.log.info("Wifi state is down. Turn on Wifi")
- ad.droid.wifiToggleState(True)
- if check_is_wifi_connected(log, ad, wifi_ssid):
- ad.log.info("Wifi is connected to %s", wifi_ssid)
- return verify_internet_connection(log, ad, retries=3)
- else:
- ad.log.info("Connecting to wifi %s", wifi_ssid)
- try:
- ad.droid.wifiConnectByConfig(network)
- except Exception:
- ad.log.info("Connecting to wifi by wifiConnect instead")
- ad.droid.wifiConnect(network)
- time.sleep(20)
- if check_is_wifi_connected(log, ad, wifi_ssid):
- ad.log.info("Connected to Wifi %s", wifi_ssid)
- return verify_internet_connection(log, ad, retries=3)
- ad.log.info("Fail to connected to wifi %s", wifi_ssid)
- return False
-
-
-def forget_all_wifi_networks(log, ad):
- """Forget all stored wifi network information
-
- Args:
- log: log object
- ad: AndroidDevice object
-
- Returns:
- boolean success (True) or failure (False)
- """
- if not ad.droid.wifiGetConfiguredNetworks():
- ad.on_mobile_data = True
- return True
- try:
- old_state = ad.droid.wifiCheckState()
- wifi_test_utils.reset_wifi(ad)
- wifi_toggle_state(log, ad, old_state)
- except Exception as e:
- log.error("forget_all_wifi_networks with exception: %s", e)
- return False
- ad.on_mobile_data = True
- return True
-
-
-def wifi_reset(log, ad, disable_wifi=True):
- """Forget all stored wifi networks and (optionally) disable WiFi
-
- Args:
- log: log object
- ad: AndroidDevice object
- disable_wifi: boolean to disable wifi, defaults to True
- Returns:
- boolean success (True) or failure (False)
- """
- if not forget_all_wifi_networks(log, ad):
- ad.log.error("Unable to forget all networks")
- return False
- if not wifi_toggle_state(log, ad, not disable_wifi):
- ad.log.error("Failed to toggle WiFi state to %s!", not disable_wifi)
- return False
- return True
-
-
-def set_wifi_to_default(log, ad):
- """Set wifi to default state (Wifi disabled and no configured network)
-
- Args:
- log: log object
- ad: AndroidDevice object
-
- Returns:
- boolean success (True) or failure (False)
- """
- ad.droid.wifiFactoryReset()
- ad.droid.wifiToggleState(False)
- ad.on_mobile_data = True
-
-
-def wifi_toggle_state(log, ad, state, retries=3):
- """Toggle the WiFi State
-
- Args:
- log: log object
- ad: AndroidDevice object
- state: True, False, or None
-
- Returns:
- boolean success (True) or failure (False)
- """
- for i in range(retries):
- if wifi_test_utils.wifi_toggle_state(ad, state, assert_on_fail=False):
- ad.on_mobile_data = not state
- return True
- time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
- return False
-
-
-def start_wifi_tethering(log, ad, ssid, password, ap_band=None):
- """Start a Tethering Session
-
- Args:
- log: log object
- ad: AndroidDevice object
- ssid: the name of the WiFi network
- password: optional password, used for secure networks.
- ap_band=DEPRECATED specification of 2G or 5G tethering
- Returns:
- boolean success (True) or failure (False)
- """
- return wifi_test_utils._assert_on_fail_handler(
- wifi_test_utils.start_wifi_tethering,
- False,
- ad,
- ssid,
- password,
- band=ap_band)
-
-
-def stop_wifi_tethering(log, ad):
- """Stop a Tethering Session
-
- Args:
- log: log object
- ad: AndroidDevice object
- Returns:
- boolean success (True) or failure (False)
- """
- return wifi_test_utils._assert_on_fail_handler(
- wifi_test_utils.stop_wifi_tethering, False, ad)
-
-
def reset_preferred_network_type_to_allowable_range(log, ad):
"""If preferred network type is not in allowable range, reset to GEN_4G
preferred network type.
@@ -5318,61 +2396,6 @@
return False
-def set_preferred_subid_for_sms(log, ad, sub_id):
- """set subscription id for SMS
-
- Args:
- log: Log object.
- ad: Android device object.
- sub_id :Subscription ID.
-
- """
- ad.log.info("Setting subscription %s as preferred SMS SIM", sub_id)
- ad.droid.subscriptionSetDefaultSmsSubId(sub_id)
- # Wait to make sure settings take effect
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- return sub_id == ad.droid.subscriptionGetDefaultSmsSubId()
-
-
-def set_preferred_subid_for_data(log, ad, sub_id):
- """set subscription id for data
-
- Args:
- log: Log object.
- ad: Android device object.
- sub_id :Subscription ID.
-
- """
- ad.log.info("Setting subscription %s as preferred Data SIM", sub_id)
- ad.droid.subscriptionSetDefaultDataSubId(sub_id)
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- # Wait to make sure settings take effect
- # Data SIM change takes around 1 min
- # Check whether data has changed to selected sim
- if not wait_for_data_connection(log, ad, True,
- MAX_WAIT_TIME_DATA_SUB_CHANGE):
- log.error("Data Connection failed - Not able to switch Data SIM")
- return False
- return True
-
-
-def set_preferred_subid_for_voice(log, ad, sub_id):
- """set subscription id for voice
-
- Args:
- log: Log object.
- ad: Android device object.
- sub_id :Subscription ID.
-
- """
- ad.log.info("Setting subscription %s as Voice SIM", sub_id)
- ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
- ad.droid.telecomSetUserSelectedOutgoingPhoneAccountBySubId(sub_id)
- # Wait to make sure settings take effect
- time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
- return True
-
-
def set_call_state_listen_level(log, ad, value, sub_id):
"""Set call state listen level for subscription id.
@@ -5397,34 +2420,6 @@
return True
-def setup_sim(log, ad, sub_id, voice=False, sms=False, data=False):
- """set subscription id for voice, sms and data
-
- Args:
- log: Log object.
- ad: Android device object.
- sub_id :Subscription ID.
- voice: True if to set subscription as default voice subscription
- sms: True if to set subscription as default sms subscription
- data: True if to set subscription as default data subscription
-
- """
- if sub_id == INVALID_SUB_ID:
- log.error("Invalid Subscription ID")
- return False
- else:
- if voice:
- if not set_preferred_subid_for_voice(log, ad, sub_id):
- return False
- if sms:
- if not set_preferred_subid_for_sms(log, ad, sub_id):
- return False
- if data:
- if not set_preferred_subid_for_data(log, ad, sub_id):
- return False
- return True
-
-
def is_event_match(event, field, value):
"""Return if <field> in "event" match <value> or not.
@@ -6101,27 +3096,6 @@
return False
-def extract_test_log(log, src_file, dst_file, test_tag):
- os.makedirs(os.path.dirname(dst_file), exist_ok=True)
- cmd = "grep -n '%s' %s" % (test_tag, src_file)
- result = job.run(cmd, ignore_status=True)
- if not result.stdout or result.exit_status == 1:
- log.warning("Command %s returns %s", cmd, result)
- return
- line_nums = re.findall(r"(\d+).*", result.stdout)
- if line_nums:
- begin_line = int(line_nums[0])
- end_line = int(line_nums[-1])
- if end_line - begin_line <= 5:
- result = job.run("wc -l < %s" % src_file)
- if result.stdout:
- end_line = int(result.stdout)
- log.info("Extract %s from line %s to line %s to %s", src_file,
- begin_line, end_line, dst_file)
- job.run("awk 'NR >= %s && NR <= %s' %s > %s" % (begin_line, end_line,
- src_file, dst_file))
-
-
def get_device_epoch_time(ad):
return int(1000 * float(ad.adb.shell("date +%s.%N")))
@@ -6196,32 +3170,6 @@
return result
-def log_screen_shot(ad, test_name=""):
- file_name = "/sdcard/Pictures/screencap"
- if test_name:
- file_name = "%s_%s" % (file_name, test_name)
- file_name = "%s_%s.png" % (file_name, utils.get_current_epoch_time())
- try:
- ad.adb.shell("screencap -p %s" % file_name)
- except:
- ad.log.error("Fail to log screen shot to %s", file_name)
-
-
-def get_screen_shot_log(ad, test_name="", begin_time=None):
- logs = ad.get_file_names("/sdcard/Pictures", begin_time=begin_time)
- if logs:
- ad.log.info("Pulling %s", logs)
- log_path = os.path.join(ad.device_log_path, "Screenshot_%s" % ad.serial)
- os.makedirs(log_path, exist_ok=True)
- ad.pull_files(logs, log_path)
- ad.adb.shell("rm -rf /sdcard/Pictures/screencap_*", ignore_status=True)
-
-
-def get_screen_shot_logs(ads, test_name="", begin_time=None):
- for ad in ads:
- get_screen_shot_log(ad, test_name=test_name, begin_time=begin_time)
-
-
def get_carrier_id_version(ad):
out = ad.adb.shell("dumpsys activity service TelephonyDebugService | " \
"grep -i carrier_list_version")
@@ -6757,12 +3705,6 @@
return rx_power, tx_power
-
-
-
-
-
-
def set_time_sync_from_network(ad, action):
if (action == 'enable'):
ad.log.info('Enabling sync time from network.')
@@ -6800,66 +3742,6 @@
return get_value
-def wait_for_call_end(
- log,
- ad_caller,
- ad_callee,
- ad_hangup,
- verify_caller_func,
- verify_callee_func,
- call_begin_time,
- check_interval=5,
- tel_result_wrapper=TelResultWrapper(CallResult('SUCCESS')),
- wait_time_in_call=WAIT_TIME_IN_CALL):
- elapsed_time = 0
- while (elapsed_time < wait_time_in_call):
- check_interval = min(check_interval, wait_time_in_call - elapsed_time)
- time.sleep(check_interval)
- elapsed_time += check_interval
- time_message = "at <%s>/<%s> second." % (elapsed_time, wait_time_in_call)
- for ad, call_func in [(ad_caller, verify_caller_func),
- (ad_callee, verify_callee_func)]:
- if not call_func(log, ad):
- ad.log.error(
- "NOT in correct %s state at %s, voice in RAT %s",
- call_func.__name__,
- time_message,
- ad.droid.telephonyGetCurrentVoiceNetworkType())
- tel_result_wrapper.result_value = CallResult(
- 'CALL_DROP_OR_WRONG_STATE_AFTER_CONNECTED')
- else:
- ad.log.info("In correct %s state at %s",
- call_func.__name__, time_message)
- if not ad.droid.telecomCallGetAudioState():
- ad.log.error("Audio is not in call state at %s", time_message)
- tel_result_wrapper.result_value = CallResult(
- 'AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED')
- if not tel_result_wrapper:
- return tel_result_wrapper
-
- if ad_hangup:
- if not hangup_call(log, ad_hangup):
- ad_hangup.log.info("Failed to hang up the call")
- tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
-
- if not tel_result_wrapper:
- for ad in (ad_caller, ad_callee):
- last_call_drop_reason(ad, call_begin_time)
- try:
- if ad.droid.telecomIsInCall():
- ad.log.info("In call. End now.")
- ad.droid.telecomEndCall()
- except Exception as e:
- log.error(str(e))
- if ad_hangup or not tel_result_wrapper:
- for ad in (ad_caller, ad_callee):
- if not wait_for_call_id_clearing(ad, getattr(ad, "caller_ids", [])):
- tel_result_wrapper.result_value = CallResult(
- 'CALL_ID_CLEANUP_FAIL')
-
- return tel_result_wrapper
-
-
def change_voice_subid_temporarily(ad, sub_id, state_check_func, params=None):
result = False
voice_sub_id_changed = False
@@ -6901,47 +3783,6 @@
return voice_network_list
-def check_call_status(ad, voice_type_init=None, voice_type_in_call=None):
- """"
- Args:
- ad: Android device object
- voice_type_init: Voice network type before initiate call
- voice_type_in_call: Voice network type in call state
-
- Return:
- voice_call_type_dict: Voice call status
- """
- dut = str(ad.serial)
- network_type = voice_type_init + "_" + voice_type_in_call
- if network_type == "NR_NR":
- voice_call_type_dict = update_voice_call_type_dict(dut, "VoNR")
- elif network_type == "NR_LTE":
- voice_call_type_dict = update_voice_call_type_dict(dut, "EPSFB")
- elif network_type == "LTE_LTE":
- voice_call_type_dict = update_voice_call_type_dict(dut, "VoLTE")
- elif network_type == "LTE_WCDMA":
- voice_call_type_dict = update_voice_call_type_dict(dut, "CSFB")
- else:
- voice_call_type_dict = update_voice_call_type_dict(dut, "UNKNOWN")
- return voice_call_type_dict
-
-
-def update_voice_call_type_dict(dut, key):
- """
- Args:
- dut: Serial Number of android device object
- key: Network subscription parameter (VoNR or EPSFB or VoLTE or CSFB or UNKNOWN)
- Return:
- voice_call_type: Voice call status
- """
- if dut in voice_call_type.keys():
- voice_call_type[dut][key] += 1
- else:
- voice_call_type[dut] = {key:0}
- voice_call_type[dut][key] += 1
- return voice_call_type
-
-
def cycle_airplane_mode(ad):
"""Turn on APM and then off."""
# APM toggle
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_video_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_video_utils.py
index 0d028f9..26751cf 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_video_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_video_utils.py
@@ -43,16 +43,16 @@
from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_video_enabled
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_network_generation
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_iwlan_for_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_generation
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_answer_call_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_generation
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
from acts_contrib.test_utils.tel.tel_voice_utils import is_call_hd
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_iwlan_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call_for_subscription
def phone_setup_video(
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_voice_conf_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_voice_conf_utils.py
index da112d3..721e83e 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_voice_conf_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_voice_conf_utils.py
@@ -24,19 +24,20 @@
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_HOLDING
from acts_contrib.test_utils.tel.tel_defines import PHONE_TYPE_GSM
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_2g
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_3g
from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
from acts_contrib.test_utils.tel.tel_test_utils import get_call_uri
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
-from acts_contrib.test_utils.tel.tel_test_utils import initiate_call
from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
from acts_contrib.test_utils.tel.tel_test_utils import is_uri_equivalent
-from acts_contrib.test_utils.tel.tel_test_utils import wait_and_reject_call_for_subscription
+from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
from acts_contrib.test_utils.tel.tel_voice_utils import get_cep_conference_call_id
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_2g
-from acts_contrib.test_utils.tel.tel_voice_utils import phone_setup_voice_3g
+from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
+from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_reject_call_for_subscription
+
def _three_phone_call_mo_add_mo(log, ads, phone_setups, verify_funcs):
"""Use 3 phones to make MO calls.
diff --git a/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py b/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py
index 84cdcf8..62e3d1e 100644
--- a/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py
+++ b/acts_tests/acts_contrib/test_utils/tel/tel_voice_utils.py
@@ -14,105 +14,934 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import re
import time
+from queue import Empty
from acts import signals
+from acts.logger import epoch_to_log_line_timestamp
+from acts.utils import get_current_epoch_time
from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs
+from acts_contrib.test_utils.tel.tel_defines import CARRIER_NTT_DOCOMO, CARRIER_KDDI, CARRIER_RAKUTEN, CARRIER_SBM
from acts_contrib.test_utils.tel.tel_defines import CALL_PROPERTY_HIGH_DEF_AUDIO
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_ACTIVE
from acts_contrib.test_utils.tel.tel_defines import CALL_STATE_HOLDING
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
-from acts_contrib.test_utils.tel.tel_defines import CARRIER_TMO
+from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
from acts_contrib.test_utils.tel.tel_defines import GEN_2G
from acts_contrib.test_utils.tel.tel_defines import GEN_3G
-from acts_contrib.test_utils.tel.tel_defines import GEN_4G
-from acts_contrib.test_utils.tel.tel_defines import GEN_5G
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
-from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
+from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
+from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
+from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
+from acts_contrib.test_utils.tel.tel_defines import MAX_SAVED_VOICE_MAIL
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_DROP
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_IDLE_EVENT
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_INITIATION
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALLEE_RINGING
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TELECOM_RINGING
+from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOICE_MAIL_COUNT
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_CDMA2000
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WCDMA
-from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
from acts_contrib.test_utils.tel.tel_defines import RAT_IWLAN
from acts_contrib.test_utils.tel.tel_defines import RAT_LTE
from acts_contrib.test_utils.tel.tel_defines import RAT_UMTS
from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
+from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
+from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
+from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_LEAVE_VOICE_MAIL
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
-from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_REJECT_CALL
+from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE
from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_CDMA
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_ONLY
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_GSM_UMTS
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_CDMA_EVDO
-from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_GSM_WCDMA
-from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
-from acts_contrib.test_utils.tel.tel_defines import DIRECTION_MOBILE_ORIGINATED
+from acts_contrib.test_utils.tel.tel_defines import EventCallStateChanged
+from acts_contrib.test_utils.tel.tel_defines import EventMessageWaitingIndicatorChanged
+from acts_contrib.test_utils.tel.tel_defines import CallStateContainer
+from acts_contrib.test_utils.tel.tel_defines import MessageWaitingIndicatorContainer
from acts_contrib.test_utils.tel.tel_ims_utils import is_wfc_enabled
from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte
-from acts_contrib.test_utils.tel.tel_ims_utils import toggle_volte_for_subscription
from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc
from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode
-from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
-from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_enhanced_4g_lte_setting
from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_volte_enabled
from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_disabled
-from acts_contrib.test_utils.tel.tel_lookup_tables import network_preference_for_generation
-from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_for_subscription
-from acts_contrib.test_utils.tel.tel_ss_utils import call_setup_teardown_for_call_forwarding
-from acts_contrib.test_utils.tel.tel_ss_utils import call_setup_teardown_for_call_waiting
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
+from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_delete_digit
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phone_subscription
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_not_network_rat
+from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_voice_attach
+from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_outgoing_call
from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
-from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
-from acts_contrib.test_utils.tel.tel_test_utils import call_reject_leave_message
-from acts_contrib.test_utils.tel.tel_test_utils import call_setup_teardown
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_network_rat_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_default_state
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phones_idle
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_phone_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import ensure_wifi_connected
-from acts_contrib.test_utils.tel.tel_test_utils import get_capability_for_subscription
+from acts_contrib.test_utils.tel.tel_test_utils import _wait_for_droid_in_state
+from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_connected_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_idle_by_adb
+from acts_contrib.test_utils.tel.tel_test_utils import check_phone_number_match
+from acts_contrib.test_utils.tel.tel_test_utils import check_voice_mail_count
+from acts_contrib.test_utils.tel.tel_test_utils import check_voice_network_type
+from acts_contrib.test_utils.tel.tel_test_utils import get_call_uri
+from acts_contrib.test_utils.tel.tel_test_utils import get_device_epoch_time
from acts_contrib.test_utils.tel.tel_test_utils import get_network_gen_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat
from acts_contrib.test_utils.tel.tel_test_utils import get_network_rat_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import get_telephony_signal_strength
-from acts_contrib.test_utils.tel.tel_test_utils import get_user_config_profile
+from acts_contrib.test_utils.tel.tel_test_utils import get_number_from_tel_uri
from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
-from acts_contrib.test_utils.tel.tel_test_utils import reset_preferred_network_type_to_allowable_range
-from acts_contrib.test_utils.tel.tel_test_utils import set_preferred_network_mode_pref
-from acts_contrib.test_utils.tel.tel_test_utils import set_wifi_to_default
+from acts_contrib.test_utils.tel.tel_test_utils import get_user_config_profile
+from acts_contrib.test_utils.tel.tel_test_utils import get_voice_mail_number
+from acts_contrib.test_utils.tel.tel_test_utils import is_event_match
+from acts_contrib.test_utils.tel.tel_test_utils import is_event_match_for_list
+from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
from acts_contrib.test_utils.tel.tel_test_utils import TelResultWrapper
-from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_by_adb
from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_data_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_generation
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_generation_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_not_network_rat
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_network_rat_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_not_network_rat_for_subscription
from acts_contrib.test_utils.tel.tel_test_utils import wait_for_state
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_voice_attach
-from acts_contrib.test_utils.tel.tel_test_utils import wait_for_voice_attach_for_subscription
-from acts_contrib.test_utils.tel.tel_test_utils import wifi_toggle_state
-from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
-from acts_contrib.test_utils.tel.tel_test_utils import hangup_call
+from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
+from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
CallResult = TelephonyVoiceTestResult.CallResult.Value
+result_dict ={}
+voice_call_type = {}
+
+
+def check_call_status(ad, voice_type_init=None, voice_type_in_call=None):
+ """"
+ Args:
+ ad: Android device object
+ voice_type_init: Voice network type before initiate call
+ voice_type_in_call: Voice network type in call state
+
+ Return:
+ voice_call_type_dict: Voice call status
+ """
+ dut = str(ad.serial)
+ network_type = voice_type_init + "_" + voice_type_in_call
+ if network_type == "NR_NR":
+ voice_call_type_dict = update_voice_call_type_dict(dut, "VoNR")
+ elif network_type == "NR_LTE":
+ voice_call_type_dict = update_voice_call_type_dict(dut, "EPSFB")
+ elif network_type == "LTE_LTE":
+ voice_call_type_dict = update_voice_call_type_dict(dut, "VoLTE")
+ elif network_type == "LTE_WCDMA":
+ voice_call_type_dict = update_voice_call_type_dict(dut, "CSFB")
+ else:
+ voice_call_type_dict = update_voice_call_type_dict(dut, "UNKNOWN")
+ return voice_call_type_dict
+
+
+def update_voice_call_type_dict(dut, key):
+ """
+ Args:
+ dut: Serial Number of android device object
+ key: Network subscription parameter (VoNR or EPSFB or VoLTE or CSFB or UNKNOWN)
+ Return:
+ voice_call_type: Voice call status
+ """
+ if dut in voice_call_type.keys():
+ voice_call_type[dut][key] += 1
+ else:
+ voice_call_type[dut] = {key:0}
+ voice_call_type[dut][key] += 1
+ return voice_call_type
+
+
+def dial_phone_number(ad, callee_number):
+ for number in str(callee_number):
+ if number == "#":
+ ad.send_keycode("POUND")
+ elif number == "*":
+ ad.send_keycode("STAR")
+ elif number in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]:
+ ad.send_keycode("%s" % number)
+
+
+def disconnect_call_by_id(log, ad, call_id):
+ """Disconnect call by call id.
+ """
+ ad.droid.telecomCallDisconnect(call_id)
+ return True
+
+
+def dumpsys_last_call_info(ad):
+ """ Get call information by dumpsys telecom. """
+ num = dumpsys_last_call_number(ad)
+ output = ad.adb.shell("dumpsys telecom")
+ result = re.search(r"Call TC@%s: {(.*?)}" % num, output, re.DOTALL)
+ call_info = {"TC": num}
+ if result:
+ result = result.group(1)
+ for attr in ("startTime", "endTime", "direction", "isInterrupted",
+ "callTechnologies", "callTerminationsReason",
+ "isVideoCall", "callProperties"):
+ match = re.search(r"%s: (.*)" % attr, result)
+ if match:
+ if attr in ("startTime", "endTime"):
+ call_info[attr] = epoch_to_log_line_timestamp(
+ int(match.group(1)))
+ else:
+ call_info[attr] = match.group(1)
+ ad.log.debug("call_info = %s", call_info)
+ return call_info
+
+
+def dumpsys_last_call_number(ad):
+ output = ad.adb.shell("dumpsys telecom")
+ call_nums = re.findall("Call TC@(\d+):", output)
+ if not call_nums:
+ return 0
+ else:
+ return int(call_nums[-1])
+
+
+def dumpsys_new_call_info(ad, last_tc_number, retries=3, interval=5):
+ for i in range(retries):
+ if dumpsys_last_call_number(ad) > last_tc_number:
+ call_info = dumpsys_last_call_info(ad)
+ ad.log.info("New call info = %s", sorted(call_info.items()))
+ return call_info
+ else:
+ time.sleep(interval)
+ ad.log.error("New call is not in sysdump telecom")
+ return {}
+
+
+def emergency_dialer_call_by_keyevent(ad, callee_number):
+ for i in range(3):
+ if "EmergencyDialer" in ad.get_my_current_focus_window():
+ ad.log.info("EmergencyDialer is the current focus window")
+ break
+ elif i <= 2:
+ ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
+ time.sleep(1)
+ else:
+ ad.log.error("Unable to bring up EmergencyDialer")
+ return False
+ ad.log.info("Make a phone call to %s", callee_number)
+ dial_phone_number(ad, callee_number)
+ ad.send_keycode("CALL")
+
+
+def get_current_voice_rat(log, ad):
+ """Return current Voice RAT
+
+ Args:
+ ad: Android device object.
+ """
+ return get_current_voice_rat_for_subscription(
+ log, ad, get_outgoing_voice_sub_id(ad))
+
+
+def get_current_voice_rat_for_subscription(log, ad, sub_id):
+ """Return current Voice RAT for subscription id.
+
+ Args:
+ ad: Android device object.
+ sub_id: subscription id.
+ """
+ return get_network_rat_for_subscription(log, ad, sub_id,
+ NETWORK_SERVICE_VOICE)
+
+
+def hangup_call_by_adb(ad):
+ """Make emergency call by EmergencyDialer.
+
+ Args:
+ ad: Caller android device object.
+ callee_number: Callee phone number.
+ """
+ ad.log.info("End call by adb")
+ ad.send_keycode("ENDCALL")
+
+
+def hangup_call(log, ad, is_emergency=False):
+ """Hang up ongoing active call.
+
+ Args:
+ log: log object.
+ ad: android device object.
+
+ Returns:
+ True: if all calls are cleared
+ False: for errors
+ """
+ # short circuit in case no calls are active
+ if not ad.droid.telecomIsInCall():
+ ad.log.warning("No active call exists.")
+ return True
+ ad.ed.clear_events(EventCallStateChanged)
+ ad.droid.telephonyStartTrackingCallState()
+ ad.log.info("Hangup call.")
+ if is_emergency:
+ for call in ad.droid.telecomCallGetCallIds():
+ ad.droid.telecomCallDisconnect(call)
+ else:
+ ad.droid.telecomEndCall()
+
+ try:
+ ad.ed.wait_for_event(
+ EventCallStateChanged,
+ is_event_match,
+ timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
+ field=CallStateContainer.CALL_STATE,
+ value=TELEPHONY_STATE_IDLE)
+ except Empty:
+ ad.log.warning("Call state IDLE event is not received after hang up.")
+ finally:
+ ad.droid.telephonyStopTrackingCallStateChange()
+ if not wait_for_state(ad.droid.telecomIsInCall, False, 15, 1):
+ ad.log.error("Telecom is in call, hangup call failed.")
+ return False
+ return True
+
+
+def initiate_emergency_dialer_call_by_adb(
+ log,
+ ad,
+ callee_number,
+ timeout=MAX_WAIT_TIME_CALL_INITIATION,
+ checking_interval=5):
+ """Make emergency call by EmergencyDialer.
+
+ Args:
+ ad: Caller android device object.
+ callee_number: Callee phone number.
+ emergency : specify the call is emergency.
+ Optional. Default value is False.
+
+ Returns:
+ result: if phone call is placed successfully.
+ """
+ try:
+ # Make a Call
+ ad.wakeup_screen()
+ ad.send_keycode("MENU")
+ ad.log.info("Call %s", callee_number)
+ ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
+ ad.adb.shell(
+ "am start -a android.intent.action.CALL_EMERGENCY -d tel:%s" %
+ callee_number)
+ if not timeout: return True
+ ad.log.info("Check call state")
+ # Verify Call State
+ elapsed_time = 0
+ while elapsed_time < timeout:
+ time.sleep(checking_interval)
+ elapsed_time += checking_interval
+ if check_call_state_connected_by_adb(ad):
+ ad.log.info("Call to %s is connected", callee_number)
+ return True
+ if check_call_state_idle_by_adb(ad):
+ ad.log.info("Call to %s failed", callee_number)
+ return False
+ ad.log.info("Make call to %s failed", callee_number)
+ return False
+ except Exception as e:
+ ad.log.error("initiate emergency call failed with error %s", e)
+
+
+def initiate_call(log,
+ ad,
+ callee_number,
+ emergency=False,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ video=False):
+ """Make phone call from caller to callee.
+
+ Args:
+ ad_caller: Caller android device object.
+ callee_number: Callee phone number.
+ emergency : specify the call is emergency.
+ Optional. Default value is False.
+ incall_ui_display: show the dialer UI foreground or backgroud
+ video: whether to initiate as video call
+
+ Returns:
+ result: if phone call is placed successfully.
+ """
+ ad.ed.clear_events(EventCallStateChanged)
+ sub_id = get_outgoing_voice_sub_id(ad)
+ begin_time = get_device_epoch_time(ad)
+ ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
+ try:
+ # Make a Call
+ ad.log.info("Make a phone call to %s", callee_number)
+ if emergency:
+ ad.droid.telecomCallEmergencyNumber(callee_number)
+ else:
+ ad.droid.telecomCallNumber(callee_number, video)
+
+ # Verify OFFHOOK state
+ if not wait_for_call_offhook_for_subscription(
+ log, ad, sub_id, event_tracking_started=True):
+ ad.log.info("sub_id %s not in call offhook state", sub_id)
+ last_call_drop_reason(ad, begin_time=begin_time)
+ return False
+ else:
+ return True
+
+ finally:
+ if hasattr(ad, "sdm_log") and getattr(ad, "sdm_log"):
+ ad.adb.shell("i2cset -fy 3 64 6 1 b", ignore_status=True)
+ ad.adb.shell("i2cset -fy 3 65 6 1 b", ignore_status=True)
+ ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
+
+ if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
+ ad.droid.telecomShowInCallScreen()
+ elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
+ ad.droid.showHomeScreen()
+
+
+def last_call_drop_reason(ad, begin_time=None):
+ reasons = ad.search_logcat(
+ "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause", begin_time)
+ reason_string = ""
+ if reasons:
+ log_msg = "Logcat call drop reasons:"
+ for reason in reasons:
+ log_msg = "%s\n\t%s" % (log_msg, reason["log_message"])
+ if "ril reason str" in reason["log_message"]:
+ reason_string = reason["log_message"].split(":")[-1].strip()
+ ad.log.info(log_msg)
+ reasons = ad.search_logcat("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION",
+ begin_time)
+ if reasons:
+ ad.log.warning("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION is seen")
+ ad.log.info("last call dumpsys: %s",
+ sorted(dumpsys_last_call_info(ad).items()))
+ return reason_string
+
+
+def call_reject(log, ad_caller, ad_callee, reject=True):
+ """Caller call Callee, then reject on callee.
+
+
+ """
+ subid_caller = ad_caller.droid.subscriptionGetDefaultVoiceSubId()
+ subid_callee = ad_callee.incoming_voice_sub_id
+ ad_caller.log.info("Sub-ID Caller %s, Sub-ID Callee %s", subid_caller,
+ subid_callee)
+ return call_reject_for_subscription(log, ad_caller, ad_callee,
+ subid_caller, subid_callee, reject)
+
+
+def call_reject_for_subscription(log,
+ ad_caller,
+ ad_callee,
+ subid_caller,
+ subid_callee,
+ reject=True):
+ """
+ """
+
+ caller_number = ad_caller.telephony['subscription'][subid_caller][
+ 'phone_num']
+ callee_number = ad_callee.telephony['subscription'][subid_callee][
+ 'phone_num']
+
+ ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
+ if not initiate_call(log, ad_caller, callee_number):
+ ad_caller.log.error("Initiate call failed")
+ return False
+
+ if not wait_and_reject_call_for_subscription(
+ log, ad_callee, subid_callee, caller_number, WAIT_TIME_REJECT_CALL,
+ reject):
+ ad_callee.log.error("Reject call fail.")
+ return False
+ # Check if incoming call is cleared on callee or not.
+ if ad_callee.droid.telephonyGetCallStateForSubscription(
+ subid_callee) == TELEPHONY_STATE_RINGING:
+ ad_callee.log.error("Incoming call is not cleared")
+ return False
+ # Hangup on caller
+ hangup_call(log, ad_caller)
+ return True
+
+
+def call_reject_leave_message(log,
+ ad_caller,
+ ad_callee,
+ verify_caller_func=None,
+ wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
+ """On default voice subscription, Call from caller to callee,
+ reject on callee, caller leave a voice mail.
+
+ 1. Caller call Callee.
+ 2. Callee reject incoming call.
+ 3. Caller leave a voice mail.
+ 4. Verify callee received the voice mail notification.
+
+ Args:
+ ad_caller: caller android device object.
+ ad_callee: callee android device object.
+ verify_caller_func: function to verify caller is in correct state while in-call.
+ This is optional, default is None.
+ wait_time_in_call: time to wait when leaving a voice mail.
+ This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
+
+ Returns:
+ True: if voice message is received on callee successfully.
+ False: for errors
+ """
+ subid_caller = get_outgoing_voice_sub_id(ad_caller)
+ subid_callee = get_incoming_voice_sub_id(ad_callee)
+ return call_reject_leave_message_for_subscription(
+ log, ad_caller, ad_callee, subid_caller, subid_callee,
+ verify_caller_func, wait_time_in_call)
+
+
+def check_reject_needed_for_voice_mail(log, ad_callee):
+ """Check if the carrier requires reject call to receive voice mail or just keep ringing
+ Requested in b//155935290
+ Four Japan carriers do not need to reject
+ SBM, KDDI, Ntt Docomo, Rakuten
+ Args:
+ log: log object
+ ad_callee: android device object
+ Returns:
+ True if callee's carrier is not one of the four Japan carriers
+ False if callee's carrier is one of the four Japan carriers
+ """
+
+ operators_no_reject = [CARRIER_NTT_DOCOMO,
+ CARRIER_KDDI,
+ CARRIER_RAKUTEN,
+ CARRIER_SBM]
+ operator_name = get_operator_name(log, ad_callee)
+
+ return operator_name not in operators_no_reject
+
+
+def _is_on_message_waiting_event_true(event):
+ """Private function to return if the received EventMessageWaitingIndicatorChanged
+ event MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING field is True.
+ """
+ return event['data'][MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING]
+
+
+def call_reject_leave_message_for_subscription(
+ log,
+ ad_caller,
+ ad_callee,
+ subid_caller,
+ subid_callee,
+ verify_caller_func=None,
+ wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
+ """On specific voice subscription, Call from caller to callee,
+ reject on callee, caller leave a voice mail.
+
+ 1. Caller call Callee.
+ 2. Callee reject incoming call.
+ 3. Caller leave a voice mail.
+ 4. Verify callee received the voice mail notification.
+
+ Args:
+ ad_caller: caller android device object.
+ ad_callee: callee android device object.
+ subid_caller: caller's subscription id.
+ subid_callee: callee's subscription id.
+ verify_caller_func: function to verify caller is in correct state while in-call.
+ This is optional, default is None.
+ wait_time_in_call: time to wait when leaving a voice mail.
+ This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
+
+ Returns:
+ True: if voice message is received on callee successfully.
+ False: for errors
+ """
+
+ # Currently this test utility only works for TMO and ATT and SPT.
+ # It does not work for VZW (see b/21559800)
+ # "with VVM TelephonyManager APIs won't work for vm"
+
+ caller_number = ad_caller.telephony['subscription'][subid_caller][
+ 'phone_num']
+ callee_number = ad_callee.telephony['subscription'][subid_callee][
+ 'phone_num']
+
+ ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
+
+ try:
+ voice_mail_count_before = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
+ subid_callee)
+ ad_callee.log.info("voice mail count is %s", voice_mail_count_before)
+ # -1 means there are unread voice mail, but the count is unknown
+ # 0 means either this API not working (VZW) or no unread voice mail.
+ if voice_mail_count_before != 0:
+ log.warning("--Pending new Voice Mail, please clear on phone.--")
+
+ if not initiate_call(log, ad_caller, callee_number):
+ ad_caller.log.error("Initiate call failed.")
+ return False
+ if check_reject_needed_for_voice_mail(log, ad_callee):
+ carrier_specific_delay_reject = 30
+ else:
+ carrier_specific_delay_reject = 2
+ carrier_reject_call = not check_reject_needed_for_voice_mail(log, ad_callee)
+
+ if not wait_and_reject_call_for_subscription(
+ log, ad_callee, subid_callee, incoming_number=caller_number, delay_reject=carrier_specific_delay_reject,
+ reject=carrier_reject_call):
+ ad_callee.log.error("Reject call fail.")
+ return False
+
+ ad_callee.droid.telephonyStartTrackingVoiceMailStateChangeForSubscription(
+ subid_callee)
+
+ # ensure that all internal states are updated in telecom
+ time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
+ ad_callee.ed.clear_events(EventCallStateChanged)
+
+ if verify_caller_func and not verify_caller_func(log, ad_caller):
+ ad_caller.log.error("Caller not in correct state!")
+ return False
+
+ # TODO: b/26293512 Need to play some sound to leave message.
+ # Otherwise carrier voice mail server may drop this voice mail.
+ time.sleep(wait_time_in_call)
+
+ if not verify_caller_func:
+ caller_state_result = ad_caller.droid.telecomIsInCall()
+ else:
+ caller_state_result = verify_caller_func(log, ad_caller)
+ if not caller_state_result:
+ ad_caller.log.error("Caller not in correct state after %s seconds",
+ wait_time_in_call)
+
+ if not hangup_call(log, ad_caller):
+ ad_caller.log.error("Error in Hanging-Up Call")
+ return False
+
+ ad_callee.log.info("Wait for voice mail indicator on callee.")
+ try:
+ event = ad_callee.ed.wait_for_event(
+ EventMessageWaitingIndicatorChanged,
+ _is_on_message_waiting_event_true)
+ ad_callee.log.info("Got event %s", event)
+ except Empty:
+ ad_callee.log.warning("No expected event %s",
+ EventMessageWaitingIndicatorChanged)
+ return False
+ voice_mail_count_after = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
+ subid_callee)
+ ad_callee.log.info(
+ "telephonyGetVoiceMailCount output - before: %s, after: %s",
+ voice_mail_count_before, voice_mail_count_after)
+
+ # voice_mail_count_after should:
+ # either equals to (voice_mail_count_before + 1) [For ATT and SPT]
+ # or equals to -1 [For TMO]
+ # -1 means there are unread voice mail, but the count is unknown
+ if not check_voice_mail_count(log, ad_callee, voice_mail_count_before,
+ voice_mail_count_after):
+ log.error("before and after voice mail count is not incorrect.")
+ return False
+ finally:
+ ad_callee.droid.telephonyStopTrackingVoiceMailStateChangeForSubscription(
+ subid_callee)
+ return True
+
+
+def call_voicemail_erase_all_pending_voicemail(log, ad):
+ """Script for phone to erase all pending voice mail.
+ This script only works for TMO and ATT and SPT currently.
+ This script only works if phone have already set up voice mail options,
+ and phone should disable password protection for voice mail.
+
+ 1. If phone don't have pending voice message, return True.
+ 2. Dial voice mail number.
+ For TMO, the number is '123'
+ For ATT, the number is phone's number
+ For SPT, the number is phone's number
+ 3. Wait for voice mail connection setup.
+ 4. Wait for voice mail play pending voice message.
+ 5. Send DTMF to delete one message.
+ The digit is '7'.
+ 6. Repeat steps 4 and 5 until voice mail server drop this call.
+ (No pending message)
+ 6. Check telephonyGetVoiceMailCount result. it should be 0.
+
+ Args:
+ log: log object
+ ad: android device object
+ Returns:
+ False if error happens. True is succeed.
+ """
+ log.info("Erase all pending voice mail.")
+ count = ad.droid.telephonyGetVoiceMailCount()
+ if count == 0:
+ ad.log.info("No Pending voice mail.")
+ return True
+ if count == -1:
+ ad.log.info("There is pending voice mail, but the count is unknown")
+ count = MAX_SAVED_VOICE_MAIL
+ else:
+ ad.log.info("There are %s voicemails", count)
+
+ voice_mail_number = get_voice_mail_number(log, ad)
+ delete_digit = get_voice_mail_delete_digit(get_operator_name(log, ad))
+ if not initiate_call(log, ad, voice_mail_number):
+ log.error("Initiate call to voice mail failed.")
+ return False
+ time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
+ callId = ad.droid.telecomCallGetCallIds()[0]
+ time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
+ while (is_phone_in_call(log, ad) and (count > 0)):
+ ad.log.info("Press %s to delete voice mail.", delete_digit)
+ ad.droid.telecomCallPlayDtmfTone(callId, delete_digit)
+ ad.droid.telecomCallStopDtmfTone(callId)
+ time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
+ count -= 1
+ if is_phone_in_call(log, ad):
+ hangup_call(log, ad)
+
+ # wait for telephonyGetVoiceMailCount to update correct result
+ remaining_time = MAX_WAIT_TIME_VOICE_MAIL_COUNT
+ while ((remaining_time > 0)
+ and (ad.droid.telephonyGetVoiceMailCount() != 0)):
+ time.sleep(1)
+ remaining_time -= 1
+ current_voice_mail_count = ad.droid.telephonyGetVoiceMailCount()
+ ad.log.info("telephonyGetVoiceMailCount: %s", current_voice_mail_count)
+ return (current_voice_mail_count == 0)
+
+
+def call_setup_teardown(log,
+ ad_caller,
+ ad_callee,
+ ad_hangup=None,
+ verify_caller_func=None,
+ verify_callee_func=None,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ dialing_number_length=None,
+ video_state=None,
+ slot_id_callee=None,
+ voice_type_init=None,
+ call_stats_check=False,
+ result_info=result_dict):
+ """ Call process, including make a phone call from caller,
+ accept from callee, and hang up. The call is on default voice subscription
+
+ In call process, call from <droid_caller> to <droid_callee>,
+ accept the call, (optional)then hang up from <droid_hangup>.
+
+ Args:
+ ad_caller: Caller Android Device Object.
+ ad_callee: Callee Android Device Object.
+ ad_hangup: Android Device Object end the phone call.
+ Optional. Default value is None, and phone call will continue.
+ verify_call_mode_caller: func_ptr to verify caller in correct mode
+ Optional. Default is None
+ verify_call_mode_caller: func_ptr to verify caller in correct mode
+ Optional. Default is None
+ incall_ui_display: after answer the call, bring in-call UI to foreground or
+ background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+ dialing_number_length: the number of digits used for dialing
+ slot_id_callee : the slot if of the callee to call to
+
+ Returns:
+ True if call process without any error.
+ False if error happened.
+
+ """
+ subid_caller = get_outgoing_voice_sub_id(ad_caller)
+ if slot_id_callee is None:
+ subid_callee = get_incoming_voice_sub_id(ad_callee)
+ else:
+ subid_callee = get_subid_from_slot_index(log, ad_callee, slot_id_callee)
+
+ return call_setup_teardown_for_subscription(
+ log, ad_caller, ad_callee, subid_caller, subid_callee, ad_hangup,
+ verify_caller_func, verify_callee_func, wait_time_in_call,
+ incall_ui_display, dialing_number_length, video_state,
+ voice_type_init, call_stats_check, result_info)
+
+
+def call_setup_teardown_for_subscription(
+ log,
+ ad_caller,
+ ad_callee,
+ subid_caller,
+ subid_callee,
+ ad_hangup=None,
+ verify_caller_func=None,
+ verify_callee_func=None,
+ wait_time_in_call=WAIT_TIME_IN_CALL,
+ incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
+ dialing_number_length=None,
+ video_state=None,
+ voice_type_init=None,
+ call_stats_check=False,
+ result_info=result_dict):
+ """ Call process, including make a phone call from caller,
+ accept from callee, and hang up. The call is on specified subscription
+
+ In call process, call from <droid_caller> to <droid_callee>,
+ accept the call, (optional)then hang up from <droid_hangup>.
+
+ Args:
+ ad_caller: Caller Android Device Object.
+ ad_callee: Callee Android Device Object.
+ subid_caller: Caller subscription ID
+ subid_callee: Callee subscription ID
+ ad_hangup: Android Device Object end the phone call.
+ Optional. Default value is None, and phone call will continue.
+ verify_call_mode_caller: func_ptr to verify caller in correct mode
+ Optional. Default is None
+ verify_call_mode_caller: func_ptr to verify caller in correct mode
+ Optional. Default is None
+ incall_ui_display: after answer the call, bring in-call UI to foreground or
+ background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
+ if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
+ if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
+ else, do nothing.
+
+ Returns:
+ TelResultWrapper which will evaluate as False if error.
+
+ """
+ CHECK_INTERVAL = 5
+ begin_time = get_current_epoch_time()
+ if not verify_caller_func:
+ verify_caller_func = is_phone_in_call
+ if not verify_callee_func:
+ verify_callee_func = is_phone_in_call
+
+ caller_number = ad_caller.telephony['subscription'][subid_caller][
+ 'phone_num']
+ callee_number = ad_callee.telephony['subscription'][subid_callee][
+ 'phone_num']
+ if dialing_number_length:
+ skip_test = False
+ trunc_position = 0 - int(dialing_number_length)
+ try:
+ caller_area_code = caller_number[:trunc_position]
+ callee_area_code = callee_number[:trunc_position]
+ callee_dial_number = callee_number[trunc_position:]
+ except:
+ skip_test = True
+ if caller_area_code != callee_area_code:
+ skip_test = True
+ if skip_test:
+ msg = "Cannot make call from %s to %s by %s digits" % (
+ caller_number, callee_number, dialing_number_length)
+ ad_caller.log.info(msg)
+ raise signals.TestSkip(msg)
+ else:
+ callee_number = callee_dial_number
+
+ tel_result_wrapper = TelResultWrapper(CallResult('SUCCESS'))
+ msg = "Call from %s to %s" % (caller_number, callee_number)
+ if video_state:
+ msg = "Video %s" % msg
+ video = True
+ else:
+ video = False
+ if ad_hangup:
+ msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
+ ad_caller.log.info(msg)
+
+ for ad in (ad_caller, ad_callee):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ setattr(ad, "call_ids", call_ids)
+ if call_ids:
+ ad.log.info("Pre-exist CallId %s before making call", call_ids)
+
+ if not initiate_call(
+ log,
+ ad_caller,
+ callee_number,
+ incall_ui_display=incall_ui_display,
+ video=video):
+ ad_caller.log.error("Initiate call failed.")
+ tel_result_wrapper.result_value = CallResult('INITIATE_FAILED')
+ return tel_result_wrapper
+ else:
+ ad_caller.log.info("Caller initate call successfully")
+ if not wait_and_answer_call_for_subscription(
+ log,
+ ad_callee,
+ subid_callee,
+ incoming_number=caller_number,
+ caller=ad_caller,
+ incall_ui_display=incall_ui_display,
+ video_state=video_state):
+ ad_callee.log.error("Answer call fail.")
+ tel_result_wrapper.result_value = CallResult(
+ 'NO_RING_EVENT_OR_ANSWER_FAILED')
+ return tel_result_wrapper
+ else:
+ ad_callee.log.info("Callee answered the call successfully")
+
+ for ad, call_func in zip([ad_caller, ad_callee],
+ [verify_caller_func, verify_callee_func]):
+ call_ids = ad.droid.telecomCallGetCallIds()
+ new_call_ids = set(call_ids) - set(ad.call_ids)
+ if not new_call_ids:
+ ad.log.error(
+ "No new call ids are found after call establishment")
+ ad.log.error("telecomCallGetCallIds returns %s",
+ ad.droid.telecomCallGetCallIds())
+ tel_result_wrapper.result_value = CallResult('NO_CALL_ID_FOUND')
+ for new_call_id in new_call_ids:
+ if not wait_for_in_call_active(ad, call_id=new_call_id):
+ tel_result_wrapper.result_value = CallResult(
+ 'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
+ else:
+ ad.log.info("callProperties = %s",
+ ad.droid.telecomCallGetProperties(new_call_id))
+
+ if not ad.droid.telecomCallGetAudioState():
+ ad.log.error("Audio is not in call state")
+ tel_result_wrapper.result_value = CallResult(
+ 'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
+
+ if call_func(log, ad):
+ ad.log.info("Call is in %s state", call_func.__name__)
+ else:
+ ad.log.error("Call is not in %s state, voice in RAT %s",
+ call_func.__name__,
+ ad.droid.telephonyGetCurrentVoiceNetworkType())
+ tel_result_wrapper.result_value = CallResult(
+ 'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
+ if not tel_result_wrapper:
+ return tel_result_wrapper
+
+ if call_stats_check:
+ voice_type_in_call = check_voice_network_type([ad_caller, ad_callee], voice_init=False)
+ phone_a_call_type = check_call_status(ad_caller,
+ voice_type_init[0],
+ voice_type_in_call[0])
+ result_info["Call Stats"] = phone_a_call_type
+ ad_caller.log.debug("Voice Call Type: %s", phone_a_call_type)
+ phone_b_call_type = check_call_status(ad_callee,
+ voice_type_init[1],
+ voice_type_in_call[1])
+ result_info["Call Stats"] = phone_b_call_type
+ ad_callee.log.debug("Voice Call Type: %s", phone_b_call_type)
+
+ return wait_for_call_end(
+ log,
+ ad_caller,
+ ad_callee,
+ ad_hangup,
+ verify_caller_func,
+ verify_callee_func,
+ begin_time,
+ check_interval=CHECK_INTERVAL,
+ tel_result_wrapper=TelResultWrapper(CallResult('SUCCESS')),
+ wait_time_in_call=WAIT_TIME_IN_CALL)
def two_phone_call_leave_voice_mail(
@@ -499,1113 +1328,38 @@
return tel_result
-def three_phone_call_forwarding_short_seq(log,
- phone_a,
- phone_a_idle_func,
- phone_a_in_call_check_func,
- phone_b,
- phone_c,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- call_forwarding_type="unconditional",
- retry=2):
- """Short sequence of call process with call forwarding.
- Test steps:
- 1. Ensure all phones are initially in idle state.
- 2. Enable call forwarding on Phone A.
- 3. Make a call from Phone B to Phone A, The call should be forwarded to
- PhoneC. Accept the call on Phone C.
- 4. Ensure the call is connected and in correct phone state.
- 5. Hang up the call on Phone B.
- 6. Ensure all phones are in idle state.
- 7. Disable call forwarding on Phone A.
- 7. Make a call from Phone B to Phone A, The call should NOT be forwarded
- to PhoneC. Accept the call on Phone A.
- 8. Ensure the call is connected and in correct phone state.
- 9. Hang up the call on Phone B.
+
+def is_phone_in_call(log, ad):
+ """Return True if phone in call.
Args:
- phone_a: android object of Phone A
- phone_a_idle_func: function to check idle state on Phone A
- phone_a_in_call_check_func: function to check in-call state on Phone A
- phone_b: android object of Phone B
- phone_c: android object of Phone C
- wait_time_in_call: time to wait in call.
- This is optional, default is WAIT_TIME_IN_CALL
- call_forwarding_type:
- - "unconditional"
- - "busy"
- - "not_answered"
- - "not_reachable"
- retry: times of retry
-
- Returns:
- True: if call sequence succeed.
- False: for errors
+ log: log object.
+ ad: android device.
"""
- ads = [phone_a, phone_b, phone_c]
-
- call_params = [
- (ads[1], ads[0], ads[2], ads[1], phone_a_in_call_check_func, False)
- ]
-
- if call_forwarding_type != "unconditional":
- call_params.append((
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- phone_a_in_call_check_func,
- True))
-
- for param in call_params:
- ensure_phones_idle(log, ads)
- if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
- phone_a.log.error("Phone A Failed to Reselect")
- return False
-
- time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
-
- log.info(
- "---> Call forwarding %s (caller: %s, callee: %s, callee forwarded:"
- " %s) <---",
- call_forwarding_type,
- param[0].serial,
- param[1].serial,
- param[2].serial)
- while not call_setup_teardown_for_call_forwarding(
- log,
- *param,
- wait_time_in_call=wait_time_in_call,
- call_forwarding_type=call_forwarding_type) and retry >= 0:
-
- if retry <= 0:
- log.error("Call forwarding %s failed." % call_forwarding_type)
- return False
- else:
- log.info(
- "RERUN the test case: 'Call forwarding %s'" %
- call_forwarding_type)
-
- retry = retry - 1
-
- return True
-
-def three_phone_call_waiting_short_seq(log,
- phone_a,
- phone_a_idle_func,
- phone_a_in_call_check_func,
- phone_b,
- phone_c,
- wait_time_in_call=WAIT_TIME_IN_CALL,
- call_waiting=True,
- scenario=None,
- retry=2):
- """Short sequence of call process with call waiting.
- Test steps:
- 1. Ensure all phones are initially in idle state.
- 2. Enable call waiting on Phone A.
- 3. Make the 1st call from Phone B to Phone A. Accept the call on Phone B.
- 4. Ensure the call is connected and in correct phone state.
- 5. Make the 2nd call from Phone C to Phone A. The call should be able to
- income correctly. Whether or not the 2nd call should be answered by
- Phone A depends on the scenario listed in the next step.
- 6. Following 8 scenarios will be tested:
- - 1st call ended first by Phone B during 2nd call incoming. 2nd call
- ended by Phone C
- - 1st call ended first by Phone B during 2nd call incoming. 2nd call
- ended by Phone A
- - 1st call ended first by Phone A during 2nd call incoming. 2nd call
- ended by Phone C
- - 1st call ended first by Phone A during 2nd call incoming. 2nd call
- ended by Phone A
- - 1st call ended by Phone B. 2nd call ended by Phone C
- - 1st call ended by Phone B. 2nd call ended by Phone A
- - 1st call ended by Phone A. 2nd call ended by Phone C
- - 1st call ended by Phone A. 2nd call ended by Phone A
- 7. Ensure all phones are in idle state.
-
- Args:
- phone_a: android object of Phone A
- phone_a_idle_func: function to check idle state on Phone A
- phone_a_in_call_check_func: function to check in-call state on Phone A
- phone_b: android object of Phone B
- phone_c: android object of Phone C
- wait_time_in_call: time to wait in call.
- This is optional, default is WAIT_TIME_IN_CALL
- call_waiting: True for call waiting enabled and False for disabled
- scenario: 1-8 for scenarios listed above
- retry: times of retry
-
- Returns:
- True: if call sequence succeed.
- False: for errors
- """
- ads = [phone_a, phone_b, phone_c]
-
- sub_test_cases = [
- {
- "description": "1st call ended first by caller1 during 2nd call"
- " incoming. 2nd call ended by caller2",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- ads[2],
- phone_a_in_call_check_func,
- True)},
- {
- "description": "1st call ended first by caller1 during 2nd call"
- " incoming. 2nd call ended by callee",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- ads[0],
- phone_a_in_call_check_func,
- True)},
- {
- "description": "1st call ended first by callee during 2nd call"
- " incoming. 2nd call ended by caller2",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[2],
- phone_a_in_call_check_func,
- True)},
- {
- "description": "1st call ended first by callee during 2nd call"
- " incoming. 2nd call ended by callee",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[0],
- phone_a_in_call_check_func,
- True)},
- {
- "description": "1st call ended by caller1. 2nd call ended by"
- " caller2",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- ads[2],
- phone_a_in_call_check_func,
- False)},
- {
- "description": "1st call ended by caller1. 2nd call ended by callee",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[1],
- ads[0],
- phone_a_in_call_check_func,
- False)},
- {
- "description": "1st call ended by callee. 2nd call ended by caller2",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[2],
- phone_a_in_call_check_func,
- False)},
- {
- "description": "1st call ended by callee. 2nd call ended by callee",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[0],
- phone_a_in_call_check_func,
- False)}
- ]
-
- if call_waiting:
- if not scenario:
- test_cases = sub_test_cases
- else:
- test_cases = [sub_test_cases[scenario-1]]
- else:
- test_cases = [
- {
- "description": "Call waiting deactivated",
- "params": (
- ads[1],
- ads[0],
- ads[2],
- ads[0],
- ads[0],
- phone_a_in_call_check_func,
- False)}
- ]
-
- results = []
-
- for test_case in test_cases:
- ensure_phones_idle(log, ads)
- if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
- phone_a.log.error("Phone A Failed to Reselect")
- return False
-
- time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
-
- log.info(
- "---> %s (caller1: %s, caller2: %s, callee: %s) <---",
- test_case["description"],
- test_case["params"][1].serial,
- test_case["params"][2].serial,
- test_case["params"][0].serial)
-
- while not call_setup_teardown_for_call_waiting(
- log,
- *test_case["params"],
- wait_time_in_call=wait_time_in_call,
- call_waiting=call_waiting) and retry >= 0:
-
- if retry <= 0:
- log.error("Call waiting sub-case: '%s' failed." % test_case[
- "description"])
- results.append(False)
- else:
- log.info("RERUN the sub-case: '%s'" % test_case["description"])
-
- retry = retry - 1
-
- for result in results:
- if not result:
- return False
-
- return True
-
-def phone_setup_iwlan(log,
- ad,
- is_airplane_mode,
- wfc_mode,
- wifi_ssid=None,
- wifi_pwd=None,
- nw_gen=None):
- """Phone setup function for epdg call test.
- Set WFC mode according to wfc_mode.
- Set airplane mode according to is_airplane_mode.
- Make sure phone connect to WiFi. (If wifi_ssid is not None.)
- Wait for phone to be in iwlan data network type.
- Wait for phone to report wfc enabled flag to be true.
- Args:
- log: Log object.
- ad: Android device object.
- is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode.
- wfc_mode: WFC mode to set to.
- wifi_ssid: WiFi network SSID. This is optional.
- If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
- wifi_pwd: WiFi network password. This is optional.
- nw_gen: network type selection. This is optional.
- GEN_4G for 4G, GEN_5G for 5G or None for doing nothing.
- Returns:
- True if success. False if fail.
- """
- return phone_setup_iwlan_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad),
- is_airplane_mode, wfc_mode,
- wifi_ssid, wifi_pwd, nw_gen)
-
-
-def phone_setup_iwlan_for_subscription(log,
- ad,
- sub_id,
- is_airplane_mode,
- wfc_mode,
- wifi_ssid=None,
- wifi_pwd=None,
- nw_gen=None,
- nr_type=None):
- """Phone setup function for epdg call test for subscription id.
- Set WFC mode according to wfc_mode.
- Set airplane mode according to is_airplane_mode.
- Make sure phone connect to WiFi. (If wifi_ssid is not None.)
- Wait for phone to be in iwlan data network type.
- Wait for phone to report wfc enabled flag to be true.
- Args:
- log: Log object.
- ad: Android device object.
- sub_id: subscription id.
- is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode.
- wfc_mode: WFC mode to set to.
- wifi_ssid: WiFi network SSID. This is optional.
- If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
- wifi_pwd: WiFi network password. This is optional.
- nw_gen: network type selection. This is optional.
- GEN_4G for 4G, GEN_5G for 5G or None for doing nothing.
- nr_type: NR network type
- Returns:
- True if success. False if fail.
- """
- if not get_capability_for_subscription(ad, CAPABILITY_WFC, sub_id):
- ad.log.error("WFC is not supported, abort test.")
- raise signals.TestSkip("WFC is not supported, abort test.")
-
- if nw_gen:
- if not ensure_network_generation_for_subscription(
- log, ad, sub_id, nw_gen, voice_or_data=NETWORK_SERVICE_DATA,
- nr_type=nr_type):
- ad.log.error("Failed to set to %s data.", nw_gen)
- return False
- toggle_airplane_mode(log, ad, is_airplane_mode, strict_checking=False)
-
- # Pause at least for 4 seconds is necessary after airplane mode was turned
- # on due to the mechanism of deferring Wi-Fi (b/191481736)
- if is_airplane_mode:
- time.sleep(5)
-
- # check if WFC supported phones
- if wfc_mode != WFC_MODE_DISABLED and not ad.droid.imsIsWfcEnabledByPlatform(
- ):
- ad.log.error("WFC is not enabled on this device by checking "
- "ImsManager.isWfcEnabledByPlatform")
- return False
- if wifi_ssid is not None:
- if not ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd, apm=is_airplane_mode):
- ad.log.error("Fail to bring up WiFi connection on %s.", wifi_ssid)
- return False
- else:
- ad.log.info("WiFi network SSID not specified, available user "
- "parameters are: wifi_network_ssid, wifi_network_ssid_2g, "
- "wifi_network_ssid_5g")
- if not set_wfc_mode_for_subscription(ad, wfc_mode, sub_id):
- ad.log.error("Unable to set WFC mode to %s.", wfc_mode)
- return False
-
- if wfc_mode != WFC_MODE_DISABLED:
- if not wait_for_wfc_enabled(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
- ad.log.error("WFC is not enabled")
- return False
-
- return True
-
-
-def phone_setup_iwlan_cellular_preferred(log,
- ad,
- wifi_ssid=None,
- wifi_pwd=None):
- """Phone setup function for iwlan Non-APM CELLULAR_PREFERRED test.
- Set WFC mode according to CELLULAR_PREFERRED.
- Set airplane mode according to False.
- Make sure phone connect to WiFi. (If wifi_ssid is not None.)
- Make sure phone don't report iwlan data network type.
- Make sure phone don't report wfc enabled flag to be true.
-
- Args:
- log: Log object.
- ad: Android device object.
- wifi_ssid: WiFi network SSID. This is optional.
- If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi.
- wifi_pwd: WiFi network password. This is optional.
-
- Returns:
- True if success. False if fail.
- """
- toggle_airplane_mode(log, ad, False, strict_checking=False)
try:
- toggle_volte(log, ad, True)
- if not wait_for_network_generation(
- log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
- if not ensure_network_generation(
- log, ad, GEN_4G, voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("Fail to ensure data in 4G")
- return False
- except Exception as e:
- ad.log.error(e)
- ad.droid.telephonyToggleDataConnection(True)
- if wifi_ssid is not None:
- if not ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd):
- ad.log.error("Connect to WiFi failed.")
- return False
- if not set_wfc_mode(log, ad, WFC_MODE_CELLULAR_PREFERRED):
- ad.log.error("Set WFC mode failed.")
- return False
- if not wait_for_not_network_rat(
- log, ad, RAT_FAMILY_WLAN, voice_or_data=NETWORK_SERVICE_DATA):
- ad.log.error("Data rat in iwlan mode.")
- return False
- elif not wait_for_wfc_disabled(log, ad, MAX_WAIT_TIME_WFC_ENABLED):
- ad.log.error("Should report wifi calling disabled within %s.",
- MAX_WAIT_TIME_WFC_ENABLED)
- return False
- return True
+ return ad.droid.telecomIsInCall()
+ except:
+ return "mCallState=2" in ad.adb.shell(
+ "dumpsys telephony.registry | grep mCallState")
-def phone_setup_data_for_subscription(log, ad, sub_id, network_generation,
- nr_type=None):
- """Setup Phone <sub_id> Data to <network_generation>
+def is_phone_in_call_active(ad, call_id=None):
+ """Return True if phone in active call.
Args:
- log: log object
- ad: android device object
- sub_id: subscription id
- network_generation: network generation, e.g. GEN_2G, GEN_3G, GEN_4G, GEN_5G
- nr_type: NR network type e.g. NSA, SA, MMWAVE
-
- Returns:
- True if success, False if fail.
+ log: log object.
+ ad: android device.
+ call_id: the call id
"""
- toggle_airplane_mode(log, ad, False, strict_checking=False)
- set_wifi_to_default(log, ad)
- if not set_wfc_mode(log, ad, WFC_MODE_DISABLED):
- ad.log.error("Disable WFC failed.")
- return False
- if not ensure_network_generation_for_subscription(
- log,
- ad,
- sub_id,
- network_generation,
- voice_or_data=NETWORK_SERVICE_DATA,
- nr_type=nr_type):
- get_telephony_signal_strength(ad)
- return False
- return True
-
-
-def phone_setup_5g(log, ad, nr_type=None):
- """Setup Phone default data sub_id data to 5G.
-
- Args:
- log: log object
- ad: android device object
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_5g_for_subscription(log, ad,
- get_default_data_sub_id(ad), nr_type=nr_type)
-
-
-def phone_setup_5g_for_subscription(log, ad, sub_id, nr_type=None):
- """Setup Phone <sub_id> Data to 5G.
-
- Args:
- log: log object
- ad: android device object
- sub_id: subscription id
- nr_type: NR network type e.g. NSA, SA, MMWAVE
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_data_for_subscription(log, ad, sub_id, GEN_5G,
- nr_type=nr_type)
-
-
-def phone_setup_4g(log, ad):
- """Setup Phone default data sub_id data to 4G.
-
- Args:
- log: log object
- ad: android device object
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_4g_for_subscription(log, ad,
- get_default_data_sub_id(ad))
-
-
-def phone_setup_4g_for_subscription(log, ad, sub_id):
- """Setup Phone <sub_id> Data to 4G.
-
- Args:
- log: log object
- ad: android device object
- sub_id: subscription id
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_data_for_subscription(log, ad, sub_id, GEN_4G)
-
-
-def phone_setup_3g(log, ad):
- """Setup Phone default data sub_id data to 3G.
-
- Args:
- log: log object
- ad: android device object
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_3g_for_subscription(log, ad,
- get_default_data_sub_id(ad))
-
-
-def phone_setup_3g_for_subscription(log, ad, sub_id):
- """Setup Phone <sub_id> Data to 3G.
-
- Args:
- log: log object
- ad: android device object
- sub_id: subscription id
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_data_for_subscription(log, ad, sub_id, GEN_3G)
-
-
-def phone_setup_2g(log, ad):
- """Setup Phone default data sub_id data to 2G.
-
- Args:
- log: log object
- ad: android device object
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_2g_for_subscription(log, ad,
- get_default_data_sub_id(ad))
-
-
-def phone_setup_2g_for_subscription(log, ad, sub_id):
- """Setup Phone <sub_id> Data to 3G.
-
- Args:
- log: log object
- ad: android device object
- sub_id: subscription id
-
- Returns:
- True if success, False if fail.
- """
- return phone_setup_data_for_subscription(log, ad, sub_id, GEN_2G)
-
-
-def phone_setup_csfb(log, ad, nw_gen=GEN_4G, nr_type=None):
- """Setup phone for CSFB call test.
-
- Setup Phone to be in 4G mode.
- Disabled VoLTE.
-
- Args:
- log: log object
- ad: Android device object.
- nw_gen: GEN_4G or GEN_5G
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_csfb_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad), nw_gen, nr_type=nr_type)
-
-
-def phone_setup_csfb_for_subscription(log, ad, sub_id, nw_gen=GEN_4G, nr_type=None):
- """Setup phone for CSFB call test for subscription id.
-
- Setup Phone to be in 4G mode.
- Disabled VoLTE.
-
- Args:
- log: log object
- ad: Android device object.
- sub_id: subscription id.
- nw_gen: GEN_4G or GEN_5G
- nr_type: NR network type e.g. NSA, SA, MMWAVE
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- capabilities = ad.telephony["subscription"][sub_id].get("capabilities", [])
- if capabilities:
- if "hide_enhanced_4g_lte" in capabilities:
- show_enhanced_4g_lte_mode = getattr(ad, "show_enhanced_4g_lte_mode", False)
- if show_enhanced_4g_lte_mode in ["false", "False", False]:
- ad.log.warning("'VoLTE' option is hidden. Test will be skipped.")
- raise signals.TestSkip("'VoLTE' option is hidden. Test will be skipped.")
-
- if nw_gen == GEN_4G:
- if not phone_setup_4g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 4G data.")
- return False
- elif nw_gen == GEN_5G:
- if not phone_setup_5g_for_subscription(log, ad, sub_id, nr_type=nr_type):
- ad.log.error("Failed to set to 5G data.")
- return False
-
- if not toggle_volte_for_subscription(log, ad, sub_id, False):
- return False
-
- if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- return False
-
- return phone_idle_csfb_for_subscription(log, ad, sub_id, nw_gen)
-
-def phone_setup_volte(log, ad, nw_gen=GEN_4G, nr_type=None):
- """Setup VoLTE enable.
-
- Args:
- log: log object
- ad: android device object.
- nw_gen: GEN_4G or GEN_5G
-
- Returns:
- True: if VoLTE is enabled successfully.
- False: for errors
- """
- if not get_capability_for_subscription(ad, CAPABILITY_VOLTE,
- get_outgoing_voice_sub_id(ad)):
- ad.log.error("VoLTE is not supported, abort test.")
- raise signals.TestSkip("VoLTE is not supported, abort test.")
- return phone_setup_volte_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad), nw_gen, nr_type= nr_type)
-
-def phone_setup_volte_for_subscription(log, ad, sub_id, nw_gen=GEN_4G,
- nr_type=None):
- """Setup VoLTE enable for subscription id.
- Args:
- log: log object
- ad: android device object.
- sub_id: subscription id.
- nw_gen: GEN_4G or GEN_5G.
- nr_type: NR network type.
-
- Returns:
- True: if VoLTE is enabled successfully.
- False: for errors
- """
- if not get_capability_for_subscription(ad, CAPABILITY_VOLTE,
- get_outgoing_voice_sub_id(ad)):
- ad.log.error("VoLTE is not supported, abort test.")
- raise signals.TestSkip("VoLTE is not supported, abort test.")
-
- if nw_gen == GEN_4G:
- if not phone_setup_4g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 4G data.")
- return False
- elif nw_gen == GEN_5G:
- if not phone_setup_5g_for_subscription(log, ad, sub_id,
- nr_type=nr_type):
- ad.log.error("Failed to set to 5G data.")
- return False
- operator_name = get_operator_name(log, ad, sub_id)
- if operator_name == CARRIER_TMO:
- return True
+ if ad.droid.telecomIsInCall():
+ if not call_id:
+ call_id = ad.droid.telecomCallGetCallIds()[0]
+ call_state = ad.droid.telecomCallGetCallState(call_id)
+ ad.log.info("%s state is %s", call_id, call_state)
+ return call_state == "ACTIVE"
else:
- if not wait_for_enhanced_4g_lte_setting(log, ad, sub_id):
- ad.log.error("Enhanced 4G LTE setting is not available")
- return False
- toggle_volte_for_subscription(log, ad, sub_id, True)
- return phone_idle_volte_for_subscription(log, ad, sub_id, nw_gen,
- nr_type=nr_type)
-
-
-def phone_setup_voice_3g(log, ad):
- """Setup phone voice to 3G.
-
- Args:
- log: log object
- ad: Android device object.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_voice_3g_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_setup_voice_3g_for_subscription(log, ad, sub_id):
- """Setup phone voice to 3G for subscription id.
-
- Args:
- log: log object
- ad: Android device object.
- sub_id: subscription id.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- if not phone_setup_3g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 3G data.")
+ ad.log.info("Not in telecomIsInCall")
return False
- if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- return False
- return phone_idle_3g_for_subscription(log, ad, sub_id)
-
-
-def phone_setup_voice_2g(log, ad):
- """Setup phone voice to 2G.
-
- Args:
- log: log object
- ad: Android device object.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_voice_2g_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_setup_voice_2g_for_subscription(log, ad, sub_id):
- """Setup phone voice to 2G for subscription id.
-
- Args:
- log: log object
- ad: Android device object.
- sub_id: subscription id.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- if not phone_setup_2g_for_subscription(log, ad, sub_id):
- ad.log.error("Failed to set to 2G data.")
- return False
- if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- return False
- return phone_idle_2g_for_subscription(log, ad, sub_id)
-
-
-def phone_setup_voice_general(log, ad):
- """Setup phone for voice general call test.
-
- Make sure phone attached to voice.
- Make necessary delay.
-
- Args:
- ad: Android device object.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_voice_general_for_subscription(
- log, ad, get_outgoing_voice_sub_id(ad))
-
-
-def phone_setup_voice_general_for_slot(log,ad,slot_id):
- return phone_setup_voice_general_for_subscription(
- log, ad, get_subid_from_slot_index(log,ad,slot_id))
-
-
-def phone_setup_voice_general_for_subscription(log, ad, sub_id):
- """Setup phone for voice general call test for subscription id.
-
- Make sure phone attached to voice.
- Make necessary delay.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- toggle_airplane_mode(log, ad, False, strict_checking=False)
- if not wait_for_voice_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- # if phone can not attach voice, try phone_setup_voice_3g
- return phone_setup_voice_3g_for_subscription(log, ad, sub_id)
- return True
-
-
-def phone_setup_data_general(log, ad):
- """Setup phone for data general test.
-
- Make sure phone attached to data.
- Make necessary delay.
-
- Args:
- ad: Android device object.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- return phone_setup_data_general_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultDataSubId())
-
-
-def phone_setup_data_general_for_subscription(log, ad, sub_id):
- """Setup phone for data general test for subscription id.
-
- Make sure phone attached to data.
- Make necessary delay.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
-
- Returns:
- True if setup successfully.
- False for errors.
- """
- toggle_airplane_mode(log, ad, False, strict_checking=False)
- if not wait_for_data_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION):
- # if phone can not attach data, try reset network preference settings
- reset_preferred_network_type_to_allowable_range(log, ad)
-
- return wait_for_data_attach_for_subscription(log, ad, sub_id,
- MAX_WAIT_TIME_NW_SELECTION)
-
-
-def phone_setup_rat_for_subscription(log, ad, sub_id, network_preference,
- rat_family):
- toggle_airplane_mode(log, ad, False, strict_checking=False)
- set_wifi_to_default(log, ad)
- if not set_wfc_mode(log, ad, WFC_MODE_DISABLED):
- ad.log.error("Disable WFC failed.")
- return False
- return ensure_network_rat_for_subscription(log, ad, sub_id,
- network_preference, rat_family)
-
-
-def phone_setup_lte_gsm_wcdma(log, ad):
- return phone_setup_lte_gsm_wcdma_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_lte_gsm_wcdma_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(
- log, ad, sub_id, NETWORK_MODE_LTE_GSM_WCDMA, RAT_FAMILY_LTE)
-
-
-def phone_setup_gsm_umts(log, ad):
- return phone_setup_gsm_umts_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_gsm_umts_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(
- log, ad, sub_id, NETWORK_MODE_GSM_UMTS, RAT_FAMILY_WCDMA)
-
-
-def phone_setup_gsm_only(log, ad):
- return phone_setup_gsm_only_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_gsm_only_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(
- log, ad, sub_id, NETWORK_MODE_GSM_ONLY, RAT_FAMILY_GSM)
-
-
-def phone_setup_lte_cdma_evdo(log, ad):
- return phone_setup_lte_cdma_evdo_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_lte_cdma_evdo_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(
- log, ad, sub_id, NETWORK_MODE_LTE_CDMA_EVDO, RAT_FAMILY_LTE)
-
-
-def phone_setup_cdma(log, ad):
- return phone_setup_cdma_for_subscription(
- log, ad, ad.droid.subscriptionGetDefaultSubId())
-
-
-def phone_setup_cdma_for_subscription(log, ad, sub_id):
- return phone_setup_rat_for_subscription(log, ad, sub_id, NETWORK_MODE_CDMA,
- RAT_FAMILY_CDMA2000)
-
-
-def phone_idle_volte(log, ad):
- """Return if phone is idle for VoLTE call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_volte_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_volte_for_subscription(log, ad, sub_id, nw_gen=GEN_4G,
- nr_type=None):
- """Return if phone is idle for VoLTE call test for subscription id.
- Args:
- ad: Android device object.
- sub_id: subscription id.
- nw_gen: GEN_4G or GEN_5G.
- nr_type: NR network type e.g. NSA, SA, MMWAVE
- """
- if nw_gen == GEN_5G:
- if not is_current_network_5g_for_subscription(ad, sub_id=sub_id,
- nr_type=nr_type):
- ad.log.error("Not in 5G coverage.")
- return False
- else:
- if not wait_for_network_rat_for_subscription(
- log, ad, sub_id, RAT_FAMILY_LTE,
- voice_or_data=NETWORK_SERVICE_VOICE):
- ad.log.error("Voice rat not in LTE mode.")
- return False
- if not wait_for_volte_enabled(log, ad, MAX_WAIT_TIME_VOLTE_ENABLED, sub_id):
- ad.log.error(
- "Failed to <report volte enabled true> within %s seconds.",
- MAX_WAIT_TIME_VOLTE_ENABLED)
- return False
- return True
-
-
-def phone_idle_iwlan(log, ad):
- """Return if phone is idle for WiFi calling call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_iwlan_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_iwlan_for_subscription(log, ad, sub_id):
- """Return if phone is idle for WiFi calling call test for subscription id.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
- """
- if not wait_for_wfc_enabled(log, ad, MAX_WAIT_TIME_WFC_ENABLED):
- ad.log.error("Failed to <report wfc enabled true> within %s seconds.",
- MAX_WAIT_TIME_WFC_ENABLED)
- return False
- return True
-
-
-def phone_idle_not_iwlan(log, ad):
- """Return if phone is idle for non WiFi calling call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_not_iwlan_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_not_iwlan_for_subscription(log, ad, sub_id):
- """Return if phone is idle for non WiFi calling call test for sub id.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
- """
- if not wait_for_not_network_rat_for_subscription(
- log, ad, sub_id, RAT_FAMILY_WLAN,
- voice_or_data=NETWORK_SERVICE_DATA):
- log.error("{} data rat in iwlan mode.".format(ad.serial))
- return False
- return True
-
-
-def phone_idle_csfb(log, ad):
- """Return if phone is idle for CSFB call test.
-
- Args:
- ad: Android device object.
- """
- return phone_idle_csfb_for_subscription(log, ad,
- get_outgoing_voice_sub_id(ad))
-
-
-def phone_idle_csfb_for_subscription(log, ad, sub_id, nw_gen=GEN_4G, nr_type=None):
- """Return if phone is idle for CSFB call test for subscription id.
-
- Args:
- ad: Android device object.
- sub_id: subscription id.
- nw_gen: GEN_4G or GEN_5G
- """
- if nw_gen == GEN_5G:
- if not is_current_network_5g_for_subscription(ad, sub_id=sub_id, nr_type=nr_type):
- ad.log.error("Not in 5G coverage.")
- return False
- else:
- if not wait_for_network_rat_for_subscription(