diff --git a/wa/workloads/gmail/__init__.py b/wa/workloads/gmail/__init__.py index cdf7ae78..84b2f79b 100755 --- a/wa/workloads/gmail/__init__.py +++ b/wa/workloads/gmail/__init__.py @@ -36,6 +36,14 @@ class Gmail(ApkUiautoWorkload): 6. Enter text in the Compose field 7. Click the Send mail button + To run the workload in offline mode, a 'mailstore.tar' file is required. In order to + generate such a file, Gmail should first be operated from an Internet-connected environment. + After this, the relevant database files can be found in the + '/data/data/com.google.android.gm/databases' directory. These files can then be archived to + produce a tarball using a command such as ``tar -cvf mailstore.tar -C /path/to/databases .``. + The result should then be placed in the '~/.workload_automation/dependencies/gmail/' directory + on your local machine, creating this if it does not already exist. + Known working APK version: 7.11.5.176133587 ''' @@ -50,17 +58,36 @@ class Gmail(ApkUiautoWorkload): An image to be copied onto the device that will be attached to the email '''), + Parameter('offline_mode', kind=bool, default=False, description=''' + If set to ``True``, the workload will execute in offline mode. + This mode requires root and makes use of a tarball of email + database files 'mailstore.tar' for the email account to be used. + This file is extracted directly to the application's 'databases' + directory at '/data/data/com.google.android.gm/databases'. + '''), ] - # This workload relies on the internet so check that there is a working - # internet connection - requires_network = True + @property + def requires_network(self): + return not self.offline_mode + + @property + def requires_rerun(self): + # In offline mode we need to restart the application after modifying its data directory + return self.offline_mode def __init__(self, target, **kwargs): super(Gmail, self).__init__(target, **kwargs) self.deployable_assets = [self.test_image] + if self.offline_mode: + self.deployable_assets.append('mailstore.tar') self.clean_assets = True + def initialize(self, context): + super(Gmail, self).initialize(context) + if self.offline_mode and not self.target.is_rooted: + raise WorkloadError('This workload requires root to set up Gmail for offline usage.') + def init_resources(self, context): super(Gmail, self).init_resources(context) if self.target.get_sdk_version() >= 24 and 'com.google.android.apps.photos' not in self.target.list_packages(): @@ -70,6 +97,17 @@ class Gmail(ApkUiautoWorkload): work_dir = work_dir if work_dir[-1] != os.sep else work_dir[:-1] self.gui.uiauto_params['workdir_name'] = self.target.path.basename(work_dir) self.gui.uiauto_params['recipient'] = self.recipient + self.gui.uiauto_params['offline_mode'] = self.offline_mode # Only accept certain image formats if os.path.splitext(self.test_image.lower())[1] not in ['.jpg', '.jpeg', '.png']: raise ValidationError('{} must be a JPEG or PNG file'.format(self.test_image)) + + def setup_rerun(self): + super(Gmail, self).setup_rerun() + database_src = self.target.path.join(self.target.working_directory, 'mailstore.tar') + database_dst = self.target.path.join(self.target.package_data_directory, self.package, 'databases') + existing_mailstores = self.target.path.join(database_dst, 'mailstore.*') + owner = self.target.execute("{} stat -c '%u' {}".format(self.target.busybox, database_dst), as_root=True).strip() + self.target.execute('{} rm {}'.format(self.target.busybox, existing_mailstores), as_root=True) + self.target.execute('{} tar -xvf {} -C {}'.format(self.target.busybox, database_src, database_dst), as_root=True) + self.target.execute('{} chown -R {}:{} {}'.format(self.target.busybox, owner, owner, database_dst), as_root=True) diff --git a/wa/workloads/gmail/com.arm.wa.uiauto.gmail.apk b/wa/workloads/gmail/com.arm.wa.uiauto.gmail.apk index a32df324..60100c4e 100644 Binary files a/wa/workloads/gmail/com.arm.wa.uiauto.gmail.apk and b/wa/workloads/gmail/com.arm.wa.uiauto.gmail.apk differ diff --git a/wa/workloads/gmail/uiauto/app/src/main/java/com/arm/wa/uiauto/gmail/UiAutomation.java b/wa/workloads/gmail/uiauto/app/src/main/java/com/arm/wa/uiauto/gmail/UiAutomation.java index 257a5190..db60c503 100755 --- a/wa/workloads/gmail/uiauto/app/src/main/java/com/arm/wa/uiauto/gmail/UiAutomation.java +++ b/wa/workloads/gmail/uiauto/app/src/main/java/com/arm/wa/uiauto/gmail/UiAutomation.java @@ -39,6 +39,7 @@ public class UiAutomation extends BaseUiAutomation implements ApplaunchInterface protected String packageID; protected String recipient; protected String workdir_name; + protected boolean offlineMode; private int networkTimeoutSecs = 30; private long networkTimeout = TimeUnit.SECONDS.toMillis(networkTimeoutSecs); @@ -49,6 +50,7 @@ public class UiAutomation extends BaseUiAutomation implements ApplaunchInterface packageID = getPackageID(parameters); recipient = parameters.getString("recipient"); workdir_name = parameters.getString("workdir_name"); + offlineMode = parameters.getBoolean("offline_mode"); } @Test @@ -112,6 +114,11 @@ public class UiAutomation extends BaseUiAutomation implements ApplaunchInterface takeMeToBox.clickAndWaitForNewWindow(uiAutoTimeout); } + // If we're in offline mode we don't need to worry about syncing, so we're done + if (offlineMode) { + return; + } + UiObject syncNowButton = mDevice.findObject(new UiSelector().textContains("Sync now") .className("android.widget.Button"));