Import AfwThSystemUtil module

Change-Id: I45cf7055face09b2795ec4837d2e82de5f7dc5c7
diff --git a/apps/Android.mk b/apps/Android.mk
new file mode 100644
index 0000000..6801acf
--- /dev/null
+++ b/apps/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/apps/DeviceAdmin/Android.mk b/apps/DeviceAdmin/Android.mk
index 8a154d9..a107fbe 100644
--- a/apps/DeviceAdmin/Android.mk
+++ b/apps/DeviceAdmin/Android.mk
@@ -22,7 +22,7 @@
 
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_STATIC_JAVA_LIBRARIES := AfwTestCommonLib
+LOCAL_STATIC_JAVA_LIBRARIES := AfwThCommonLib
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
@@ -30,4 +30,4 @@
 
 LOCAL_SDK_VERSION := 22
 
-include $(BUILD_AFW_TEST_SUPPORT_PACKAGE)
+include $(BUILD_AFW_TH_SUPPORT_PACKAGE)
diff --git a/apps/SystemUtil/Android.mk b/apps/SystemUtil/Android.mk
new file mode 100644
index 0000000..2ea02ab
--- /dev/null
+++ b/apps/SystemUtil/Android.mk
@@ -0,0 +1,33 @@
+#
+# 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_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_STATIC_JAVA_LIBRARIES := AfwThCommonLib
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := AfwThSystemUtil
+
+LOCAL_SDK_VERSION := 22
+
+include $(BUILD_AFW_TH_SUPPORT_PACKAGE)
diff --git a/apps/SystemUtil/AndroidManifest.xml b/apps/SystemUtil/AndroidManifest.xml
new file mode 100644
index 0000000..0d0436b
--- /dev/null
+++ b/apps/SystemUtil/AndroidManifest.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.android.afwtest.systemutil" >
+
+    <uses-sdk android:minSdkVersion="22" />
+
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION"/>
+    <uses-permission android:name="android.permission.DISPATCH_NFC_MESSAGE" />
+    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
+    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
+
+    <instrumentation
+            android:name=".RemoveGoogleAccount"
+            android:label="Remove Google Account"
+            android:targetPackage="com.android.afwtest.systemutil" >
+    </instrumentation>
+
+    <instrumentation
+            android:name=".ChangeLocale"
+            android:label="Change the device locale"
+            android:targetPackage="com.android.afwtest.systemutil" >
+    </instrumentation>
+
+    <application android:label="Afw Test Harness System Util">
+        <!-- NFC Bump Sender activity -->
+        <activity
+                android:name="com.android.afwtest.systemutil.NfcBumpSender"
+                android:label="NFC Bump Sender" >
+            <intent-filter>
+                <action android:name="com.android.afwtest.systemutil.action.SEND_NFC_BUMP" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/apps/SystemUtil/README b/apps/SystemUtil/README
new file mode 100644
index 0000000..fc4e3a0
--- /dev/null
+++ b/apps/SystemUtil/README
@@ -0,0 +1,34 @@
+- About
+
+  System util app. It must be pushed to /system/priv-app on the device.
+  Requires a device where 'adb root' is possible, typically a userdebug build.
+
+- Build & Install:
+
+  make AfwThSystemUtil
+  adb root
+  adb remount
+  adb push AfwThSystemUtil.apk /system/priv-app
+  adb reboot
+
+- Usage
+
+  - Remove all Google accounts:
+    adb shell am instrument -w com.android.afwtest.systemutil/.RemoveGoogleAccount
+
+  - Remove a Google account:
+    adb shell am instrument \
+       -w -e account accountName com.android.afwtest.systemutil/.RemoveGoogleAccount
+
+  - Change system locale
+     adb shell am instrument \
+       -w -e locale locale_code com.android.afwtest.systemutil/.ChangeLocale
+
+  - locale_code can be language code only or languageCode_COUNTRYCODE, e.g. en, en_US, en_UK, zh_CN.
+
+  - Simulate a NFC bump
+    Configure the parameters you would like to be sent in the nfc bump by editing afw-test.props
+
+      adb push afw-test.props /data/local/tmp/afw-test.props
+      adb shell am start -n com.android.afwtest.systemutil/.NfcBumpSender
+                         -e NFCBumpFile "/data/local/tmp/afw-test.props"
diff --git a/apps/SystemUtil/src/com/android/afwtest/systemutil/ChangeLocale.java b/apps/SystemUtil/src/com/android/afwtest/systemutil/ChangeLocale.java
new file mode 100644
index 0000000..038c1f4
--- /dev/null
+++ b/apps/SystemUtil/src/com/android/afwtest/systemutil/ChangeLocale.java
@@ -0,0 +1,111 @@
+/*
+ * 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.systemutil;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Locale;
+
+/**
+ * Change the system locale.
+ **/
+public class ChangeLocale extends Instrumentation {
+    private static final String TAG = "afwtest.ChangeLocale";
+
+    // Locale code, expecting something like: en, en_US, en_UK, zh, zh_CN, zh_TW.
+    private String mLocale;
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+        mLocale = arguments.getString("locale", "");
+        start();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        // Locale must be specified.
+        if (mLocale.isEmpty()) {
+            handleError("Locale is not specified");
+            return;
+        }
+
+        Log.i(TAG, String.format("Attempting to change locale to %s", mLocale));
+
+        try {
+            // It could be en_US or en.
+            final String[] codes = mLocale.split("_");
+            final Locale locale =
+                    codes.length > 1 ? new Locale(codes[0], codes[1]) : new Locale(codes[0]);
+
+            // Change locale through reflection.
+            Class amnClass = Class.forName("android.app.ActivityManagerNative");
+            Method getDefault = amnClass.getMethod("getDefault");
+            getDefault.setAccessible(true);
+            Object amn = getDefault.invoke(amnClass);
+
+            Method getConfig = amnClass.getMethod("getConfiguration");
+            getConfig.setAccessible(true);
+            Configuration config = (Configuration) getConfig.invoke(amn);
+
+            Field field = config.getClass().getField("userSetLocale");
+            field.setBoolean(config, true);
+
+            // Set new locale.
+            config.locale = locale;
+
+            // Update configuration.
+            Method updateConfig = amnClass.getMethod("updateConfiguration", Configuration.class);
+            updateConfig.setAccessible(true);
+            updateConfig.invoke(amn, config);
+
+            // Success
+            Bundle results = new Bundle();
+            results.putString("result", "SUCCESS");
+            finish(Activity.RESULT_OK, results);
+        } catch (Exception e) {
+            Log.e(TAG, "Failed to change locale", e);
+            handleError(String.format("Failed to change locale: %s", e));
+        }
+    }
+
+    /**
+     * Handles error by exiting instrumentation.
+     *
+     * @param errorMsg error msg
+     */
+    private void handleError(String errorMsg) {
+        Bundle results = new Bundle();
+        results.putString("error", errorMsg);
+        finish(Activity.RESULT_CANCELED, results);
+    }
+
+}
diff --git a/apps/SystemUtil/src/com/android/afwtest/systemutil/NfcBumpSender.java b/apps/SystemUtil/src/com/android/afwtest/systemutil/NfcBumpSender.java
new file mode 100644
index 0000000..636d537
--- /dev/null
+++ b/apps/SystemUtil/src/com/android/afwtest/systemutil/NfcBumpSender.java
@@ -0,0 +1,61 @@
+/*
+ * 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.systemutil;
+
+import static com.android.afwtest.common.Constants.NFC_BUMP_FILE;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.io.IOException;
+
+import com.android.afwtest.common.nfcprovisioning.NfcBumpSimulator;
+
+/**
+ * Activity to send a nfc bump.
+ */
+public class NfcBumpSender extends Activity {
+
+    private static final String TAG = "afwtest.NfcBumpSender";
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        try {
+            Intent intent = getIntent();
+            // Gets the path of the file that containing the parameters to be sent
+            // in the nfc bump.
+            if (intent.hasExtra(NFC_BUMP_FILE)) {
+                String bumpFileLocation = getIntent().getStringExtra(NFC_BUMP_FILE);
+                NfcBumpSimulator.sendNfcBump(this, bumpFileLocation);
+                Log.d(TAG, String.format("%s=%s", NFC_BUMP_FILE, bumpFileLocation));
+            } else {
+                Log.e(TAG, String.format("Nfc bump not sent."
+                        + "Intent doesn't contain extra %s.", NFC_BUMP_FILE));
+            }
+        } catch (IOException e) {
+            Log.e(TAG, "Failed to send Nfc Bump", e);
+        }
+        finish();
+    }
+}
diff --git a/apps/SystemUtil/src/com/android/afwtest/systemutil/RemoveGoogleAccount.java b/apps/SystemUtil/src/com/android/afwtest/systemutil/RemoveGoogleAccount.java
new file mode 100644
index 0000000..dc57c1d
--- /dev/null
+++ b/apps/SystemUtil/src/com/android/afwtest/systemutil/RemoveGoogleAccount.java
@@ -0,0 +1,151 @@
+/*
+ * 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.systemutil;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.concurrent.Semaphore;
+
+/**
+ * An instrumentation utility to remove Google account from device.
+ */
+public class RemoveGoogleAccount extends Instrumentation {
+
+    private static final String TAG = "afwtest.RemoveGoogleAccount";
+
+    // Account to remove; remove all Google accounts if null.
+    private String mAccount;
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+        mAccount = arguments.getString("account", null);
+        start();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        Log.d(TAG, "Attempting to remove Google accounts");
+        Bundle results = new Bundle();
+
+        AccountManager accountManager = AccountManager.get(getContext());
+        Account[] accounts = accountManager.getAccountsByType("com.google");
+        for (Account account : accounts) {
+            if (mAccount == null || account.name.equals(mAccount)) {
+                Log.i(TAG, String.format("Removing account %s", account.name));
+                RemoveCallback callback = new RemoveCallback();
+                accountManager.removeAccount(account, callback, null /* handler */);
+                if (!callback.waitForRemoveCompletion()) {
+                    String error = String.format("Failed to remove account %s: Reason: %s",
+                            account.name, callback.getErrorMessage());
+                    results.putString("error", error);
+                    finish(Activity.RESULT_CANCELED, results);
+                    return;
+                }
+            }
+        }
+        results.putString("result", "SUCCESS");
+        finish(Activity.RESULT_OK, results);
+    }
+
+    /**
+     * Callback which will block until account removal result is available or exception throws.
+     */
+    private static class RemoveCallback implements AccountManagerCallback<Boolean> {
+
+        private static final String TAG = "afwtest.RemoveCallback";
+
+        /**
+         * Stores the result of account removal.
+         */
+        private boolean mResult = false;
+
+        /**
+         * Error message if any.
+         */
+        private String mErrorMessage = null;
+
+        /**
+         * {@link Semaphore}, indicating result is available if it's value > 0.
+         */
+        private Semaphore mLock = new Semaphore(0);
+
+        /**
+         * Block and wait for the remove callback to complete.
+         *
+         * @return the {@link Bundle} result from the remove op.
+         */
+
+        public Boolean waitForRemoveCompletion() {
+            try {
+                // Blocks until semaphore count > 0
+                mLock.acquire();
+            } catch (InterruptedException e) {
+                handleException(e);
+            }
+            return mResult;
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public void run(AccountManagerFuture<Boolean> future) {
+            try {
+                mResult = future.getResult();
+            } catch (OperationCanceledException | IOException | AuthenticatorException e) {
+                handleException(e);
+            } finally {
+                // Increment semaphore count by 1.
+                mLock.release();
+            }
+        }
+
+        /**
+         * Gets the error message.
+         *
+         * @return error message
+         */
+        public String getErrorMessage() {
+            return mErrorMessage;
+        }
+
+        /**
+         * Creates a result bundle for given exception
+         */
+        private void handleException(Exception e) {
+            Log.e(TAG, "Failed to remove account", e);
+            mResult = false;
+            mErrorMessage = e.toString();
+        }
+    }
+}
diff --git a/libs/CommonLib/src/com/android/afwtest/common/Constants.java b/libs/CommonLib/src/com/android/afwtest/common/Constants.java
index b708037..de50839 100644
--- a/libs/CommonLib/src/com/android/afwtest/common/Constants.java
+++ b/libs/CommonLib/src/com/android/afwtest/common/Constants.java
@@ -164,13 +164,13 @@
     /**
      * Package name of system util app.
      */
