diff options
author | Jinhui Wang <jinhuiw@google.com> | 2016-08-19 18:26:13 -0700 |
---|---|---|
committer | Jinhui Wang <jinhuiw@google.com> | 2016-08-24 10:35:10 -0700 |
commit | 92acce1a02118d0b0468b01a486fa3ccc757c61e (patch) | |
tree | f5037d9f3879803455cbc2c72b2b551f985c2dfe | |
parent | 22d065954bcdd50f2e1054a5e53aa486317d81a3 (diff) | |
download | AfwTestHarness-92acce1a02118d0b0468b01a486fa3ccc757c61e.tar.gz |
Make test harness support WEP wifi
Created and util app to connect wifi.
Update AfwTesWifiPreparer to connect WEP wifi with the util app.
Change-Id: I01ef074323600a1b7a0f84b404d388355989c566
14 files changed, 825 insertions, 17 deletions
diff --git a/AfwTestCaseList.mk b/AfwTestCaseList.mk index adae60f..ea16169 100644 --- a/AfwTestCaseList.mk +++ b/AfwTestCaseList.mk @@ -24,7 +24,8 @@ afw_th_test_packages := \ # Support packages afw_th_support_packages := \ AfwThDeviceAdmin \ - AfwThSystemUtil + AfwThSystemUtil \ + AfwThUtil # All the test case apk files that will end up under the repository/testcases diff --git a/apps/Util/Android.mk b/apps/Util/Android.mk new file mode 100644 index 0000000..89742c4 --- /dev/null +++ b/apps/Util/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 := AfwThUtil + +LOCAL_SDK_VERSION := 22 + +include $(BUILD_AFW_TEST_SUPPORT_PACKAGE) diff --git a/apps/Util/AndroidManifest.xml b/apps/Util/AndroidManifest.xml new file mode 100644 index 0000000..f270fcc --- /dev/null +++ b/apps/Util/AndroidManifest.xml @@ -0,0 +1,34 @@ +<?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.util" > + + <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> + <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> + <uses-permission android:name="android.permission.INTERNET" /> + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> + + <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="22" /> + + <instrumentation android:name=".Wifi" + android:targetPackage="com.android.afwtest.util" + android:label="Afw Test Harness Utility App"> + </instrumentation> + + <application android:label="Afw Test Harness Util"> + </application> +</manifest> diff --git a/apps/Util/README.txt b/apps/Util/README.txt new file mode 100644 index 0000000..8d17880 --- /dev/null +++ b/apps/Util/README.txt @@ -0,0 +1,17 @@ +- About + + Common util app that works on user builds. + +- Usage: connect a wifi + + adb shell am instrument -w -e action connect \ + -e ssid <ssid> -e security_type <security_type> -e password <password> \ + com.android.afwtest.util/.Wifi + + security_type could be WPA, WEP or NONE. Default to be NONE if no password is specified; default + to be WPA if password is given. + +- Usage: disconnect from wifi + + adb shell am instrument -w -e action disconnect com.android.afwtest.util/.Wifi + diff --git a/apps/Util/src/com/android/afwtest/util/NetworkMonitor.java b/apps/Util/src/com/android/afwtest/util/NetworkMonitor.java new file mode 100644 index 0000000..b432549 --- /dev/null +++ b/apps/Util/src/com/android/afwtest/util/NetworkMonitor.java @@ -0,0 +1,98 @@ +/* + * 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.util; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.util.Log; + +import com.android.afwtest.common.NetworkUtils; + +/** + * Monitor the state of the data network. Invoke a callback when the network is connected + */ +public class NetworkMonitor { + private static final String TAG = "afwtest.NetworkMonitor"; + + /** State notification callback. Expect some duplicate notifications. */ + public interface Callback { + /** Notify on network connected. */ + void onNetworkConnected(); + /** Notify on network disconnected. */ + void onNetworkDisconnected(); + } + + /** Application context. */ + private final Context mContext; + + /** Registered callback that is listening to network events. */ + private final Callback mCallback; + + /** Whether receiver is registered. */ + private boolean mReceiverRegistered; + + /** + * Start watching the network and monitoring the checkin service. Immediately invokes one of the + * callback methods to report the current state, and then invokes callback methods over time as + * the state changes. + * + * @param context to use for intent observers and such + * @param callback to invoke when the network status changes + */ + public NetworkMonitor(Context context, Callback callback) { + mContext = context; + mCallback = callback; + + IntentFilter filter = new IntentFilter(); + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); + + context.registerReceiver(mBroadcastReceiver, filter); + + mReceiverRegistered = true; + } + + /** + * Stop watching the network and checkin service. + */ + public synchronized void close() { + if (mReceiverRegistered) { + mContext.unregisterReceiver(mBroadcastReceiver); + mReceiverRegistered = false; + } + } + + /** + * Broadcast receiver. + */ + public final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + Log.i(TAG, String.format("onReceive: %s", intent.toString())); + + if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { + if (NetworkUtils.isConnectedToWifi(context)) { + mCallback.onNetworkConnected(); + } else { + mCallback.onNetworkDisconnected(); + } + } + } + }; +} diff --git a/apps/Util/src/com/android/afwtest/util/Wifi.java b/apps/Util/src/com/android/afwtest/util/Wifi.java new file mode 100644 index 0000000..e55ab40 --- /dev/null +++ b/apps/Util/src/com/android/afwtest/util/Wifi.java @@ -0,0 +1,133 @@ +/* + * 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.util; + +import android.app.Activity; +import android.app.Instrumentation; +import android.os.Bundle; +import android.util.Log; + +import com.android.afwtest.common.NetworkUtils; + +/** + * Adds a wifi network to system. + */ +public class Wifi extends Instrumentation { + + private static final String TAG = "afwtest.Wifi"; + + private static final String ACTION_CONNECT = "connect"; + private static final String ACTION_DISCONNECT = "disconnect"; + + /** Supported actions: connect, disconnect*/ + private String mAction; + + private String mSSID, mSecurityType, mPassword; + + /** + * {@inheritDoc} + */ + @Override + public void onCreate(Bundle arguments) { + super.onCreate(arguments); + mAction = arguments.getString("action", ""); + mSSID = arguments.getString("ssid", ""); + if (!mSSID.startsWith("\"") || !mSSID.endsWith("\"")) { + mSSID = String.format("\"%s\"", mSSID); + } + mSecurityType = arguments.getString("security_type", ""); + mPassword = arguments.getString("password", ""); + start(); + } + + /** + * {@inheritDoc} + */ + @Override + public void onStart() { + // Handle connect action + if (ACTION_CONNECT.equals(mAction)) { + handleConnect(); + } else if (ACTION_DISCONNECT.equals(mAction)) { + handleDisconnect(); + } else { + handleError(String.format("Invalid action: %s", mAction)); + } + } + + /** + * Handles connecting wifi request. + */ + private void handleConnect() { + if (!NetworkUtils.enableWifi(getContext())) { + handleError("Failed to enable wifi."); + } + + // If the expected wifi is already connected, return. + if (NetworkUtils.isConnectedToSpecifiedWifi(getContext(), mSSID)) { + Log.i(TAG, String.format("Wifi already connected: %s (%s)", mSSID, mSecurityType)); + handleSuccess(); + } else { + WifiConnector wifiConnector = new WifiConnector(getContext(), + mSSID, + mSecurityType, + mPassword); + if (wifiConnector.connect()) { + Log.i(TAG, String.format("Connected to wifi: %s (%s)", mSSID, mSecurityType)); + handleSuccess(); + } else { + handleError(String. + format("Failed to connect to wifi: %s (%s)", mSSID, mSecurityType)); + } + } + } + + /** + * Handles wifi disconnecting request. + * + * Handled by removing all configured networks. + */ + private void handleDisconnect() { + if (!NetworkUtils.disconnectFromWifi(getContext())) { + handleError("Failed to disconnect from Wifi"); + } else { + Log.i(TAG, "Wifi disconnected."); + handleSuccess(); + } + } + + /** + * Handles error by exiting instrumentation. + * + * @param errorMsg error msg + */ + private void handleError(String errorMsg) { + Log.i(TAG, errorMsg); + Bundle results = new Bundle(); + results.putString("error", errorMsg); + finish(Activity.RESULT_CANCELED, results); + } + + /** + * Handles success execution + */ + private void handleSuccess() { + Bundle results = new Bundle(); + results.putString("result", "SUCCESS"); + finish(Activity.RESULT_OK, results); + } +}
\ No newline at end of file diff --git a/apps/Util/src/com/android/afwtest/util/WifiConfig.java b/apps/Util/src/com/android/afwtest/util/WifiConfig.java new file mode 100644 index 0000000..f49d710 --- /dev/null +++ b/apps/Util/src/com/android/afwtest/util/WifiConfig.java @@ -0,0 +1,145 @@ +/* + * 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.util; + +import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiManager; +import android.text.TextUtils; +import android.util.Log; + +import java.util.Locale; + +/** + * Utility class for configuring a new WiFi network. + */ +public final class WifiConfig { + + private static final String TAG = "afwtest.WifiConfig"; + + /** Security type enum. */ + enum SecurityType { + NONE, + WPA, + WEP + } + + /** {@link WifiManager} instance. */ + private final WifiManager mWifiManager; + + /** + * Constructor. + * + * @param manager {@link WifiManager} object + */ + public WifiConfig(WifiManager manager) { + mWifiManager = manager; + } + + /** + * Adds a new WiFi network. + * + * @param ssid Wifi SSID + * @param type Wifi security type + * @param password Wifi password + * @return the ID of the newly created network description. Returns -1 on failure. + */ + public int addNetwork(String ssid, String type, String password) { + WifiConfiguration wifiConf = new WifiConfiguration(); + SecurityType securityType; + if (type == null || TextUtils.isEmpty(type)) { + securityType = SecurityType.NONE; + } else { + try { + securityType = Enum.valueOf(SecurityType.class, type.toUpperCase(Locale.US)); + } catch (IllegalArgumentException e) { + Log.e(TAG, String.format("Invalid Wifi security type: %s", type)); + return -1; + } + } + // If we have a password, and no security type, assume WPA. + if (securityType.equals(SecurityType.NONE) && !TextUtils.isEmpty(password)) { + securityType = SecurityType.WPA; + } + + wifiConf.SSID = ssid; + wifiConf.status = WifiConfiguration.Status.ENABLED; + switch (securityType) { + case NONE: + wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); + break; + case WPA: + updateForWPAConfiguration(wifiConf, password); + break; + case WEP: + updateForWEPConfiguration(wifiConf, password); + break; + } + + int netId = mWifiManager.addNetwork(wifiConf); + + if (netId != -1) { + // Setting disableOthers to 'true' should trigger a connection attempt. + mWifiManager.enableNetwork(netId, true); + mWifiManager.saveConfiguration(); + } + + return netId; + } + + /** + * Updates WAP Wifi configuration. + * + * @param wifiConf {@link WifiConfiguration} object to update + * @param password Wifi password + */ + protected void updateForWPAConfiguration(WifiConfiguration wifiConf, String password) { + wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); + wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); + wifiConf.allowedProtocols.set(WifiConfiguration.Protocol.WPA); // For WPA + wifiConf.allowedProtocols.set(WifiConfiguration.Protocol.RSN); // For WPA2 + wifiConf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); + wifiConf.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); + wifiConf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); + wifiConf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); + if (!TextUtils.isEmpty(password)) { + wifiConf.preSharedKey = "\"" + password + "\""; + } + } + + /** + * Updates WEP Wifi configuration. + * + * @param wifiConf {@link WifiConfiguration} object to update + * @param password Wifi password + */ + protected void updateForWEPConfiguration(WifiConfiguration wifiConf, String password) { + wifiConf.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); + wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); + wifiConf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); + wifiConf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP40); + wifiConf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.WEP104); + wifiConf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP); + wifiConf.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP); + int length = password.length(); + if ((length == 10 || length == 26 || length == 58) && password.matches("[0-9A-Fa-f]*")) { + wifiConf.wepKeys[0] = password; + } else { + wifiConf.wepKeys[0] = '"' + password + '"'; + } + wifiConf.wepTxKeyIndex = 0; + } +}
\ No newline at end of file diff --git a/apps/Util/src/com/android/afwtest/util/WifiConnector.java b/apps/Util/src/com/android/afwtest/util/WifiConnector.java new file mode 100644 index 0000000..f10ab2d --- /dev/null +++ b/apps/Util/src/com/android/afwtest/util/WifiConnector.java @@ -0,0 +1,145 @@ +/* + * 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.util; + +import android.content.Context; +import android.net.wifi.WifiManager; +import android.os.SystemClock; +import android.util.Log; + +import com.android.afwtest.common.NetworkUtils; + +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +/** + * Utility class responsible for connecting wifi. + */ +public final class WifiConnector implements NetworkMonitor.Callback { + + private static final String TAG = "afwtest.WifiConnector"; + + /** Connection retry base duration. */ + private static final int RETRY_SLEEP_DURATION_BASE_MS = 500; + /** Connection retry duration multiplier. */ + private static final int RETRY_SLEEP_MULTIPLIER = 2; + /** Max connection attempts. */ + private static final int MAX_ATTEMPS = 6; + /** Wifi reconnection timeout. */ + private static final int RECONNECT_TIMEOUT_MS = (int)TimeUnit.MINUTES.toMillis(1); + + private final Context mContext; + private final String mSSID, mSecurityType, mPassword; + private final WifiManager mWifiManager; + private final WifiConfig mWifiConfig; + + /** + * {@link Semaphore}, indicating result is available if it's value > 0. + */ + private Semaphore mLock = new Semaphore(0); + + /** + * Constructor. + * + * @param context {@link Context} object + * @param ssid Wifi SSID + * @param securityType Wifi security type + * @param password Wifi password + */ + public WifiConnector(Context context, String ssid, String securityType, String password) { + mContext = context; + mSSID = ssid; + mSecurityType = securityType; + mPassword = password; + mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + mWifiConfig = new WifiConfig(mWifiManager); + } + + /** + * Connects to WIFI. + * + * @return {@code true} if the given WIFI is connected; {@code false} othwerise + */ + public boolean connect() { + if (!NetworkUtils.enableWifi(mContext)) { + Log.e(TAG, "Failed to enable WIFI."); + return false; + } + + NetworkMonitor networkMonitor = new NetworkMonitor(mContext, this); + + try { + int netId = -1; + + int nextSleepTimeMs = RETRY_SLEEP_DURATION_BASE_MS; + int attempts = MAX_ATTEMPS; + while (attempts > 0) { + if (netId == -1) { + netId = mWifiConfig.addNetwork(mSSID, mSecurityType, mPassword); + } + + if (netId == -1) { + Log.e(TAG, "Failed to save network."); + } else if (!mWifiManager.reconnect()) { + Log.e(TAG, "Unable to connect to wifi"); + } else { + // Connected + break; + } + + --attempts; + // Sleep before next attempt + Log.e(TAG, String.format("Retrying in %s ms.", nextSleepTimeMs)); + SystemClock.sleep(nextSleepTimeMs); + // Increase the next sleep time. + nextSleepTimeMs *= RETRY_SLEEP_MULTIPLIER; + } + + // Failed to add network or reconnect. + if (netId == -1 || attempts <= 0) { + return false; + } + + // Wait for connection event + mLock.tryAcquire(RECONNECT_TIMEOUT_MS, TimeUnit.MILLISECONDS); + return true; + } catch (InterruptedException e) { + Log.e(TAG, "Failed to connect to wifi", e); + } finally { + networkMonitor.close(); + } + + return false; + } + + /** + * {@inheritDoc} + */ + @Override + public void onNetworkConnected() { + if (NetworkUtils.isConnectedToSpecifiedWifi(mContext, mSSID)) { + // Let's the waiter know it's connected. + mLock.release(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void onNetworkDisconnected() { + } +}
\ No newline at end of file diff --git a/libs/CommonLib/src/com/android/afwtest/common/NetworkUtils.java b/libs/CommonLib/src/com/android/afwtest/common/NetworkUtils.java new file mode 100644 index 0000000..ef7e00c --- /dev/null +++ b/libs/CommonLib/src/com/android/afwtest/common/NetworkUtils.java @@ -0,0 +1,104 @@ +/* + * 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.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiManager; +import android.util.Log; + +/** + * Network utilities. + */ +public class NetworkUtils { + private static final String TAG = "afwtest.NetworkUtils"; + + /** + * Enables Wifi. + * + * @param context {@link Context} object + * @return {@code true} if Wifi is enabled successfully; {@code false} otherwise + */ + public static boolean enableWifi(Context context) { + WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + return wifiManager != null + && (wifiManager.isWifiEnabled() || wifiManager.setWifiEnabled(true)); + } + + /** + * Returns whether the device is currently connected to a wifi. + * + * @param context {@link Context} object + * @return {@code true} if connected to Wifi; {@code false} otherwise + */ + public static boolean isConnectedToWifi(Context context) { + NetworkInfo info = getActiveNetworkInfo(context); + return info != null + && info.isConnected() + && info.getType() == ConnectivityManager.TYPE_WIFI; + } + + /** + * Checks if connected with expected wifi. + * + * @param context {@link Context} object + * @param ssid Wifi SSID + * @return {@code true} if the expected wifi + */ + public static boolean isConnectedToSpecifiedWifi(Context context, String ssid) { + WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + return ssid != null + && wifiManager != null + && isConnectedToWifi(context) + && wifiManager.getConnectionInfo() != null + && ssid.equals(wifiManager.getConnectionInfo().getSSID()); + } + + /** + * Gets the active network. + * + * @param context {@link Context} object + * @return active {@link NetworkInfo} + */ + private static NetworkInfo getActiveNetworkInfo(Context context) { + ConnectivityManager cm = + (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + if (cm != null) { + return cm.getActiveNetworkInfo(); + } + return null; + } + + /** + * Disconnects a device from the connected Wi-Fi network by removing the network configuration. + * + * @param context {@link Context} object + */ + public static boolean disconnectFromWifi(Context context) { + WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + if (wifiManager.isWifiEnabled() && isConnectedToWifi(context)) { + String wifiSsid = wifiManager.getConnectionInfo().getSSID(); + if (!wifiManager.removeNetwork(wifiManager.getConnectionInfo().getNetworkId())) { + Log.e(TAG, String.format("Failed to remove Wifi %s", wifiSsid)); + return false; + } + } + + return true; + } +} diff --git a/tools/tradefed-host/res/config/afw-test-wifi.xml b/tools/tradefed-host/res/config/afw-test-wifi.xml index 962aec3..24a6260 100644 --- a/tools/tradefed-host/res/config/afw-test-wifi.xml +++ b/tools/tradefed-host/res/config/afw-test-wifi.xml @@ -16,9 +16,15 @@ <configuration description="Connect to wifi network"> + <!-- Install device admin app --> + <target_preparer class="com.android.cts.tradefed.targetprep.CtsApkInstaller"> + <option name="test-file-name" value="AfwThUtil.apk" /> + </target_preparer> + <target_preparer class="com.android.afwtest.tradefed.targetprep.AfwTestWifiPreparer" > <option name="wifi-config-file" value="afw-test.props"/> <option name="wifi-ssid-key" value="wifi_ssid"/> + <option name="wifi-security-type-key" value="wifi_security_type"/> <option name="wifi-password-key" value="wifi_password"/> <option name="disconnect-wifi-after-test" value="false"/> </target_preparer> diff --git a/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestEnvDumper.java b/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestEnvDumper.java index cdb0b28..6d6717e 100644 --- a/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestEnvDumper.java +++ b/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestEnvDumper.java @@ -86,7 +86,7 @@ public class AfwTestEnvDumper extends AfwTestTargetPreparer implements ITargetCl os.write(str.getBytes()); StreamUtil.flushAndCloseStream(os); - CLog.i("Dumped file: " + dumpFile.getAbsolutePath()); + CLog.i(String.format("Dumped file: %s", dumpFile.getAbsolutePath())); } catch (IOException exception) { CLog.e("Failed to dump app versions to file", e); } @@ -95,7 +95,7 @@ public class AfwTestEnvDumper extends AfwTestTargetPreparer implements ITargetCl /** * Gets environment configurations as string. * - * @param deivce testing device + * @param device testing device * @return environment configuration as string */ protected String getEnv(ITestDevice device) throws DeviceNotAvailableException { diff --git a/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestTargetPreparer.java b/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestTargetPreparer.java index 3316e6b..cfca249 100644 --- a/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestTargetPreparer.java +++ b/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestTargetPreparer.java @@ -171,7 +171,7 @@ public abstract class AfwTestTargetPreparer { protected void fastbootFormat(ITestDevice device, String partition) throws DeviceNotAvailableException, TargetSetupError { - CLog.i("Attempting: fastboot format %s", partition); + CLog.i(String.format("Attempting: fastboot format %s", partition)); CommandResult r = device.executeLongFastbootCommand("format", partition); if (r.getStatus() != CommandStatus.SUCCESS) { throw new TargetSetupError( diff --git a/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestUserRemover.java b/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestUserRemover.java index 832a9a9..c21c8e6 100644 --- a/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestUserRemover.java +++ b/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestUserRemover.java @@ -92,9 +92,13 @@ public class AfwTestUserRemover implements ITargetCleaner { } if (device.removeUser(userId)) { - CLog.i("Successfully removed user %d on %s", userId, device.getSerialNumber()); + CLog.i(String.format("Successfully removed user %d on %s", + userId, + device.getSerialNumber())); } else { - CLog.e("Failed to remove user %d on %s", userId, device.getSerialNumber()); + CLog.e(String.format("Failed to remove user %d on %s", + userId, + device.getSerialNumber())); success = false; } } diff --git a/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestWifiPreparer.java b/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestWifiPreparer.java index ffa9def..1355be8 100644 --- a/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestWifiPreparer.java +++ b/tools/tradefed-host/src/com/android/afwtest/tradefed/targetprep/AfwTestWifiPreparer.java @@ -38,6 +38,15 @@ import java.util.Properties; @OptionClass(alias = "afw-test-wifi") public final class AfwTestWifiPreparer extends AfwTestTargetPreparer implements ITargetCleaner { + /** + * Package name of the system util app. + */ + private static final String UTIL_PKG_NAME = "com.android.afwtest.util"; + + /** Shell command template for connect/disconnect wifi. */ + private static final String ADB_SHELL_CMD_TEMPL = + "am instrument -w %s com.android.afwtest.util/.Wifi"; + @Option(name = "wifi-config-file", description = "The file name containing wifi configuration.") private String mConfigFileName = null; @@ -46,6 +55,10 @@ public final class AfwTestWifiPreparer extends AfwTestTargetPreparer implements description = "The key of wifi ssid in the config file.") private String mWifiSsidKey = null; + @Option(name = "wifi-security-type-key", + description = "The key of wifi security type in the config file.") + private String mWifiSecurityType = null; + @Option(name = "wifi-password-key", description = "The key of wifi password in the config file.") private String mWifiPasswordKey = null; @@ -58,6 +71,9 @@ public final class AfwTestWifiPreparer extends AfwTestTargetPreparer implements description = "Disconnect from wifi network after test completes.") private boolean mDisconnectWifiAfterTest = true; + /** Whether to connect with AfwThUtil app. */ + private boolean mWifiConnectedWithUtilApp = false; + /** * {@inheritDoc} */ @@ -74,30 +90,38 @@ public final class AfwTestWifiPreparer extends AfwTestTargetPreparer implements } File configFile = new File(getCtsBuildHelper(buildInfo).getTestCasesDir(), mConfigFileName); - Properties props = null; + Properties props; try { props = readProperties(configFile); } catch (IOException e) { - throw new TargetSetupError("Failed to read prop file: " + configFile.getAbsolutePath()); + throw new TargetSetupError( + String.format("Failed to read prop file: %s", configFile.getAbsolutePath())); } String wifiSsid = props.getProperty(mWifiSsidKey, ""); + String wifiSecurityType = props.getProperty(mWifiSecurityType, ""); String wifiPassword = props.getProperty(mWifiPasswordKey, ""); if (wifiSsid.isEmpty()) { - throw new TargetSetupError( - mWifiSsidKey + " not specified in file " + configFile.getAbsolutePath()); + throw new TargetSetupError(String.format( + "%s not specified in file %s", mWifiSsidKey, configFile.getAbsolutePath())); + } + + // tradefed doesn't support WEP wifi; connect to it by AfwThUtil + if ("WEP".equals(wifiSecurityType)) { + mWifiConnectedWithUtilApp = true; + connectWifiWithUtilApp(device, wifiSsid, wifiSecurityType, wifiPassword); + return; } // Implement retry. for (int i = 0; i < mWifiAttempts; ++i) { try { - if (device.connectToWifiNetworkIfNeeded(wifiSsid, wifiPassword)) { return; } - } catch(Exception e) { - CLog.e("Error trying to connect to Wifi:", e); + } catch (Exception e) { + CLog.e(e); } boolean lastAttempt = (i + 1) == mWifiAttempts; if (!lastAttempt) { @@ -117,16 +141,80 @@ public final class AfwTestWifiPreparer extends AfwTestTargetPreparer implements throws DeviceNotAvailableException { if (mDisconnectWifiAfterTest && device.isWifiEnabled()) { - if (device.disconnectFromWifi()) { - CLog.i("Successfully disconnected from wifi network on %s", - device.getSerialNumber()); + if (mWifiConnectedWithUtilApp) { + disconnectWifiWithUtilApp(device); } else { - CLog.w("Failed to disconnect from wifi network on %s", device.getSerialNumber()); + if (device.disconnectFromWifi()) { + CLog.i("Successfully disconnected from wifi network on %s", + device.getSerialNumber()); + } else { + CLog.w("Failed to disconnect from wifi network on %s", + device.getSerialNumber()); + } } } } /** + * Connects to wifi with AfwThUtil app. + * + * @param device test device + * @param wifiSSID WIFI SSID + * @param securityType WIFI security type + * @param password WIFI password + */ + private void connectWifiWithUtilApp(ITestDevice device, + String wifiSSID, + String securityType, + String password) + throws TargetSetupError, DeviceNotAvailableException { + String args = String.format("-e action connect -e ssid %s", wifiSSID); + if (securityType != null && !securityType.isEmpty()) { + args = String.format("%s -e security_type %s", args, securityType); + } + if (password != null && !password.isEmpty()) { + args = String.format("%s -e password %s", args, password); + } + + String cmdStr = String.format(ADB_SHELL_CMD_TEMPL, args); + CLog.i(String.format("Shell: %s", cmdStr)); + String result = device.executeShellCommand(cmdStr); + if (result != null && result.contains("result=SUCCESS")) { + CLog.i(String.format( + "Successfully connected to wifi network %s(security_type=%s) on %s", + wifiSSID, + securityType, + device.getSerialNumber())); + } else { + throw new TargetSetupError(String.format( + "Failed to connected to wifi network %s(security_type=%s) on %s: %s", + wifiSSID, + securityType, + device.getSerialNumber(), + result)); + } + } + + /** + * Disconnects from Wifi with AfwThUtil app. + * + * @param device test device + */ + private void disconnectWifiWithUtilApp(ITestDevice device) throws DeviceNotAvailableException { + String cmdStr = String.format(ADB_SHELL_CMD_TEMPL, "-e action disconnect"); + CLog.i(String.format("Shell: %s", cmdStr)); + String result = device.executeShellCommand(cmdStr); + if (result != null && result.contains("result=SUCCESS")) { + CLog.i(String.format("Successfully disconnected from wifi network on %s", + device.getSerialNumber())); + } else { + CLog.w(String.format("Failed to disconnect from wifi network on %s: %s", + device.getSerialNumber(), + result)); + } + } + + /** * Help function to read {@link Properties} from a file. * * @param file {@link File} to read properties from |