aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJinhui Wang <jinhuiw@google.com>2016-06-07 18:38:00 -0700
committerJinhui Wang <jinhuiw@google.com>2016-06-10 09:16:53 -0700
commitdc65dc058699a68bfa8f5f0fc1b031125137db43 (patch)
treea7f35ad46548b05433743afff4d52800a6bc2b7e
parent03597fd71c63bbdd361685fdd264199a3fbea4bc (diff)
downloadAfwTestHarness-dc65dc058699a68bfa8f5f0fc1b031125137db43.tar.gz
Import AfwThCommonLib module
Change-Id: I0e6298bd72a026b61ddde7ca513e5bb26adfc8db
-rw-r--r--Android.mk17
-rw-r--r--libs/Android.mk18
-rw-r--r--libs/CommonLib/Android.mk27
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/AccountManagerUtils.java79
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/Constants.java180
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/FileUtils.java86
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/PkgMgrUtils.java45
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/Preconditions.java45
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/Timer.java95
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/NfcBumpSimulator.java128
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/Utils.java72
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/test/OemWidget.java160
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/test/StatsLogger.java153
-rw-r--r--libs/CommonLib/src/com/android/afwtest/common/test/TestConfig.java391
14 files changed, 1496 insertions, 0 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..41a41d0
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2016 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.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/libs/Android.mk b/libs/Android.mk
new file mode 100644
index 0000000..6801acf
--- /dev/null
+++ b/libs/Android.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (C) 2016 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.
+#
+
+include $(call all-subdir-makefiles)
+
diff --git a/libs/CommonLib/Android.mk b/libs/CommonLib/Android.mk
new file mode 100644
index 0000000..f0c3f65
--- /dev/null
+++ b/libs/CommonLib/Android.mk
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2016 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := AfwThCommonLib
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/libs/CommonLib/src/com/android/afwtest/common/AccountManagerUtils.java b/libs/CommonLib/src/com/android/afwtest/common/AccountManagerUtils.java
new file mode 100644
index 0000000..8384a6c
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/AccountManagerUtils.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common;
+
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import java.io.IOException;
+
+/**
+ * Help class to wrap AccountManager ralated functionalities.
+ */
+public final class AccountManagerUtils {
+
+ private static final String TAG = "afwtest.AccountManagerUtils";
+
+ private static final String GOOGLE_ACCOUNT_TYPE = "com.google";
+ private static final String EXTRA_SETUP_WIZARD = "setupWizard";
+
+ /**
+ * Private constructor to prevent instantiation.
+ */
+ private AccountManagerUtils() {
+ }
+
+ /**
+ * Starts Add Account activity by firing a proper intent.
+ *
+ * @param context {@link Context} object
+ * @param isSetupWizard {@code true} if simulating setup wizard,
+ * {@code false} if simulating Settings->Add Account
+ */
+ public static void startAddGoogleAccountActivity(Context context, boolean isSetupWizard)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final AccountManager accountManager = AccountManager.get(context);
+
+ // Options for the Add Account activity.
+ Bundle options = new Bundle();
+ options.putBoolean(EXTRA_SETUP_WIZARD, isSetupWizard);
+ if (isSetupWizard) {
+ // Skip "Got another device?" page
+ options.putBoolean("suppress_device_to_device_setup", true);
+ }
+
+ AccountManagerFuture<Bundle> amf = accountManager.addAccount(
+ GOOGLE_ACCOUNT_TYPE,
+ null, /* authTokenType*/
+ null, /* requiredFeatures */
+ options,
+ null, /* Activity context, null to not start the intent automatically */
+ null, /* callback */
+ null /* handler */
+ );
+
+ // Fire the intent to start the UI.
+ Intent intent = (Intent) amf.getResult().get(AccountManager.KEY_INTENT);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(intent);
+ }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/Constants.java b/libs/CommonLib/src/com/android/afwtest/common/Constants.java
new file mode 100644
index 0000000..b708037
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/Constants.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common;
+
+/***
+ * Common constants.
+ */
+public final class Constants {
+
+ /**
+ * Property key of device admin package name, used in the test configuration file.
+ */
+ public static final String KEY_DEVICE_ADMIN_PKG_NAME = "device_admin_pkg_name";
+
+ /**
+ * Property key of device admin package location, used in the test configuration file.
+ */
+ public static final String KEY_DEVICE_ADMIN_PKG_LOCATION = "device_admin_pkg_location";
+
+ /**
+ * Property key of device admin package checksum, used in the test configuration file.
+ */
+ public static final String KEY_DEVICE_ADMIN_PKG_CHECKSUM = "device_admin_pkg_checksum";
+
+ /**
+ * Property key of device admin package signature hash, used in the test configuration file.
+ */
+ public static final String KEY_DEVICE_ADMIN_PKG_SIGNATURE_HASH
+ = "device_admin_pkg_signature_hash";
+
+ /**
+ * Property key of timeout size, used in the test configuration file.
+ */
+ public static final String KEY_TIMEOUT_SIZE = "timeout_size";
+
+ /**
+ * Property key of test timeout in minute, used in the test configuration file.
+ */
+ public static final String KEY_TEST_TIMEOUT_MIN = "test_timeout_min";
+
+ /**
+ * Property key of wifi ssid, used in the test configuration file.
+ */
+ public static final String KEY_WIFI_SSID = "wifi_ssid";
+
+ /**
+ * Property key of the wifi password, used in the test configuration file.
+ */
+ public static final String KEY_WIFI_PWD = "wifi_password";
+
+ /**
+ * Property key of the wifi security type, used in the test configuration file.
+ */
+ public static final String KEY_WIFI_SECURITY_TYPE = "wifi_security_type";
+
+ /**
+ * Property key of the username of the work account, used in the test configuration file.
+ */
+ public static final String KEY_WORK_ACCOUNT_USERNAME = "work_account_username";
+
+ /**
+ * Property key of the password of the work account, used in the test configuration file.
+ */
+ public static final String KEY_WORK_ACCOUNT_PASSWORD = "work_account_password";
+
+ /**
+ * Property key for the list of OEM customized widget Ids.
+ *
+ * <p>The properties of each OEM widget are specified by separate keys in the format of
+ * widget_id.property. "property" can be any of {@link #KEY_OEM_WIDGET_TEXT},
+ * {@link #KEY_OEM_WIDGET_DESCRIPTION}, {@link #KEY_OEM_WIDGET_RESOURCE_ID},
+ * {@link #KEY_OEM_WIDGET_PACKAGE}, {@link #KEY_OEM_WIDGET_CLASS} or
+ * {@link #KEY_OEM_WIDGET_ACTION}.</p>
+ *
+ * <p>For example, OEM can define a widget like:
+ * <ul>
+ * <li>oem_widgets=custom_widget</li>
+ * <li>custom_widget.text=Get started</li>
+ * <li>custom_widget.class=android.widget.Button</li>
+ * <li>custom_widget.action=click</li>
+ * </ul>
+ * This tells the test to find a widget with text "Get started" and with class name
+ * "android.widget.Button" to click.</p>
+ */
+ public static final String KEY_OEM_WIDGETS = "oem_widgets";
+
+ /**
+ * Property key for the text of an OEM widget.
+ */
+ public static final String KEY_OEM_WIDGET_TEXT = "text";
+
+ /**
+ * Property key for the content description of an OEM widget.
+ */
+ public static final String KEY_OEM_WIDGET_DESCRIPTION = "description";
+
+ /**
+ * Property key for the resource ID of an OEM widget.
+ */
+ public static final String KEY_OEM_WIDGET_RESOURCE_ID = "resource_id";
+
+ /**
+ * Property key for the package name of an OEM widget.
+ */
+ public static final String KEY_OEM_WIDGET_PACKAGE = "package";
+
+ /**
+ * Property key for the class name of an OEM widget.
+ */
+ public static final String KEY_OEM_WIDGET_CLASS = "class";
+
+ /**
+ * Property key for the action on an OEM widget. It can any of {@link #ACTION_CLICK},
+ * {@link #ACTION_CHECK} or {@link #ACTION_SCROLL}.
+ */
+ public static final String KEY_OEM_WIDGET_ACTION = "action";
+
+ /**
+ * Property key for the app crash dialog auto close strategy: whether to auto close
+ * all non-fatal crashes.
+ */
+ public static final String KEY_MUTE_APP_CRASH_DIALOGS = "mute_app_crash_dialogs";
+
+ /**
+ * Property key for app names whose app crash dialog should be auto closed, separated by ",".
+ */
+ public static final String KEY_APP_CRASH_WHITELIST = "app_crash_whitelist";
+
+ /**
+ * Click action on a widget.
+ */
+ public static final String ACTION_CLICK = "click";
+
+ /**
+ * Scroll action on a widget.
+ */
+ public static final String ACTION_SCROLL = "scroll";
+
+ /**
+ * Check action on a widget, either a checkbox or radio button.
+ */
+ public static final String ACTION_CHECK = "check";
+
+ /**
+ * Constant string for the user to specify the path of the file
+ * that contains NFC provisioning configurations.
+ */
+ public static final String NFC_BUMP_FILE = "NFCBumpFile";
+
+ /**
+ * Package name of system util app.
+ */
+ public static final String SYSTEM_UTIL_PKG_NAME = "com.google.android.afwtest.systemutil";
+
+ /**
+ * Send NFC bump action.
+ */
+ public static final String ACTION_SEND_NFC_BUMP
+ = "com.google.android.afwtest.systemutil.action.SEND_NFC_BUMP";
+
+ /**
+ * Private constructor to prevent instantiation.
+ */
+ private Constants() {
+ }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/FileUtils.java b/libs/CommonLib/src/com/android/afwtest/common/FileUtils.java
new file mode 100644
index 0000000..dcf962f
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/FileUtils.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common;
+
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Properties;
+
+/**
+ * File Utils.
+ */
+public final class FileUtils {
+
+ private static final String TAG = "afwtest.FileUtils";
+
+ /**
+ * Reads {@link Properties} object from file.
+ *
+ * @param path File path
+ * @return Constructed {@link Properties} object
+ */
+ public static Properties readPropertiesFromFile(String path) throws IOException {
+ InputStream input = null;
+
+ try {
+ input = new FileInputStream(path);
+ Properties props = new Properties();
+ props.load(input);
+ return props;
+ } finally {
+ quietClose(input);
+ }
+ }
+
+ /**
+ * Writes {@link Properties} object into a file.
+ *
+ * @param props {@link Properties} object to write
+ * @param path file path
+ */
+ public static void writePropertiesToFile(Properties props, String path) throws IOException {
+ OutputStream output = null;
+
+ try {
+ output = new FileOutputStream(path);
+ props.store(output, null);
+ } finally {
+ quietClose(output);
+ }
+ }
+
+ /**
+ * Closes a closeable object quietly.
+ *
+ * @param handler The handler to close.
+ */
+ public static void quietClose(Closeable handler) {
+ if (handler != null) {
+ try {
+ handler.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Closing stream failed", e);
+ }
+ }
+ }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/PkgMgrUtils.java b/libs/CommonLib/src/com/android/afwtest/common/PkgMgrUtils.java
new file mode 100644
index 0000000..fac3624
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/PkgMgrUtils.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+package com.android.afwtest.common;
+
+import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Log;
+
+/**
+ * Utils for {@link PackageManager}.
+ */
+public final class PkgMgrUtils {
+ private static final String TAG = "afwtest.PkgMgrUtil";
+
+ /**
+ * Checks if a package is installed.
+ *
+ * @param context {@link Context} object
+ * @param pkgName name of the package to check
+ * @return {@code true} if target package is installed, {@code false} otherwise
+ */
+ public static boolean isPkgInstalled(Context context, String pkgName) {
+ try {
+ return context.getPackageManager().getPackageInfo(pkgName, 0) != null;
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Pkg not found", e);
+ }
+
+ // Not installed
+ return false;
+ }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/Preconditions.java b/libs/CommonLib/src/com/android/afwtest/common/Preconditions.java
new file mode 100644
index 0000000..bcaf2fc
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/Preconditions.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common;
+
+import android.text.TextUtils;
+
+/**
+ * Precondition check utility.
+ */
+public final class Preconditions {
+
+ /**
+ * Private constructor to prevent instantiation.
+ */
+ private Preconditions() {
+ }
+
+ /**
+ * Ensures that a string passed is not null or empty.
+ *
+ * @param string a string
+ * @return the non-null, non-empty string that was validated
+ * @throws IllegalArgumentException if {@code String} is null or empty
+ */
+ public static String checkNotEmpty(String string) {
+ if (TextUtils.isEmpty(string)) {
+ throw new IllegalArgumentException();
+ }
+ return string;
+ }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/Timer.java b/libs/CommonLib/src/com/android/afwtest/common/Timer.java
new file mode 100644
index 0000000..b33fcf1
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/Timer.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common;
+
+import android.util.Log;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A count-down timer.
+ */
+public final class Timer {
+
+ private static final String TAG = "afwtest.Timer";
+
+ // A year in milliseconds
+ private static final long ONE_YEAR_IN_MS = TimeUnit.DAYS.toMillis(365);
+
+ // Timeout of this timer in milliseconds
+ private final long mTimeoutMs;
+
+ // Start time in milliseconds since Jan 1, 1970
+ private long mStartTime;
+
+ // Elapsed time so far, in milliseconds
+ private long mElapsedTime;
+
+ /**
+ * Constructor.
+ *
+ * @param timeout timeout in milliseconds
+ */
+ public Timer(long timeout) {
+ mTimeoutMs = timeout;
+ }
+
+ /**
+ * Starts this timer.
+ */
+ public void start() {
+ mStartTime = System.currentTimeMillis();
+ mElapsedTime = 0;
+ }
+
+ /**
+ * Checks if time is up by checking if elapsed time is greater than timeout.
+ *
+ * @return {@code true} if time is up, {@code false} otherwise
+ */
+ public boolean isTimeUp() {
+ elapse();
+ return mElapsedTime > mTimeoutMs;
+ }
+
+ /**
+ * Gets elapsed time since start().
+ *
+ * @return long, elapsed time in milliseconds.
+ */
+ public long elapsedTime(){
+ elapse();
+ return mElapsedTime;
+ }
+
+ /**
+ * Re-calculate elapsed time.
+ */
+ private void elapse() {
+ long currentTime = System.currentTimeMillis();
+ long elapsedTime = currentTime - mStartTime;
+ // The system time might change suddenly from 1970 to 21 century, e.g. after factory reset.
+ // Reset mStartTime without updating mElapsedTime.
+ if (elapsedTime > ONE_YEAR_IN_MS) {
+ // Reset time
+ mStartTime = currentTime - mElapsedTime;
+ Log.w(TAG, String.format("System time changed: delta=%d", elapsedTime));
+ } else {
+ mElapsedTime = elapsedTime;
+ }
+ }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/NfcBumpSimulator.java b/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/NfcBumpSimulator.java
new file mode 100644
index 0000000..44e2505
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/NfcBumpSimulator.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common.nfcprovisioning;
+
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_PASSWORD;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SECURITY_TYPE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_WIFI_SSID;
+import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC;
+import static android.nfc.NfcAdapter.ACTION_NDEF_DISCOVERED;
+import static com.android.afwtest.common.Constants.KEY_DEVICE_ADMIN_PKG_CHECKSUM;
+import static com.android.afwtest.common.Constants.KEY_DEVICE_ADMIN_PKG_SIGNATURE_HASH;
+import static com.android.afwtest.common.Preconditions.checkNotEmpty;
+
+import android.content.Context;
+import android.content.Intent;
+import android.nfc.NdefMessage;
+import android.nfc.NdefRecord;
+import android.nfc.NfcAdapter;
+
+import com.android.afwtest.common.test.TestConfig;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+
+/**
+ * Simulates Nfc Bump to start device owner provisioning.
+ */
+public final class NfcBumpSimulator {
+
+ private static final String TAG = "afwtest.NfcBumpSimulator";
+
+ /**
+ * Sends NFC bump to initiate device owner provisioning.
+ *
+ * @param context {@link Context} object
+ * @param propsConfigFile {@link Properties} configuration file containing NFC bump properties.
+ * @return Device admin package name after provisioning completes successfully
+ */
+ public static String sendNfcBump(Context context, String propsConfigFile) throws Exception {
+
+ TestConfig testConfig = TestConfig.get(propsConfigFile);
+
+ Properties bumpProps = new Properties();
+ String deviceAdminPkgName = checkNotEmpty(testConfig.getDeviceAdminPkgName());
+ bumpProps.put(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME, deviceAdminPkgName);
+ bumpProps.put(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION,
+ checkNotEmpty(testConfig.getDeviceAdminPkgLocation()));
+
+ String signatureHash = testConfig.getDeviceAdminPkgSignatureHash("");
+ String checksum = testConfig.getDeviceAdminPkgChecksum("");
+ if (signatureHash.isEmpty() && checksum.isEmpty()) {
+ throw new RuntimeException(String.format("Neither %s nor %s is specified in file %s",
+ KEY_DEVICE_ADMIN_PKG_SIGNATURE_HASH,
+ KEY_DEVICE_ADMIN_PKG_CHECKSUM,
+ propsConfigFile));
+ }
+
+ if (!signatureHash.isEmpty()) {
+ bumpProps.put(EXTRA_PROVISIONING_DEVICE_ADMIN_SIGNATURE_CHECKSUM, signatureHash);
+ }
+
+ // Add checksum if it's not empty because OEM L devices use SHA1 checksum only.
+ if (!checksum.isEmpty()) {
+ bumpProps.put(EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM, checksum);
+ }
+
+ String wifiSsid = checkNotEmpty(testConfig.getWifiSsid());
+ // Make sure to surround SSID with double quotes.
+ if (!wifiSsid.startsWith("\"") || !wifiSsid.endsWith("\"")) {
+ wifiSsid = "\"" + wifiSsid + "\"";
+ }
+ bumpProps.put(EXTRA_PROVISIONING_WIFI_SSID, wifiSsid);
+
+ bumpProps.put(EXTRA_PROVISIONING_WIFI_SECURITY_TYPE, testConfig.getWifiSecurityType(""));
+ bumpProps.put(EXTRA_PROVISIONING_WIFI_PASSWORD, testConfig.getWifiPassword(""));
+
+ // Skip encryption.
+ bumpProps.put(EXTRA_PROVISIONING_SKIP_ENCRYPTION, "true");
+
+ sendNfcBump(context, bumpProps);
+
+ // Return expected device admin package name
+ return deviceAdminPkgName;
+ }
+
+ /**
+ * Sends NFC bump to initiate device owner provisioning.
+ *
+ * @param context {@link Context} object.
+ * @param props {@link Properties} object contains NFC bump properties.
+ */
+ public static void sendNfcBump(Context context, Properties props) throws IOException {
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+
+ props.store(stream, "AFW NFC provisioning");
+ NdefRecord record = NdefRecord
+ .createMime(MIME_TYPE_PROVISIONING_NFC, stream.toByteArray());
+ NdefMessage ndfMsg = new NdefMessage(new NdefRecord[]{record});
+
+ Intent intent = new Intent(ACTION_NDEF_DISCOVERED);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setType(MIME_TYPE_PROVISIONING_NFC);
+ intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[]{ndfMsg});
+
+ context.startActivity(intent);
+ }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/Utils.java b/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/Utils.java
new file mode 100644
index 0000000..45fec51
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/Utils.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common.nfcprovisioning;
+
+import static com.android.afwtest.common.Constants.ACTION_SEND_NFC_BUMP;
+import static com.android.afwtest.common.Constants.KEY_DEVICE_ADMIN_PKG_NAME;
+import static com.android.afwtest.common.Constants.NFC_BUMP_FILE;
+import static com.android.afwtest.common.Constants.SYSTEM_UTIL_PKG_NAME;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+
+import com.android.afwtest.common.FileUtils;
+import com.android.afwtest.common.PkgMgrUtils;
+
+import java.util.Properties;
+
+/**
+ * NFC provisioning utils.
+ */
+public final class Utils {
+
+ /**
+ * Start provisioning by sending an intent to AfwTestSystemUtil app.
+ *
+ * @param context {@link Context} object
+ * @param nfcBumpFilePath path of the file containing the parameters to be sent in the Nfc bump
+ * @return expected device admin package name
+ */
+ public static String startProvisioning(Context context, String nfcBumpFilePath)
+ throws Exception {
+ // Find Device Admin Package name
+ Properties props = FileUtils.readPropertiesFromFile(nfcBumpFilePath);
+ if (!props.containsKey(KEY_DEVICE_ADMIN_PKG_NAME)) {
+ throw new RuntimeException(
+ KEY_DEVICE_ADMIN_PKG_NAME + " not specified in " + nfcBumpFilePath);
+ }
+
+ // Check if system util app is installed.
+ String deviceAdminPkgName = props.getProperty(KEY_DEVICE_ADMIN_PKG_NAME);
+ PackageManager pkgManager = context.getPackageManager();
+ if (!PkgMgrUtils.isPkgInstalled(context, SYSTEM_UTIL_PKG_NAME)) {
+ throw new RuntimeException(String.format("%s is not installed", SYSTEM_UTIL_PKG_NAME));
+ }
+
+ // Fire an intent to start nfc provisioning
+ Intent intent = new Intent(ACTION_SEND_NFC_BUMP);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(NFC_BUMP_FILE, nfcBumpFilePath);
+
+ context.startActivity(intent);
+
+ // Return the expected device admin package name
+ return deviceAdminPkgName;
+ }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/test/OemWidget.java b/libs/CommonLib/src/com/android/afwtest/common/test/OemWidget.java
new file mode 100644
index 0000000..bec3935
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/test/OemWidget.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common.test;
+
+import static com.android.afwtest.common.Constants.ACTION_CLICK;
+import static com.android.afwtest.common.Constants.KEY_OEM_WIDGET_ACTION;
+import static com.android.afwtest.common.Constants.KEY_OEM_WIDGET_CLASS;
+import static com.android.afwtest.common.Constants.KEY_OEM_WIDGET_DESCRIPTION;
+import static com.android.afwtest.common.Constants.KEY_OEM_WIDGET_PACKAGE;
+import static com.android.afwtest.common.Constants.KEY_OEM_WIDGET_RESOURCE_ID;
+import static com.android.afwtest.common.Constants.KEY_OEM_WIDGET_TEXT;
+
+import android.util.Log;
+
+import com.android.afwtest.common.Preconditions;
+
+/**
+ * A data class to store properties of an OEM widget.
+ */
+public final class OemWidget {
+
+ private static final String TAG = "afwtest.OemWidget";
+
+ // Id of the OEM widget.
+ private final String mId;
+
+ // Text property of this widget.
+ private final String mText;
+
+ // Description property of this widget.
+ private final String mDescription;
+
+ // Resource id of this widget.
+ private final String mResourceId;
+
+ // Package name of this widget.
+ private final String mPackage;
+
+ // Class name of this widget.
+ private final String mClass;
+
+ // Action of this widget, any of {@link com.android.afwtest.common.Constants#ACTION_CLICK},
+ // {@link com.android.afwtest.common.Constants#ACTION_CHECK} or
+ // {@link com.android.afwtest.common.Constants#ACTION_SCROLL}.
+ private final String mAction;
+
+ /**
+ * Constructs a {@link OemWidget} from configuration file.
+ *
+ * @param testConfig Path of the test configuration file
+ * @param widgetId id of the widget to construct.
+ */
+ public OemWidget(TestConfig testConfig, String widgetId) {
+ // Check Id.
+ Preconditions.checkNotEmpty(widgetId);
+
+ Log.d(TAG, "Creating OemWidget " + widgetId);
+
+ mId = widgetId;
+
+ mText = testConfig.getProperty(widgetId + "." + KEY_OEM_WIDGET_TEXT, "");
+ mDescription = testConfig.getProperty(widgetId + "." + KEY_OEM_WIDGET_DESCRIPTION, "");
+ mResourceId = testConfig.getProperty(widgetId + "." + KEY_OEM_WIDGET_RESOURCE_ID, "");
+ mPackage = testConfig.getProperty(widgetId + "." + KEY_OEM_WIDGET_PACKAGE, "");
+ mClass = testConfig.getProperty(widgetId + "." + KEY_OEM_WIDGET_CLASS, "");
+ mAction = testConfig.getProperty(widgetId + "." + KEY_OEM_WIDGET_ACTION, ACTION_CLICK);
+
+ // At least one property is specified.
+ Preconditions.checkNotEmpty(mText + mDescription + mResourceId + mPackage + mClass);
+
+ Log.d(TAG, "OemWidget: " + toString());
+ }
+
+ /**
+ * Gets id of this widget.
+ *
+ * @return id of this widget
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Gets text property of this widget.
+ *
+ * @return text property of this widget
+ */
+ public String getText() {
+ return mText;
+ }
+
+ /**
+ * Gets description property of this widget.
+ *
+ * @return description property of this widget
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * Gets resource id of this widget.
+ *
+ * @return resournce id of this widget
+ */
+ public String getResourceId() {
+ return mResourceId;
+ }
+
+ /**
+ * Gets package name of this widget.
+ *
+ * @return package name of this widget
+ */
+ public String getPackage() {
+ return mPackage;
+ }
+
+ /**
+ * Gets class name of this widget.
+ *
+ * @return class name of this widget
+ */
+ public String getClassName() {
+ return mClass;
+ }
+
+ /**
+ * Gets action of this widget.
+ *
+ * @return action of this widget
+ */
+ public String getAction() {
+ return mAction;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format(
+ "OemWidget[Id=%s,text=[%s],desc=[%s],res=[%s],pkg=[%s],class=[%s],action=[%s]]",
+ mId, mText, mDescription, mResourceId, mPackage, mClass, mAction);
+ }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/test/StatsLogger.java b/libs/CommonLib/src/com/android/afwtest/common/test/StatsLogger.java
new file mode 100644
index 0000000..6131f9d
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/test/StatsLogger.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common.test;
+
+import static android.os.Environment.getExternalStorageDirectory;
+
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Range;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Singleton class to measure and save time stats in a local file in External Storage Directory.
+ *
+ * <p>writeStatsToFile() should be called at the end of the test.</p>
+ */
+public final class StatsLogger {
+
+ private static final String TAG = "afwtest.StatsLogger";
+
+ // Map stats file with corresponding {@link StatsLogger} object.
+ private static Map<String, StatsLogger> sStasLogger = new HashMap<String, StatsLogger>();
+
+ // File to save stats.
+ private File mAfwStatsFile;
+
+ // Time stats being logged by this StatsLogger.
+ // The key of the map is the name of a metric.
+ private Map<String, Range<Long>> mTimeStats = new HashMap<String, Range<Long>>();
+
+ /**
+ * Constructor.
+ *
+ * @param fileName Path of the file to save stats
+ */
+ private StatsLogger(String fileName) throws IOException {
+ mAfwStatsFile = new File(getExternalStorageDirectory().getAbsolutePath(), fileName);
+
+ if (!mAfwStatsFile.exists()){
+ Log.d(TAG, String.format("%s does not exist, creating... ", fileName));
+ mAfwStatsFile.createNewFile();
+ }
+ }
+
+ /**
+ * Gets {@link StatsLogger} object for given file, or create a new one if does not exist.
+ *
+ * @param fileName file relative to external storage.
+ */
+ public static StatsLogger getInstance(String fileName) throws IOException {
+ if (sStasLogger.containsKey(fileName)){
+ return sStasLogger.get(fileName);
+ }
+
+ StatsLogger statsLogger = new StatsLogger(fileName);
+ sStasLogger.put(fileName, statsLogger);
+ return statsLogger;
+ }
+
+ /**
+ * Saves the stats to file.
+ */
+ public void writeStatsToFile() throws IOException {
+ FileOutputStream outputStream = new FileOutputStream(mAfwStatsFile);
+ String stats = toCsvFormatString(mTimeStats);
+
+ try {
+ outputStream.write(stats.getBytes());
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to write stats to file", e);
+ } finally {
+ outputStream.close();
+ }
+ }
+
+ /**
+ * Converts set of time stats to cvs formatted string.
+ *
+ * @param timeStats time stats to convert, the key of the map is time stats name
+ * @return String format:
+ * Key1,Key2,...\n
+ * Time1,Time2,...\n
+ */
+ private static String toCsvFormatString(Map<String, Range<Long>> timeStats) {
+ List<String> keyList = new ArrayList();
+ List<String> valueList = new ArrayList();
+ for (Map.Entry<String, Range<Long>> entry : timeStats.entrySet()) {
+ keyList.add(entry.getKey());
+ long interval = entry.getValue().getUpper() - entry.getValue().getLower();
+ valueList.add(String.format("%d", interval));
+ }
+ String keys = TextUtils.join(",", keyList);
+ String values = TextUtils.join(",", valueList);
+
+ return String.format("%s\n%s", keys, values);
+ }
+
+ /**
+ * Start counting time associated with the passed metric.
+ *
+ * @param keyName name of the metric to measure.
+ */
+ public void startTime(String keyName){
+ long currentTime = System.currentTimeMillis();
+ Range<Long> range = Range.create(currentTime, currentTime);
+ Log.d(TAG, String.format("%s start-time: %d", keyName, currentTime));
+
+ mTimeStats.put(keyName, range);
+ Log.d(TAG, String.format("HashMap for %s:%s", keyName, range.toString()));
+ }
+
+ /**
+ * Stops counting time associated with the given metric and return the period.
+ *
+ * @param keyName name of the metric to measure
+ * @return time between startTime and stopTime in milliseconds
+ */
+ public long stopTime(String keyName) throws Exception {
+ // Find the key
+ if (!mTimeStats.containsKey(keyName)) {
+ throw new RuntimeException(String.format("%s was never started", keyName));
+ }
+
+ // Set end time
+ Range<Long> range = mTimeStats.get(keyName).extend(System.currentTimeMillis());
+ mTimeStats.put(keyName, range);
+ Log.d(TAG, String.format("%s: %s", keyName, range.toString()));
+
+ return range.getUpper() - range.getLower();
+ }
+}
+
diff --git a/libs/CommonLib/src/com/android/afwtest/common/test/TestConfig.java b/libs/CommonLib/src/com/android/afwtest/common/test/TestConfig.java
new file mode 100644
index 0000000..a046eed
--- /dev/null
+++ b/libs/CommonLib/src/com/android/afwtest/common/test/TestConfig.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package com.android.afwtest.common.test;
+
+import static com.android.afwtest.common.Constants.KEY_APP_CRASH_WHITELIST;
+import static com.android.afwtest.common.Constants.KEY_DEVICE_ADMIN_PKG_CHECKSUM;
+import static com.android.afwtest.common.Constants.KEY_DEVICE_ADMIN_PKG_LOCATION;
+import static com.android.afwtest.common.Constants.KEY_DEVICE_ADMIN_PKG_NAME;
+import static com.android.afwtest.common.Constants.KEY_DEVICE_ADMIN_PKG_SIGNATURE_HASH;
+import static com.android.afwtest.common.Constants.KEY_MUTE_APP_CRASH_DIALOGS;
+import static com.android.afwtest.common.Constants.KEY_OEM_WIDGETS;
+import static com.android.afwtest.common.Constants.KEY_TEST_TIMEOUT_MIN;
+import static com.android.afwtest.common.Constants.KEY_TIMEOUT_SIZE;
+import static com.android.afwtest.common.Constants.KEY_WIFI_PWD;
+import static com.android.afwtest.common.Constants.KEY_WIFI_SECURITY_TYPE;
+import static com.android.afwtest.common.Constants.KEY_WIFI_SSID;
+import static com.android.afwtest.common.Constants.KEY_WORK_ACCOUNT_PASSWORD;
+import static com.android.afwtest.common.Constants.KEY_WORK_ACCOUNT_USERNAME;
+
+import android.util.Log;
+
+import com.android.afwtest.common.FileUtils;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * A singleton class that reads properties from afw-test.props and provides interfaces
+ * to get test configurations.
+ */
+public final class TestConfig {
+
+ private static final String TAG = "afwtest.TestConfig";
+
+ /**
+ * Mapping from timeout size to its integer value.
+ */
+ private static final Map<String, Integer> TIMEOUT_SIZE_MAPPING =
+ new HashMap<String, Integer>() {{
+ put("S", 2);
+ put("M", 3);
+ put("L", 5);
+ put("XL", 8);
+ put("XXL", 13);
+ }};
+
+ /**
+ * File path of the default test config file.
+ */
+ public static final String DEFAULT_TEST_CONFIG_FILE = "/data/local/tmp/afw-test.props";
+
+ // Mapping from test configuration file path and its loaded {@link TestConfig} object.
+ private static Map<String, TestConfig> sTestConfigs = new HashMap<String, TestConfig>();
+
+ // Store configurations loaded from a file.
+ private final Properties mProps;
+
+ /**
+ * Creates a new object by loading configurations from file.
+ *
+ * @param configFilePath path of the test configuration file
+ */
+ private TestConfig(String configFilePath) throws IOException {
+ mProps = FileUtils.readPropertiesFromFile(configFilePath);
+ }
+
+ /**
+ * Gets {@link TestConfig} object for given file path.
+ *
+ * @param configFilePath file path of the test configuration
+ * @return {@link TestConfig} object for given file path
+ */
+ public static TestConfig get(String configFilePath) throws IOException {
+ if (sTestConfigs.containsKey(configFilePath)) {
+ return sTestConfigs.get(configFilePath);
+ }
+
+ // Create new object.
+ TestConfig testConfig = new TestConfig(configFilePath);
+ sTestConfigs.put(configFilePath, testConfig);
+ return testConfig;
+ }
+
+ /**
+ * Gets {@link TestConfig} object for {@link #DEFAULT_TEST_CONFIG_FILE}.
+ *
+ * @return {@link TestConfig} object for {@link #DEFAULT_TEST_CONFIG_FILE}
+ */
+ public static TestConfig getDefault() throws IOException {
+ return get(DEFAULT_TEST_CONFIG_FILE);
+ }
+
+ /**
+ * Gets device admin package name.
+ *
+ * @return device admin package name
+ */
+ public String getDeviceAdminPkgName() {
+ return mProps.getProperty(KEY_DEVICE_ADMIN_PKG_NAME);
+ }
+
+ /**
+ * Gets device admin package name.
+ *
+ * @param defaultValue default value if device admin pkg name is not found
+ * @return device admin package name
+ */
+ public String getDeviceAdminPkgName(String defaultValue) {
+ return mProps.getProperty(KEY_DEVICE_ADMIN_PKG_NAME, defaultValue);
+ }
+
+ /**
+ * Gets device admin package location.
+ *
+ * @return device admin package location
+ */
+ public String getDeviceAdminPkgLocation() {
+ return mProps.getProperty(KEY_DEVICE_ADMIN_PKG_LOCATION);
+ }
+
+ /**
+ * Gets device admin package location.
+ *
+ * @param defaultValue default value if device admin package location is not found
+ * @return device admin package location
+ */
+ public String getDeviceAdminPkgLocation(String defaultValue) {
+ return mProps.getProperty(KEY_DEVICE_ADMIN_PKG_LOCATION, defaultValue);
+ }
+
+ /**
+ * Gets device admin package checksum.
+ *
+ * @return device admin package checksum
+ */
+ public String getDeviceAdminPkgChecksum() {
+ return mProps.getProperty(KEY_DEVICE_ADMIN_PKG_CHECKSUM);
+ }
+
+ /**
+ * Gets device admin package checksum.
+ *
+ * @param defaultValue default valud if device admin package checksum is not found
+ * @return device admin package checksum
+ */
+ public String getDeviceAdminPkgChecksum(String defaultValue) {
+ return mProps.getProperty(KEY_DEVICE_ADMIN_PKG_CHECKSUM, defaultValue);
+ }
+
+ /**
+ * Gets device admin package signature hash.
+ *
+ * @return device admin package signature hash
+ */
+ public String getDeviceAdminPkgSignatureHash() {
+ return mProps.getProperty(KEY_DEVICE_ADMIN_PKG_SIGNATURE_HASH);
+ }
+
+ /**
+ * Gets device admin package signature hash.
+ *
+ * @param defaultValue default value if device admin package signature hash is not found
+ * @return device admin package signature hash
+ */
+ public String getDeviceAdminPkgSignatureHash(String defaultValue) {
+ return mProps.getProperty(KEY_DEVICE_ADMIN_PKG_SIGNATURE_HASH, defaultValue);
+ }
+
+ /**
+ * Gets timeout size value from props file.
+ *
+ * <p>
+ * Possible size values are strings "S", "M", "L", "XL" or "XXL".
+ * </p>
+ *
+ * @return An integer corresponding to the timeout size configured in the config file.
+ */
+ public int getTimeoutSize() {
+ // Default to M
+ String timeoutSize = getProperty(KEY_TIMEOUT_SIZE, "M");
+ if (!TIMEOUT_SIZE_MAPPING.containsKey(timeoutSize)) {
+ Log.w(TAG, "Invalid timeout size, defaulting to M");
+ timeoutSize = "M";
+ }
+
+ return TIMEOUT_SIZE_MAPPING.get(timeoutSize);
+ }
+
+ /**
+ * Gets test timeout in minutes.
+ *
+ * @return test timeout in minutes or -1 if either timeout is not specified or invalid
+ */
+ public int getTestTimeoutMin() {
+ return getTestTimeoutMin(-1);
+ }
+
+ /**
+ * Gets test timeout in minutes.
+ *
+ * @param defaultValue default value if test timeout not specified
+ * @return test timeout in minutes
+ */
+ public int getTestTimeoutMin(int defaultValue) {
+ String value = mProps.getProperty(KEY_TEST_TIMEOUT_MIN);
+ if (value == null || value.isEmpty()) {
+ return defaultValue;
+ }
+
+ return Integer.valueOf(value);
+ }
+
+ /**
+ * Gets Wifi SSID.
+ *
+ * @return Wifi SSID
+ */
+ public String getWifiSsid() {
+ return mProps.getProperty(KEY_WIFI_SSID);
+ }
+
+ /**
+ * Gets Wifi SSID.
+ *
+ * @param defaultValue default value if Wifi SSID is not found
+ * @return Wifi SSID
+ */
+ public String getWifiSsid(String defaultValue) {
+ return mProps.getProperty(KEY_WIFI_SSID, defaultValue);
+ }
+
+ /**
+ * Gets Wifi password.
+ *
+ * @return Wifi password
+ */
+ public String getWifiPassword() {
+ return mProps.getProperty(KEY_WIFI_PWD);
+ }
+
+ /**
+ * Gets Wifi password.
+ *
+ * @param defaultValue default value if Wifi password is not found
+ * @return Wifi password
+ */
+ public String getWifiPassword(String defaultValue) {
+ return mProps.getProperty(KEY_WIFI_PWD, defaultValue);
+ }
+
+ /**
+ * Gets Wifi security type.
+ *
+ * @return Wifi security type
+ */
+ public String getWifiSecurityType() {
+ return mProps.getProperty(KEY_WIFI_SECURITY_TYPE);
+ }
+
+ /**
+ * Gets Wifi security type.
+ *
+ * @param defaultValue default value if Wifi security type is not found
+ * @return Wifi security type
+ */
+ public String getWifiSecurityType(String defaultValue) {
+ return mProps.getProperty(KEY_WIFI_SECURITY_TYPE, defaultValue);
+ }
+
+ /**
+ * Gets work account user name.
+ *
+ * @return work account user name
+ */
+ public String getWorkAccountUsername() {
+ return mProps.getProperty(KEY_WORK_ACCOUNT_USERNAME);
+ }
+
+ /**
+ * Gets work account user name.
+ *
+ * @param defaultValue default value if work account user name is not found
+ * @return work account user name
+ */
+ public String getWorkAccountUsername(String defaultValue) {
+ return mProps.getProperty(KEY_WORK_ACCOUNT_USERNAME, defaultValue);
+ }
+
+ /**
+ * Gets work account password.
+ *
+ * @return work account password
+ */
+ public String getWorkAccountPassword() {
+ return mProps.getProperty(KEY_WORK_ACCOUNT_PASSWORD);
+ }
+
+ /**
+ * Gets work account password.
+ *
+ * @param defaultValue default value if work account password is not found
+ * @return work account password
+ */
+ public String getWorkAccountPassword(String defaultValue) {
+ return mProps.getProperty(KEY_WORK_ACCOUNT_PASSWORD, defaultValue);
+ }
+
+ /**
+ * Gets the property of a specific key.
+ *
+ * @param key property key
+ * @return property value of the given key
+ * If the key doesn't exist in the configuration file, null will be returned;
+ * If the value of the key is empty, empty string will be returned
+ */
+ public String getProperty(String key) {
+ return mProps.getProperty(key);
+ }
+
+ /**
+ * Gets the property of a specific key.
+ *
+ * @param key property key
+ * @param defaultValue default value if given key is not found
+ * @return property value of the given key;
+ * if given key not found, {@link #defaultValue} is returned
+ */
+ public String getProperty(String key, String defaultValue) {
+ return mProps.getProperty(key, defaultValue);
+ }
+
+ /**
+ * Gets the OEM widgets as a list.
+ *
+ * @return {@link List} of {@link OemWidget}
+ */
+ public List<OemWidget> getOemWidgets() {
+ List<OemWidget> oemWidgets = new LinkedList<OemWidget>();
+
+ String idList = mProps.getProperty(KEY_OEM_WIDGETS, "");
+ if (!idList.isEmpty()) {
+ String[] ids = idList.split(",");
+ for (String id : ids) {
+ OemWidget oemWidget = new OemWidget(this, id);
+ oemWidgets.add(oemWidget);
+ }
+ }
+
+ return oemWidgets;
+ }
+
+ /**
+ * Whether to mute app crash dialogs.
+ *
+ * @return {@code true} if yes, {@code false} otherwise
+ */
+ public boolean muteAppCrashDialogs() {
+ return Boolean.parseBoolean(mProps.getProperty(KEY_MUTE_APP_CRASH_DIALOGS, "true"));
+ }
+
+ /**
+ * Gets list of app names that if they crash, just auto close the dialog.
+ *
+ * @return set of app names that in the app crash dialog message, all in lower case
+ */
+ public List<String> getAppCrashWhitelist() {
+ String[] apps = getProperty(KEY_APP_CRASH_WHITELIST, "").split(",");
+ List<String> results = new LinkedList(Arrays.asList(apps));
+ results.removeAll(Arrays.asList("", null));
+ return results;
+ }
+}