-    public static final String SYSTEM_UTIL_PKG_NAME = "com.google.android.afwtest.systemutil";
+    public static final String SYSTEM_UTIL_PKG_NAME = "com.android.afwtest.systemutil";
 
     /**
      * Send NFC bump action.
      */
     public static final String ACTION_SEND_NFC_BUMP
-            = "com.google.android.afwtest.systemutil.action.SEND_NFC_BUMP";
+            = "com.android.afwtest.systemutil.action.SEND_NFC_BUMP";
 
     /**
      * Private constructor to prevent instantiation.
diff --git a/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/NfcBumpSimulator.java b/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/NfcBumpSimulator.java
index 44e2505..d38a997 100644
--- a/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/NfcBumpSimulator.java
+++ b/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/NfcBumpSimulator.java
@@ -56,7 +56,7 @@
      * @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 {
+    public static String sendNfcBump(Context context, String propsConfigFile) throws IOException {
 
         TestConfig testConfig = TestConfig.get(propsConfigFile);
 
diff --git a/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/Utils.java b/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/Utils.java
index 45fec51..810846a 100644
--- a/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/Utils.java
+++ b/libs/CommonLib/src/com/android/afwtest/common/nfcprovisioning/Utils.java
@@ -36,7 +36,7 @@
 public final class Utils {
 
     /**
-     * Start provisioning by sending an intent to AfwTestSystemUtil app.
+     * Start provisioning by sending an intent to AfwThSystemUtil app.
      *
      * @param context {@link Context} object
      * @param nfcBumpFilePath path of the file containing the parameters to be sent in the Nfc bump
diff --git a/libs/UiAutomatorLib/src/com/android/afwtest/uiautomator/Constants.java b/libs/UiAutomatorLib/src/com/android/afwtest/uiautomator/Constants.java
index 51e3101..5bb5bcf 100644
--- a/libs/UiAutomatorLib/src/com/android/afwtest/uiautomator/Constants.java
+++ b/libs/UiAutomatorLib/src/com/android/afwtest/uiautomator/Constants.java
@@ -35,7 +35,7 @@
     public static final String ANDROID_PKG_NAME = "android";
 
     /**
-     * GMSCore Pakcage name.
+     * GMSCore package name.
      */
     public static final String GMS_PKG_NAME = "com.google.android.gms";