Merge "Bandwidth microbenchmark test app for ICS."
This commit is contained in:
committed by
Android (Google) Code Review
commit
4adcfb3b01
30
core/tests/bandwidthtests/Android.mk
Normal file
30
core/tests/bandwidthtests/Android.mk
Normal file
@@ -0,0 +1,30 @@
|
||||
# Copyright (C) 2011 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)
|
||||
|
||||
# We only want this apk build for tests.
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
# Include all test java files.
|
||||
LOCAL_SRC_FILES := \
|
||||
$(call all-java-files-under, src)
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := android.test.runner
|
||||
LOCAL_PACKAGE_NAME := BandwidthTests
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||
38
core/tests/bandwidthtests/AndroidManifest.xml
Normal file
38
core/tests/bandwidthtests/AndroidManifest.xml
Normal file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2011 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.bandwidth.tests" >
|
||||
|
||||
<application >
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation
|
||||
android:name="com.android.bandwidthtest.BandwidthTestRunner"
|
||||
android:targetPackage="com.android.bandwidth.tests"
|
||||
android:label="Bandwidth Tests" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.DEVICE_POWER" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
</manifest>
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2011, 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.bandwidthtest;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo.State;
|
||||
import android.net.NetworkStats;
|
||||
import android.net.TrafficStats;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Process;
|
||||
import android.os.SystemClock;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.test.InstrumentationTestCase;
|
||||
import android.test.suitebuilder.annotation.LargeTest;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.bandwidthtest.util.BandwidthTestUtil;
|
||||
import com.android.bandwidthtest.util.ConnectionUtil;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Test that downloads files from a test server and reports the bandwidth metrics collected.
|
||||
*/
|
||||
public class BandwidthTest extends InstrumentationTestCase {
|
||||
|
||||
private static final String LOG_TAG = "BandwidthTest";
|
||||
private final static String PROF_LABEL = "PROF_";
|
||||
private final static String PROC_LABEL = "PROC_";
|
||||
private final static int INSTRUMENTATION_IN_PROGRESS = 2;
|
||||
|
||||
private final static String BASE_DIR =
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
private final static String TMP_FILENAME = "tmp.dat";
|
||||
// Download 10.486 * 106 bytes (+ headers) from app engine test server.
|
||||
private final int FILE_SIZE = 10485613;
|
||||
private Context mContext;
|
||||
private ConnectionUtil mConnectionUtil;
|
||||
private TelephonyManager mTManager;
|
||||
private int mUid;
|
||||
private String mSsid;
|
||||
private String mTestServer;
|
||||
private String mDeviceId;
|
||||
private BandwidthTestRunner mRunner;
|
||||
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mRunner = (BandwidthTestRunner) getInstrumentation();
|
||||
mSsid = mRunner.mSsid;
|
||||
mTestServer = mRunner.mTestServer;
|
||||
mContext = mRunner.getTargetContext();
|
||||
mConnectionUtil = new ConnectionUtil(mContext);
|
||||
mConnectionUtil.initialize();
|
||||
Log.v(LOG_TAG, "Initialized mConnectionUtil");
|
||||
mUid = Process.myUid();
|
||||
mTManager = (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE);
|
||||
mDeviceId = mTManager.getDeviceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
mConnectionUtil.cleanUp();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that downloading on wifi reports reasonable stats.
|
||||
*/
|
||||
@LargeTest
|
||||
public void testWifiDownload() {
|
||||
assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
|
||||
NetworkStats pre_test_stats = fetchDataFromProc(mUid);
|
||||
String ts = Long.toString(System.currentTimeMillis());
|
||||
|
||||
String targetUrl = BandwidthTestUtil.buildDownloadUrl(
|
||||
mTestServer, FILE_SIZE, mDeviceId, ts);
|
||||
TrafficStats.startDataProfiling(mContext);
|
||||
File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
|
||||
assertTrue(BandwidthTestUtil.DownloadFromUrl(targetUrl, tmpSaveFile));
|
||||
NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
|
||||
|
||||
NetworkStats post_test_stats = fetchDataFromProc(mUid);
|
||||
NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);
|
||||
|
||||
// Output measurements to instrumentation out, so that it can be compared to that of
|
||||
// the server.
|
||||
Bundle results = new Bundle();
|
||||
results.putString("device_id", mDeviceId);
|
||||
results.putString("timestamp", ts);
|
||||
results.putInt("size", FILE_SIZE);
|
||||
AddStatsToResults(PROF_LABEL, prof_stats, results);
|
||||
AddStatsToResults(PROC_LABEL, proc_stats, results);
|
||||
getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
|
||||
|
||||
// Clean up.
|
||||
assertTrue(cleanUpFile(tmpSaveFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* We want to make sure that if we use the Download Manager to download stuff,
|
||||
* accounting still goes to the app making the call and that the numbers still make sense.
|
||||
*/
|
||||
@LargeTest
|
||||
public void testWifiDownloadWithDownloadManager() {
|
||||
assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
|
||||
// If we are using the download manager, then the data that is written to /proc/uid_stat/
|
||||
// is accounted against download manager's uid, since it uses pre-ICS API.
|
||||
int downloadManagerUid = mConnectionUtil.downloadManagerUid();
|
||||
assertTrue(downloadManagerUid >= 0);
|
||||
NetworkStats pre_test_stats = fetchDataFromProc(downloadManagerUid);
|
||||
// start profiling
|
||||
TrafficStats.startDataProfiling(mContext);
|
||||
String ts = Long.toString(System.currentTimeMillis());
|
||||
String targetUrl = BandwidthTestUtil.buildDownloadUrl(
|
||||
mTestServer, FILE_SIZE, mDeviceId, ts);
|
||||
Log.v(LOG_TAG, "Download url: " + targetUrl);
|
||||
File tmpSaveFile = new File(BASE_DIR + File.separator + TMP_FILENAME);
|
||||
assertTrue(mConnectionUtil.startDownloadAndWait(targetUrl, 500000));
|
||||
NetworkStats prof_stats = TrafficStats.stopDataProfiling(mContext);
|
||||
NetworkStats post_test_stats = fetchDataFromProc(downloadManagerUid);
|
||||
NetworkStats proc_stats = post_test_stats.subtract(pre_test_stats);
|
||||
|
||||
// Output measurements to instrumentation out, so that it can be compared to that of
|
||||
// the server.
|
||||
Bundle results = new Bundle();
|
||||
results.putString("device_id", mDeviceId);
|
||||
results.putString("timestamp", ts);
|
||||
results.putInt("size", FILE_SIZE);
|
||||
AddStatsToResults(PROF_LABEL, prof_stats, results);
|
||||
AddStatsToResults(PROC_LABEL, proc_stats, results);
|
||||
getInstrumentation().sendStatus(INSTRUMENTATION_IN_PROGRESS, results);
|
||||
|
||||
// Clean up.
|
||||
assertTrue(cleanUpFile(tmpSaveFile));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch network data from /proc/uid_stat/uid
|
||||
* @return populated {@link NetworkStats}
|
||||
*/
|
||||
public NetworkStats fetchDataFromProc(int uid) {
|
||||
String root_filepath = "/proc/uid_stat/" + uid + "/";
|
||||
File rcv_stat = new File (root_filepath + "tcp_rcv");
|
||||
int rx = BandwidthTestUtil.parseIntValueFromFile(rcv_stat);
|
||||
File snd_stat = new File (root_filepath + "tcp_snd");
|
||||
int tx = BandwidthTestUtil.parseIntValueFromFile(snd_stat);
|
||||
NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
|
||||
stats.addValues(NetworkStats.IFACE_ALL, uid, NetworkStats.TAG_NONE, rx, 0, tx, 0);
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn on Airplane mode and connect to the wifi
|
||||
* @param ssid of the wifi to connect to
|
||||
* @return true if we successfully connected to a given network.
|
||||
*/
|
||||
public boolean setDeviceWifiAndAirplaneMode(String ssid) {
|
||||
mConnectionUtil.setAirplaneMode(mContext, true);
|
||||
assertTrue(mConnectionUtil.connectToWifi(ssid));
|
||||
assertTrue(mConnectionUtil.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
|
||||
ConnectionUtil.LONG_TIMEOUT));
|
||||
return mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
|
||||
ConnectionUtil.LONG_TIMEOUT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the {@link NetworkStats} to Instrumentation out.
|
||||
* @param label to attach to this given stats.
|
||||
* @param stats {@link NetworkStats} to add.
|
||||
* @param results {@link Bundle} to be added to.
|
||||
*/
|
||||
public void AddStatsToResults(String label, NetworkStats stats, Bundle results){
|
||||
if (results == null || results.isEmpty()) {
|
||||
Log.e(LOG_TAG, "Empty bundle provided.");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < stats.size(); ++i) {
|
||||
android.net.NetworkStats.Entry entry = stats.getValues(i, null);
|
||||
results.putInt(label + "uid", entry.uid);
|
||||
results.putString(label + "iface", entry.iface);
|
||||
results.putInt(label + "tag", entry.tag);
|
||||
results.putLong(label + "tx", entry.txBytes);
|
||||
results.putLong(label + "rx", entry.rxBytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove file if it exists.
|
||||
* @param file {@link File} to delete.
|
||||
* @return true if successfully deleted the file.
|
||||
*/
|
||||
private boolean cleanUpFile(File file) {
|
||||
if (file.exists()) {
|
||||
return file.delete();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2011, 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.bandwidthtest;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.test.InstrumentationTestRunner;
|
||||
|
||||
public class BandwidthTestRunner extends InstrumentationTestRunner {
|
||||
public String mSsid = "wifi-ssid";
|
||||
public String mTestServer = "http://www.sometestserver.com";
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
String ssidStr= (String) icicle.get("ssid");
|
||||
if (ssidStr != null) {
|
||||
mSsid = ssidStr;
|
||||
}
|
||||
String serverStr = (String) icicle.get("server");
|
||||
if (serverStr != null) {
|
||||
mTestServer = serverStr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
* Copyright (C) 2011 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.bandwidthtest;
|
||||
|
||||
import android.net.NetworkInfo.State;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Data structure to keep track of the network state transitions.
|
||||
*/
|
||||
public class NetworkState {
|
||||
/**
|
||||
* Desired direction of state transition.
|
||||
*/
|
||||
public enum StateTransitionDirection {
|
||||
TO_DISCONNECTION, TO_CONNECTION, DO_NOTHING
|
||||
}
|
||||
private final String LOG_TAG = "NetworkState";
|
||||
private List<State> mStateDepository;
|
||||
private State mTransitionTarget;
|
||||
private StateTransitionDirection mTransitionDirection;
|
||||
private String mReason = null; // record mReason of state transition failure
|
||||
|
||||
public NetworkState() {
|
||||
mStateDepository = new ArrayList<State>();
|
||||
mTransitionDirection = StateTransitionDirection.DO_NOTHING;
|
||||
mTransitionTarget = State.UNKNOWN;
|
||||
}
|
||||
|
||||
public NetworkState(State currentState) {
|
||||
mStateDepository = new ArrayList<State>();
|
||||
mStateDepository.add(currentState);
|
||||
mTransitionDirection = StateTransitionDirection.DO_NOTHING;
|
||||
mTransitionTarget = State.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reinitialize the network state
|
||||
*/
|
||||
public void resetNetworkState() {
|
||||
mStateDepository.clear();
|
||||
mTransitionDirection = StateTransitionDirection.DO_NOTHING;
|
||||
mTransitionTarget = State.UNKNOWN;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transition criteria
|
||||
* @param initState initial {@link State}
|
||||
* @param transitionDir explicit {@link StateTransitionDirection}
|
||||
* @param targetState desired {@link State}
|
||||
*/
|
||||
public void setStateTransitionCriteria(State initState, StateTransitionDirection transitionDir,
|
||||
State targetState) {
|
||||
if (!mStateDepository.isEmpty()) {
|
||||
mStateDepository.clear();
|
||||
}
|
||||
mStateDepository.add(initState);
|
||||
mTransitionDirection = transitionDir;
|
||||
mTransitionTarget = targetState;
|
||||
Log.v(LOG_TAG, "setStateTransitionCriteria: " + printStates());
|
||||
}
|
||||
|
||||
/**
|
||||
* Record the current state of the network
|
||||
* @param currentState the current {@link State}
|
||||
*/
|
||||
public void recordState(State currentState) {
|
||||
mStateDepository.add(currentState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the state transition
|
||||
* @return true if the requested transition completed successfully.
|
||||
*/
|
||||
public boolean validateStateTransition() {
|
||||
Log.v(LOG_TAG, String.format("Print state depository: %s", printStates()));
|
||||
switch (mTransitionDirection) {
|
||||
case DO_NOTHING:
|
||||
Log.v(LOG_TAG, "No direction requested, verifying network states");
|
||||
return validateNetworkStates();
|
||||
case TO_CONNECTION:
|
||||
Log.v(LOG_TAG, "Transition to CONNECTED");
|
||||
return validateNetworkConnection();
|
||||
case TO_DISCONNECTION:
|
||||
Log.v(LOG_TAG, "Transition to DISCONNECTED");
|
||||
return validateNetworkDisconnection();
|
||||
default:
|
||||
Log.e(LOG_TAG, "Invalid transition direction.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that network states are valid
|
||||
* @return false if any of the states are invalid
|
||||
*/
|
||||
private boolean validateNetworkStates() {
|
||||
if (mStateDepository.isEmpty()) {
|
||||
Log.v(LOG_TAG, "no state is recorded");
|
||||
mReason = "no state is recorded.";
|
||||
return false;
|
||||
} else if (mStateDepository.size() > 1) {
|
||||
Log.v(LOG_TAG, "no broadcast is expected, instead broadcast is probably received");
|
||||
mReason = "no broadcast is expected, instead broadcast is probably received";
|
||||
return false;
|
||||
} else if (mStateDepository.get(0) != mTransitionTarget) {
|
||||
Log.v(LOG_TAG, String.format("%s is expected, but it is %s",
|
||||
mTransitionTarget.toString(),
|
||||
mStateDepository.get(0).toString()));
|
||||
mReason = String.format("%s is expected, but it is %s",
|
||||
mTransitionTarget.toString(),
|
||||
mStateDepository.get(0).toString());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the network state to disconnection
|
||||
* @return false if any of the state transitions were not valid
|
||||
*/
|
||||
private boolean validateNetworkDisconnection() {
|
||||
// Transition from CONNECTED -> DISCONNECTED: CONNECTED->DISCONNECTING->DISCONNECTED
|
||||
StringBuffer str = new StringBuffer ("States: ");
|
||||
str.append(printStates());
|
||||
if (mStateDepository.get(0) != State.CONNECTED) {
|
||||
str.append(String.format(" Initial state should be CONNECTED, but it is %s.",
|
||||
mStateDepository.get(0)));
|
||||
mReason = str.toString();
|
||||
return false;
|
||||
}
|
||||
State lastState = mStateDepository.get(mStateDepository.size() - 1);
|
||||
if ( lastState != mTransitionTarget) {
|
||||
str.append(String.format(" Last state should be DISCONNECTED, but it is %s",
|
||||
lastState));
|
||||
mReason = str.toString();
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < mStateDepository.size() - 1; i++) {
|
||||
State preState = mStateDepository.get(i-1);
|
||||
State curState = mStateDepository.get(i);
|
||||
if ((preState == State.CONNECTED) && ((curState == State.DISCONNECTING) ||
|
||||
(curState == State.DISCONNECTED))) {
|
||||
continue;
|
||||
} else if ((preState == State.DISCONNECTING) && (curState == State.DISCONNECTED)) {
|
||||
continue;
|
||||
} else if ((preState == State.DISCONNECTED) && (curState == State.DISCONNECTED)) {
|
||||
continue;
|
||||
} else {
|
||||
str.append(String.format(" Transition state from %s to %s is not valid",
|
||||
preState.toString(), curState.toString()));
|
||||
mReason = str.toString();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mReason = str.toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the network state to connection
|
||||
* @return false if any of the state transitions were not valid
|
||||
*/
|
||||
private boolean validateNetworkConnection() {
|
||||
StringBuffer str = new StringBuffer("States ");
|
||||
str.append(printStates());
|
||||
if (mStateDepository.get(0) != State.DISCONNECTED) {
|
||||
str.append(String.format(" Initial state should be DISCONNECTED, but it is %s.",
|
||||
mStateDepository.get(0)));
|
||||
mReason = str.toString();
|
||||
return false;
|
||||
}
|
||||
State lastState = mStateDepository.get(mStateDepository.size() - 1);
|
||||
if ( lastState != mTransitionTarget) {
|
||||
str.append(String.format(" Last state should be %s, but it is %s", mTransitionTarget,
|
||||
lastState));
|
||||
mReason = str.toString();
|
||||
return false;
|
||||
}
|
||||
for (int i = 1; i < mStateDepository.size(); i++) {
|
||||
State preState = mStateDepository.get(i-1);
|
||||
State curState = mStateDepository.get(i);
|
||||
if ((preState == State.DISCONNECTED) && ((curState == State.CONNECTING) ||
|
||||
(curState == State.CONNECTED) || (curState == State.DISCONNECTED))) {
|
||||
continue;
|
||||
} else if ((preState == State.CONNECTING) && (curState == State.CONNECTED)) {
|
||||
continue;
|
||||
} else if ((preState == State.CONNECTED) && (curState == State.CONNECTED)) {
|
||||
continue;
|
||||
} else {
|
||||
str.append(String.format(" Transition state from %s to %s is not valid.",
|
||||
preState.toString(), curState.toString()));
|
||||
mReason = str.toString();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mReason = str.toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the different network state transitions
|
||||
* @return {@link List} of {@link State}
|
||||
*/
|
||||
public List<State> getTransitionStates() {
|
||||
return mStateDepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the reason for network state transition failure
|
||||
* @return the {@link String} for the failure
|
||||
*/
|
||||
public String getFailureReason() {
|
||||
return mReason;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the network state
|
||||
* @return {@link String} representation of the network state
|
||||
*/
|
||||
public String printStates() {
|
||||
StringBuilder stateBuilder = new StringBuilder();
|
||||
for (int i = 0; i < mStateDepository.size(); i++) {
|
||||
stateBuilder.append(" ").append(mStateDepository.get(i).toString()).append("->");
|
||||
}
|
||||
return stateBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("mTransitionDirection: ").append(mTransitionDirection.toString()).
|
||||
append("; ").append("states:").
|
||||
append(printStates()).append("; ");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (C) 2011, 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.bandwidthtest.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.apache.http.util.ByteArrayBuffer;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
public class BandwidthTestUtil {
|
||||
private static final String LOG_TAG = "BandwidthTestUtil";
|
||||
/**
|
||||
* Parses the first line in a file if exists.
|
||||
*
|
||||
* @param file {@link File} the input
|
||||
* @return the integer value of the first line of the file.
|
||||
*/
|
||||
public static int parseIntValueFromFile(File file) {
|
||||
int value = 0;
|
||||
if (file.exists()) {
|
||||
try {
|
||||
FileInputStream fstream = new FileInputStream(file);
|
||||
DataInputStream in = new DataInputStream(fstream);
|
||||
BufferedReader br = new BufferedReader(new InputStreamReader(in));
|
||||
String strLine = br.readLine();
|
||||
if (strLine != null) {
|
||||
value = Integer.parseInt(strLine);
|
||||
}
|
||||
// Close the input stream
|
||||
in.close();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Download string for the test server.
|
||||
*
|
||||
* @param server url of the test server
|
||||
* @param size in bytes of the file to download
|
||||
* @param deviceId the device id that is downloading
|
||||
* @param timestamp
|
||||
* @return download url
|
||||
*/
|
||||
public static String buildDownloadUrl(String server, int size, String deviceId,
|
||||
String timestamp) {
|
||||
String downloadUrl = server + "/download?size=" + size + "&device_id=" + deviceId +
|
||||
"×tamp=" + timestamp;
|
||||
return downloadUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a given file from a target url to a given destination file.
|
||||
* @param targetUrl the url to download
|
||||
* @param file the {@link File} location where to save to
|
||||
* @return true if it succeeded.
|
||||
*/
|
||||
public static boolean DownloadFromUrl(String targetUrl, File file) {
|
||||
try {
|
||||
URL url = new URL(targetUrl);
|
||||
Log.d(LOG_TAG, "Download begining");
|
||||
Log.d(LOG_TAG, "Download url:" + url);
|
||||
Log.d(LOG_TAG, "Downloaded file name:" + file.getAbsolutePath());
|
||||
URLConnection ucon = url.openConnection();
|
||||
InputStream is = ucon.getInputStream();
|
||||
BufferedInputStream bis = new BufferedInputStream(is);
|
||||
ByteArrayBuffer baf = new ByteArrayBuffer(50);
|
||||
int current = 0;
|
||||
while ((current = bis.read()) != -1) {
|
||||
baf.append((byte) current);
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(file);
|
||||
fos.write(baf.toByteArray());
|
||||
fos.close();
|
||||
} catch (IOException e) {
|
||||
Log.d(LOG_TAG, "Failed to download file with error: " + e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,684 @@
|
||||
/*
|
||||
* Copyright (C) 2011, 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.bandwidthtest.util;
|
||||
|
||||
import android.app.DownloadManager;
|
||||
import android.app.DownloadManager.Query;
|
||||
import android.app.DownloadManager.Request;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.database.Cursor;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkInfo.State;
|
||||
import android.net.Uri;
|
||||
import android.net.wifi.ScanResult;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiConfiguration.KeyMgmt;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.bandwidthtest.NetworkState;
|
||||
import com.android.bandwidthtest.NetworkState.StateTransitionDirection;
|
||||
import com.android.internal.util.AsyncChannel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* Utility class used to set the connectivity of the device and to download files.
|
||||
*/
|
||||
public class ConnectionUtil {
|
||||
private static final String LOG_TAG = "ConnectionUtil";
|
||||
private static final String DOWNLOAD_MANAGER_PKG_NAME = "com.android.providers.downloads";
|
||||
private static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; // 10 seconds
|
||||
private static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
|
||||
public static final int SHORT_TIMEOUT = 5 * 1000;
|
||||
public static final int LONG_TIMEOUT = 10 * 1000;
|
||||
private ConnectivityReceiver mConnectivityReceiver = null;
|
||||
private WifiReceiver mWifiReceiver = null;
|
||||
private DownloadReceiver mDownloadReceiver = null;
|
||||
private DownloadManager mDownloadManager;
|
||||
private NetworkInfo mNetworkInfo;
|
||||
private NetworkInfo mOtherNetworkInfo;
|
||||
private boolean mScanResultIsAvailable = false;
|
||||
private ConnectivityManager mCM;
|
||||
private Object mWifiMonitor = new Object();
|
||||
private Object mConnectivityMonitor = new Object();
|
||||
private Object mDownloadMonitor = new Object();
|
||||
private int mWifiState;
|
||||
private NetworkInfo mWifiNetworkInfo;
|
||||
private WifiManager mWifiManager;
|
||||
private Context mContext;
|
||||
// Verify connectivity state
|
||||
private static final int NUM_NETWORK_TYPES = ConnectivityManager.MAX_NETWORK_TYPE + 1;
|
||||
private NetworkState[] mConnectivityState = new NetworkState[NUM_NETWORK_TYPES];
|
||||
|
||||
public ConnectionUtil(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the class. Needs to be called before any other methods in {@link ConnectionUtil}
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void initialize() throws Exception {
|
||||
// Register a connectivity receiver for CONNECTIVITY_ACTION
|
||||
mConnectivityReceiver = new ConnectivityReceiver();
|
||||
mContext.registerReceiver(mConnectivityReceiver,
|
||||
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
|
||||
// Register a download receiver for ACTION_DOWNLOAD_COMPLETE
|
||||
mDownloadReceiver = new DownloadReceiver();
|
||||
mContext.registerReceiver(mDownloadReceiver,
|
||||
new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
|
||||
|
||||
// Register a wifi receiver
|
||||
mWifiReceiver = new WifiReceiver();
|
||||
IntentFilter mIntentFilter = new IntentFilter();
|
||||
mIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
|
||||
mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||
mIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
|
||||
mIntentFilter.addAction(WifiManager.SUPPLICANT_CONNECTION_CHANGE_ACTION);
|
||||
mIntentFilter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
|
||||
mContext.registerReceiver(mWifiReceiver, mIntentFilter);
|
||||
|
||||
// Get an instance of ConnectivityManager
|
||||
mCM = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
|
||||
// Get an instance of WifiManager
|
||||
mWifiManager =(WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
|
||||
mWifiManager.asyncConnect(mContext, new WifiServiceHandler());
|
||||
|
||||
mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE);
|
||||
|
||||
initializeNetworkStates();
|
||||
|
||||
mWifiManager.setWifiEnabled(true);
|
||||
|
||||
Log.v(LOG_TAG, "Clear Wifi before we start the test.");
|
||||
sleep(SHORT_TIMEOUT);
|
||||
removeConfiguredNetworksAndDisableWifi();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A wrapper of a broadcast receiver which provides network connectivity information
|
||||
* for all kinds of network: wifi, mobile, etc.
|
||||
*/
|
||||
private class ConnectivityReceiver extends BroadcastReceiver {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (isInitialStickyBroadcast()) {
|
||||
Log.d(LOG_TAG, "This is a sticky broadcast don't do anything.");
|
||||
return;
|
||||
}
|
||||
Log.v(LOG_TAG, "ConnectivityReceiver: onReceive() is called with " + intent);
|
||||
String action = intent.getAction();
|
||||
if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
|
||||
Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
|
||||
return;
|
||||
}
|
||||
if (intent.hasExtra(ConnectivityManager.EXTRA_NETWORK_INFO)) {
|
||||
mNetworkInfo = (NetworkInfo)
|
||||
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
|
||||
}
|
||||
|
||||
if (intent.hasExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO)) {
|
||||
mOtherNetworkInfo = (NetworkInfo)
|
||||
intent.getParcelableExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO);
|
||||
}
|
||||
|
||||
Log.v(LOG_TAG, "mNetworkInfo: " + mNetworkInfo.toString());
|
||||
recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
|
||||
if (mOtherNetworkInfo != null) {
|
||||
Log.v(LOG_TAG, "mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
|
||||
recordNetworkState(mOtherNetworkInfo.getType(), mOtherNetworkInfo.getState());
|
||||
}
|
||||
notifyNetworkConnectivityChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper of a broadcast receiver which provides wifi information.
|
||||
*/
|
||||
private class WifiReceiver extends BroadcastReceiver {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
Log.v("WifiReceiver", "onReceive() is calleld with " + intent);
|
||||
if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
|
||||
Log.v(LOG_TAG, "Scan results are available");
|
||||
notifyScanResult();
|
||||
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
|
||||
mWifiNetworkInfo =
|
||||
(NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
|
||||
Log.v(LOG_TAG, "mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
|
||||
if (mWifiNetworkInfo.getState() == State.CONNECTED) {
|
||||
intent.getStringExtra(WifiManager.EXTRA_BSSID);
|
||||
}
|
||||
notifyWifiState();
|
||||
} else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
|
||||
mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
|
||||
WifiManager.WIFI_STATE_UNKNOWN);
|
||||
notifyWifiState();
|
||||
} else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
|
||||
notifyWifiAPState();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper of a broadcast receiver which provides download manager information.
|
||||
*/
|
||||
private class DownloadReceiver extends BroadcastReceiver {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
Log.v("DownloadReceiver", "onReceive() is called with " + intent);
|
||||
// Download complete
|
||||
if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
|
||||
notifiyDownloadState();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class WifiServiceHandler extends Handler {
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
|
||||
if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
|
||||
// AsyncChannel in msg.obj
|
||||
} else {
|
||||
Log.v(LOG_TAG, "Failed to establish AsyncChannel connection");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Ignore
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize all the network states.
|
||||
*/
|
||||
public void initializeNetworkStates() {
|
||||
// For each network type, initialize network states to UNKNOWN, and no verification
|
||||
// flag is set.
|
||||
for (int networkType = NUM_NETWORK_TYPES - 1; networkType >= 0; networkType--) {
|
||||
mConnectivityState[networkType] = new NetworkState();
|
||||
Log.v(LOG_TAG, "Initialize network state for " + networkType + ": " +
|
||||
mConnectivityState[networkType].toString());
|
||||
}
|
||||
}
|
||||
|
||||
public void recordNetworkState(int networkType, State networkState) {
|
||||
// deposit a network state
|
||||
Log.v(LOG_TAG, "record network state for network " + networkType +
|
||||
", state is " + networkState);
|
||||
mConnectivityState[networkType].recordState(networkState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the state transition criteria
|
||||
*
|
||||
* @param networkType
|
||||
* @param initState
|
||||
* @param transitionDir
|
||||
* @param targetState
|
||||
*/
|
||||
public void setStateTransitionCriteria(int networkType, State initState,
|
||||
StateTransitionDirection transitionDir, State targetState) {
|
||||
mConnectivityState[networkType].setStateTransitionCriteria(
|
||||
initState, transitionDir, targetState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the states recorded.
|
||||
* @param networkType
|
||||
* @return
|
||||
*/
|
||||
public boolean validateNetworkStates(int networkType) {
|
||||
Log.v(LOG_TAG, "validate network state for " + networkType + ": ");
|
||||
return mConnectivityState[networkType].validateStateTransition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the failure reason for the transition.
|
||||
* @param networkType
|
||||
* @return result from network state validation
|
||||
*/
|
||||
public String getTransitionFailureReason(int networkType) {
|
||||
Log.v(LOG_TAG, "get network state transition failure reason for " + networkType + ": " +
|
||||
mConnectivityState[networkType].toString());
|
||||
return mConnectivityState[networkType].getFailureReason();
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notification via the mConnectivityMonitor when the network connectivity changes.
|
||||
*/
|
||||
private void notifyNetworkConnectivityChange() {
|
||||
synchronized(mConnectivityMonitor) {
|
||||
Log.v(LOG_TAG, "notify network connectivity changed");
|
||||
mConnectivityMonitor.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notification when a scan for the wifi network is done.
|
||||
*/
|
||||
private void notifyScanResult() {
|
||||
synchronized (this) {
|
||||
Log.v(LOG_TAG, "notify that scan results are available");
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notification via the mWifiMonitor when the wifi state changes.
|
||||
*/
|
||||
private void notifyWifiState() {
|
||||
synchronized (mWifiMonitor) {
|
||||
Log.v(LOG_TAG, "notify wifi state changed.");
|
||||
mWifiMonitor.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notification via the mDownloadMonitor when a download is complete.
|
||||
*/
|
||||
private void notifiyDownloadState() {
|
||||
synchronized (mDownloadMonitor) {
|
||||
Log.v(LOG_TAG, "notifiy download manager state changed.");
|
||||
mDownloadMonitor.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a notification when the wifi ap state changes.
|
||||
*/
|
||||
private void notifyWifiAPState() {
|
||||
synchronized (this) {
|
||||
Log.v(LOG_TAG, "notify wifi AP state changed.");
|
||||
this.notify();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a download on a given url and wait for completion.
|
||||
*
|
||||
* @param targetUrl the target to download.x
|
||||
* @param timeout to wait for download to finish
|
||||
* @return true if we successfully downloaded the requestedUrl, false otherwise.
|
||||
*/
|
||||
public boolean startDownloadAndWait(String targetUrl, long timeout) {
|
||||
if (targetUrl.length() == 0 || targetUrl == null) {
|
||||
Log.v(LOG_TAG, "Empty or Null target url requested to DownloadManager");
|
||||
return true;
|
||||
}
|
||||
Request request = new Request(Uri.parse(targetUrl));
|
||||
long enqueue = mDownloadManager.enqueue(request);
|
||||
Log.v(LOG_TAG, "Sending download request of " + targetUrl + " to DownloadManager");
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (true) {
|
||||
if ((System.currentTimeMillis() - startTime) > timeout) {
|
||||
Log.v(LOG_TAG, "startDownloadAndWait timed out, failed to fetch " + targetUrl +
|
||||
" within " + timeout);
|
||||
return downloadSuccessful(enqueue);
|
||||
}
|
||||
Log.v(LOG_TAG, "Waiting for the download to finish " + targetUrl);
|
||||
synchronized (mDownloadMonitor) {
|
||||
try {
|
||||
mDownloadMonitor.wait(SHORT_TIMEOUT);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (!downloadSuccessful(enqueue)) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the Download Manager's UID.
|
||||
* @return the Download Manager's UID
|
||||
*/
|
||||
public int downloadManagerUid() {
|
||||
try {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
ApplicationInfo appInfo = pm.getApplicationInfo(DOWNLOAD_MANAGER_PKG_NAME,
|
||||
PackageManager.GET_META_DATA);
|
||||
return appInfo.uid;
|
||||
} catch (NameNotFoundException e) {
|
||||
Log.d(LOG_TAG, "Did not find the package for the download service.");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a given download was successful by querying the DownloadManager.
|
||||
*
|
||||
* @param enqueue the id used to identify/query the DownloadManager with.
|
||||
* @return true if download was successful, false otherwise.
|
||||
*/
|
||||
private boolean downloadSuccessful(long enqueue) {
|
||||
Query query = new Query();
|
||||
query.setFilterById(enqueue);
|
||||
Cursor c = mDownloadManager.query(query);
|
||||
if (c.moveToFirst()) {
|
||||
int columnIndex = c.getColumnIndex(DownloadManager.COLUMN_STATUS);
|
||||
if (DownloadManager.STATUS_SUCCESSFUL == c.getInt(columnIndex)) {
|
||||
Log.v(LOG_TAG, "Successfully downloaded file!");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for network connectivity state.
|
||||
* @param networkType the network to check for
|
||||
* @param expectedState the desired state
|
||||
* @param timeout in milliseconds
|
||||
* @return true if the network connectivity state matched what was expected
|
||||
*/
|
||||
public boolean waitForNetworkState(int networkType, State expectedState, long timeout) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (true) {
|
||||
if ((System.currentTimeMillis() - startTime) > timeout) {
|
||||
Log.v(LOG_TAG, "waitForNetworkState time out, the state of network type " + networkType +
|
||||
" is: " + mCM.getNetworkInfo(networkType).getState());
|
||||
if (mCM.getNetworkInfo(networkType).getState() != expectedState) {
|
||||
return false;
|
||||
} else {
|
||||
// the broadcast has been sent out. the state has been changed.
|
||||
Log.v(LOG_TAG, "networktype: " + networkType + " state: " +
|
||||
mCM.getNetworkInfo(networkType));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
|
||||
" to be " + expectedState.toString());
|
||||
synchronized (mConnectivityMonitor) {
|
||||
try {
|
||||
mConnectivityMonitor.wait(SHORT_TIMEOUT);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if ((mNetworkInfo.getType() != networkType) ||
|
||||
(mNetworkInfo.getState() != expectedState)) {
|
||||
Log.v(LOG_TAG, "network state for " + mNetworkInfo.getType() +
|
||||
"is: " + mNetworkInfo.getState());
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for a given wifi state to occur within a given timeout.
|
||||
* @param expectedState the expected wifi state.
|
||||
* @param timeout for the state to be set in milliseconds.
|
||||
* @return true if the state was achieved within the timeout, false otherwise.
|
||||
*/
|
||||
public boolean waitForWifiState(int expectedState, long timeout) {
|
||||
// Wait for Wifi state: WIFI_STATE_DISABLED, WIFI_STATE_DISABLING, WIFI_STATE_ENABLED,
|
||||
// WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (true) {
|
||||
if ((System.currentTimeMillis() - startTime) > timeout) {
|
||||
if (mWifiState != expectedState) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
|
||||
synchronized (mWifiMonitor) {
|
||||
try {
|
||||
mWifiMonitor.wait(SHORT_TIMEOUT);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (mWifiState != expectedState) {
|
||||
Log.v(LOG_TAG, "Wifi state is: " + mWifiState);
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to determine if we are connected to a mobile network.
|
||||
* @return true if connected to a mobile network, false otherwise.
|
||||
*/
|
||||
public boolean isConnectedToMobile() {
|
||||
return (mNetworkInfo.getType() == ConnectivityManager.TYPE_MOBILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to determine if we are connected to wifi.
|
||||
* @return true if connected to wifi, false otherwise.
|
||||
*/
|
||||
public boolean isConnectedToWifi() {
|
||||
return (mNetworkInfo.getType() == ConnectivityManager.TYPE_WIFI);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Associate the device to given SSID
|
||||
* If the device is already associated with a WiFi, disconnect and forget it,
|
||||
* We don't verify whether the connection is successful or not, leave this to the test
|
||||
*/
|
||||
public boolean connectToWifi(String knownSSID) {
|
||||
WifiConfiguration config = new WifiConfiguration();
|
||||
config.SSID = knownSSID;
|
||||
config.allowedKeyManagement.set(KeyMgmt.NONE);
|
||||
return connectToWifiWithConfiguration(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to Wi-Fi with the given configuration.
|
||||
* @param config
|
||||
* @return true if we ar connected to a given
|
||||
*/
|
||||
public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
|
||||
// The SSID in the configuration is a pure string, need to convert it to a quoted string.
|
||||
String ssid = config.SSID;
|
||||
config.SSID = convertToQuotedString(ssid);
|
||||
|
||||
// If wifi is not enabled, enable it
|
||||
if (!mWifiManager.isWifiEnabled()) {
|
||||
Log.v(LOG_TAG, "Wifi is not enabled, enable it");
|
||||
mWifiManager.setWifiEnabled(true);
|
||||
// wait for the wifi state change before start scanning.
|
||||
if (!waitForWifiState(WifiManager.WIFI_STATE_ENABLED, 2 * SHORT_TIMEOUT)) {
|
||||
Log.v(LOG_TAG, "Wait for WIFI_STATE_ENABLED failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
boolean foundApInScanResults = false;
|
||||
for (int retry = 0; retry < 5; retry++) {
|
||||
List<ScanResult> netList = mWifiManager.getScanResults();
|
||||
if (netList != null) {
|
||||
Log.v(LOG_TAG, "size of scan result list: " + netList.size());
|
||||
for (int i = 0; i < netList.size(); i++) {
|
||||
ScanResult sr= netList.get(i);
|
||||
if (sr.SSID.equals(ssid)) {
|
||||
Log.v(LOG_TAG, "Found " + ssid + " in the scan result list.");
|
||||
Log.v(LOG_TAG, "Retry: " + retry);
|
||||
foundApInScanResults = true;
|
||||
mWifiManager.connectNetwork(config);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (foundApInScanResults) {
|
||||
return true;
|
||||
} else {
|
||||
// Start an active scan
|
||||
mWifiManager.startScanActive();
|
||||
mScanResultIsAvailable = false;
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (!mScanResultIsAvailable) {
|
||||
if ((System.currentTimeMillis() - startTime) > WIFI_SCAN_TIMEOUT) {
|
||||
Log.v(LOG_TAG, "wait for scan results timeout");
|
||||
return false;
|
||||
}
|
||||
// wait for the scan results to be available
|
||||
synchronized (this) {
|
||||
// wait for the scan result to be available
|
||||
try {
|
||||
this.wait(WAIT_FOR_SCAN_RESULT);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if ((mWifiManager.getScanResults() == null) ||
|
||||
(mWifiManager.getScanResults().size() <= 0)) {
|
||||
continue;
|
||||
}
|
||||
mScanResultIsAvailable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnect from the current AP and remove configured networks.
|
||||
*/
|
||||
public boolean disconnectAP() {
|
||||
// remove saved networks
|
||||
List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
|
||||
Log.v(LOG_TAG, "size of wifiConfigList: " + wifiConfigList.size());
|
||||
for (WifiConfiguration wifiConfig: wifiConfigList) {
|
||||
Log.v(LOG_TAG, "Remove wifi configuration: " + wifiConfig.networkId);
|
||||
int netId = wifiConfig.networkId;
|
||||
mWifiManager.forgetNetwork(netId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable Wifi
|
||||
* @return true if Wifi is enabled successfully
|
||||
*/
|
||||
public boolean enableWifi() {
|
||||
return mWifiManager.setWifiEnabled(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Wifi
|
||||
* @return true if Wifi is disabled successfully
|
||||
*/
|
||||
public boolean disableWifi() {
|
||||
return mWifiManager.setWifiEnabled(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove configured networks and disable wifi
|
||||
*/
|
||||
public boolean removeConfiguredNetworksAndDisableWifi() {
|
||||
if (!disconnectAP()) {
|
||||
return false;
|
||||
}
|
||||
sleep(SHORT_TIMEOUT);
|
||||
if (!mWifiManager.setWifiEnabled(false)) {
|
||||
return false;
|
||||
}
|
||||
sleep(SHORT_TIMEOUT);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the current thread sleep.
|
||||
* @param sleeptime the time to sleep in milliseconds
|
||||
*/
|
||||
private void sleep(long sleeptime) {
|
||||
try {
|
||||
Thread.sleep(sleeptime);
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set airplane mode on device, caller is responsible to ensuring correct state.
|
||||
* @param context {@link Context}
|
||||
* @param enableAM to enable or disable airplane mode.
|
||||
*/
|
||||
public void setAirplaneMode(Context context, boolean enableAM) {
|
||||
//set the airplane mode
|
||||
Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
|
||||
enableAM ? 1 : 0);
|
||||
// Post the intent
|
||||
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||
intent.putExtra("state", enableAM);
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add quotes around the string.
|
||||
* @param string to convert
|
||||
* @return string with quotes around it
|
||||
*/
|
||||
protected static String convertToQuotedString(String string) {
|
||||
return "\"" + string + "\"";
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
// Unregister receivers if defined.
|
||||
if (mConnectivityReceiver != null) {
|
||||
mContext.unregisterReceiver(mConnectivityReceiver);
|
||||
}
|
||||
if (mWifiReceiver != null) {
|
||||
mContext.unregisterReceiver(mWifiReceiver);
|
||||
}
|
||||
if (mDownloadReceiver != null) {
|
||||
mContext.unregisterReceiver(mDownloadReceiver);
|
||||
}
|
||||
Log.v(LOG_TAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user