diff options
author | Jinhui Wang <jinhuiw@google.com> | 2016-06-07 18:38:00 -0700 |
---|---|---|
committer | Jinhui Wang <jinhuiw@google.com> | 2016-06-10 09:16:53 -0700 |
commit | dc65dc058699a68bfa8f5f0fc1b031125137db43 (patch) | |
tree | a7f35ad46548b05433743afff4d52800a6bc2b7e | |
parent | 03597fd71c63bbdd361685fdd264199a3fbea4bc (diff) | |
download | AfwTestHarness-dc65dc058699a68bfa8f5f0fc1b031125137db43.tar.gz |
Import AfwThCommonLib module
Change-Id: I0e6298bd72a026b61ddde7ca513e5bb26adfc8db
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; + } +} |