140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen/* 240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Copyright (C) 2010 The Android Open Source Project 340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Licensed under the Apache License, Version 2.0 (the "License"); 540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * you may not use this file except in compliance with the License. 640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * You may obtain a copy of the License at 740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * http://www.apache.org/licenses/LICENSE-2.0 940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 1040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Unless required by applicable law or agreed to in writing, software 1140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * distributed under the License is distributed on an "AS IS" BASIS, 1240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * See the License for the specific language governing permissions and 1440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * limitations under the License. 1540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 1640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 1731fd85f39b554e09b2e6c1c2ccf5c186859880faSteve Howardpackage android.app; 1840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 1931fd85f39b554e09b2e6c1c2ccf5c186859880faSteve Howardimport android.app.DownloadManager.Query; 2031fd85f39b554e09b2e6c1c2ccf5c186859880faSteve Howardimport android.app.DownloadManager.Request; 2140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.content.BroadcastReceiver; 2240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.content.Context; 2340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.content.Intent; 2440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.content.IntentFilter; 2540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.database.Cursor; 2640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.net.ConnectivityManager; 2740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.net.NetworkInfo; 2831fd85f39b554e09b2e6c1c2ccf5c186859880faSteve Howardimport android.net.Uri; 2940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.net.wifi.WifiManager; 30df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyenimport android.os.Bundle; 3140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.os.Environment; 3240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.os.ParcelFileDescriptor; 3340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.os.SystemClock; 3440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.os.ParcelFileDescriptor.AutoCloseInputStream; 3540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.provider.Settings; 3640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.test.InstrumentationTestCase; 3740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport android.util.Log; 3840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 3940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.io.DataInputStream; 4040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.io.DataOutputStream; 4140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.io.File; 4240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.io.FileInputStream; 4340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.io.FileOutputStream; 4440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.io.IOException; 4540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.net.URL; 4640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.util.concurrent.TimeoutException; 47df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyenimport java.util.Collections; 48df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyenimport java.util.HashSet; 4940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.util.Iterator; 5040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.util.List; 5140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.util.Random; 52df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyenimport java.util.Set; 5340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport java.util.Vector; 5440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 5540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport junit.framework.AssertionFailedError; 5640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 5740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport coretestutils.http.MockResponse; 5840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenimport coretestutils.http.MockWebServer; 5940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 6040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen/** 6140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Base class for Instrumented tests for the Download Manager. 6240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 6340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyenpublic class DownloadManagerBaseTest extends InstrumentationTestCase { 6440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 6540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected DownloadManager mDownloadManager = null; 6640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected MockWebServer mServer = null; 6740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected String mFileType = "text/plain"; 6840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected Context mContext = null; 6963e5d79a163461651cd8bd89d3de691ef7649109Neal Nguyen protected MultipleDownloadsCompletedReceiver mReceiver = null; 7040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int DEFAULT_FILE_SIZE = 130 * 1024; // 130kb 7140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int FILE_BLOCK_READ_SIZE = 1024 * 1024; 7240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 7340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final String LOG_TAG = "android.net.DownloadManagerBaseTest"; 7440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int HTTP_OK = 200; 75df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen protected static final int HTTP_REDIRECT = 307; 7640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int HTTP_PARTIAL_CONTENT = 206; 7740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int HTTP_NOT_FOUND = 404; 7840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int HTTP_SERVICE_UNAVAILABLE = 503; 7940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected String DEFAULT_FILENAME = "somefile.txt"; 8040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 8140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int DEFAULT_MAX_WAIT_TIME = 2 * 60 * 1000; // 2 minutes 8240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int DEFAULT_WAIT_POLL_TIME = 5 * 1000; // 5 seconds 8340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 8440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int WAIT_FOR_DOWNLOAD_POLL_TIME = 1 * 1000; // 1 second 8540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 5 * 60 * 1000; // 5 minutes 86bd06f02d02e07ca15e420ee9e50e35253646ba64Neal Nguyen protected static final int MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME = 15 * 60 * 1000; // 15 minutes 8740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 8840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Just a few popular file types used to return from a download 8940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected enum DownloadFileType { 9040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen PLAINTEXT, 9140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen APK, 9240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen GIF, 9340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen GARBAGE, 9440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen UNRECOGNIZED, 9540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen ZIP 9640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 9740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 9840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected enum DataType { 9940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen TEXT, 10040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen BINARY 10140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 10240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 10340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public static class LoggingRng extends Random { 10440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 10540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 10640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Constructor 10740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 10840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Creates RNG with self-generated seed value. 10940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 11040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public LoggingRng() { 11140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen this(SystemClock.uptimeMillis()); 11240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 11340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 11440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 11540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Constructor 11640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 11740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Creats RNG with given initial seed value 11840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 11940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param seed The initial seed value 12040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 12140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public LoggingRng(long seed) { 12240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen super(seed); 12340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "Seeding RNG with value: " + seed); 12440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 12540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 12640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 12740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public static class MultipleDownloadsCompletedReceiver extends BroadcastReceiver { 12840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen private volatile int mNumDownloadsCompleted = 0; 129df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen private Set<Long> downloadIds = Collections.synchronizedSet(new HashSet<Long>()); 13040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 13140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 13240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * {@inheritDoc} 13340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 13440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen @Override 13540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public void onReceive(Context context, Intent intent) { 13640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (intent.getAction().equalsIgnoreCase(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { 13763e5d79a163461651cd8bd89d3de691ef7649109Neal Nguyen synchronized(this) { 13865c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen long id = intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID); 13965c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen Log.i(LOG_TAG, "Received Notification for download: " + id); 14065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen if (!downloadIds.contains(id)) { 14165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen ++mNumDownloadsCompleted; 14265c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen Log.i(LOG_TAG, "MultipleDownloadsCompletedReceiver got intent: " + 14365c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen intent.getAction() + " --> total count: " + mNumDownloadsCompleted); 14465c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen downloadIds.add(id); 14565c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen 14665c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen DownloadManager dm = (DownloadManager)context.getSystemService( 14765c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen Context.DOWNLOAD_SERVICE); 14865c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen 14965c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen Cursor cursor = dm.query(new Query().setFilterById(id)); 15065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen try { 15165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen if (cursor.moveToFirst()) { 15265c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen int status = cursor.getInt(cursor.getColumnIndex( 15365c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen DownloadManager.COLUMN_STATUS)); 15465c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen Log.i(LOG_TAG, "Download status is: " + status); 15565c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } else { 15665c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen fail("No status found for completed download!"); 15765c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } 15865c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } finally { 15965c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen cursor.close(); 16065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } 16165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } else { 16265c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen Log.i(LOG_TAG, "Notification for id: " + id + " has already been made."); 16365c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } 16463e5d79a163461651cd8bd89d3de691ef7649109Neal Nguyen } 16540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 16640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 16740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 16840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 16940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Gets the number of times the {@link #onReceive} callback has been called for the 17040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * {@link DownloadManager.ACTION_DOWNLOAD_COMPLETED} action, indicating the number of 17140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * downloads completed thus far. 17240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 17340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return the number of downloads completed so far. 17440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 17540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public int numDownloadsCompleted() { 17640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return mNumDownloadsCompleted; 17740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 178df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen 179df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen /** 180df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen * Gets the list of download IDs. 181df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen * @return A Set<Long> with the ids of the completed downloads. 182df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen */ 183df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen public Set<Long> getDownloadIds() { 184bd06f02d02e07ca15e420ee9e50e35253646ba64Neal Nguyen synchronized(this) { 185df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen Set<Long> returnIds = new HashSet<Long>(downloadIds); 186df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen return returnIds; 187df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen } 188df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen } 189df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen 19040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 19140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 19240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public static class WiFiChangedReceiver extends BroadcastReceiver { 19340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen private Context mContext = null; 19440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 19540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 19640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Constructor 19740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 19840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Sets the current state of WiFi. 19940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 20040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param context The current app {@link Context}. 20140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 20240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public WiFiChangedReceiver(Context context) { 20340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mContext = context; 20440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 20540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 20640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 20740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * {@inheritDoc} 20840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 20940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen @Override 21040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public void onReceive(Context context, Intent intent) { 21140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (intent.getAction().equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION)) { 21240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "ConnectivityManager state change: " + intent.getAction()); 21340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen synchronized (this) { 21440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen this.notify(); 21540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 21640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 21740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 21840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 21940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 22040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Gets the current state of WiFi. 22140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 22240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return Returns true if WiFi is on, false otherwise. 22340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 22440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public boolean getWiFiIsOn() { 22540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen ConnectivityManager connManager = (ConnectivityManager)mContext.getSystemService( 22640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Context.CONNECTIVITY_SERVICE); 22740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen NetworkInfo info = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); 228bd06f02d02e07ca15e420ee9e50e35253646ba64Neal Nguyen Log.i(LOG_TAG, "WiFi Connection state is currently: " + info.isConnected()); 22940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return info.isConnected(); 23040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 23140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 23240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 23340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 23440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * {@inheritDoc} 23540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 23640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen @Override 23740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen public void setUp() throws Exception { 23840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mContext = getInstrumentation().getContext(); 23940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE); 24040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mServer = new MockWebServer(); 24163e5d79a163461651cd8bd89d3de691ef7649109Neal Nguyen mReceiver = registerNewMultipleDownloadsReceiver(); 24240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Note: callers overriding this should call mServer.play() with the desired port # 24340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 24440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 24540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 246df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen * Helper to enqueue a response from the MockWebServer with no body. 247df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen * 248df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen * @param status The HTTP status code to return for this response 249df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen * @return Returns the mock web server response that was queued (which can be modified) 250df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen */ 251df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen protected MockResponse enqueueResponse(int status) { 252df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen return doEnqueueResponse(status); 253df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen 254df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen } 255df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen 256df7a865bbf45b57c60d294d5ac721e67e69a2dd6Neal Nguyen /** 25740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to enqueue a response from the MockWebServer. 25840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 25940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param status The HTTP status code to return for this response 26040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param body The body to return in this response 26140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return Returns the mock web server response that was queued (which can be modified) 26240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 26340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected MockResponse enqueueResponse(int status, byte[] body) { 26440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return doEnqueueResponse(status).setBody(body); 26540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 26640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 26740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 26840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 26940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to enqueue a response from the MockWebServer. 27040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 27140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param status The HTTP status code to return for this response 27240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param bodyFile The body to return in this response 27340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return Returns the mock web server response that was queued (which can be modified) 27440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 27540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected MockResponse enqueueResponse(int status, File bodyFile) { 27640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return doEnqueueResponse(status).setBody(bodyFile); 27740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 27840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 27940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 28040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper for enqueue'ing a response from the MockWebServer. 28140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 28240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param status The HTTP status code to return for this response 28340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return Returns the mock web server response that was queued (which can be modified) 28440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 28540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected MockResponse doEnqueueResponse(int status) { 28640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen MockResponse response = new MockResponse().setResponseCode(status); 28740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen response.addHeader("Content-type", mFileType); 28840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mServer.enqueue(response); 28940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return response; 29040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 29140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 29240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 29340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to generate a random blob of bytes. 29440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 29540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param size The size of the data to generate 29640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param type The type of data to generate: currently, one of {@link DataType.TEXT} or 29740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * {@link DataType.BINARY}. 29840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return The random data that is generated. 29940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 30040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected byte[] generateData(int size, DataType type) { 30140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return generateData(size, type, null); 30240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 30340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 30440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 30540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to generate a random blob of bytes using a given RNG. 30640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 30740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param size The size of the data to generate 30840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param type The type of data to generate: currently, one of {@link DataType.TEXT} or 30940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * {@link DataType.BINARY}. 31040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param rng (optional) The RNG to use; pass null to use 31140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return The random data that is generated. 31240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 31340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected byte[] generateData(int size, DataType type, Random rng) { 31440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int min = Byte.MIN_VALUE; 31540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int max = Byte.MAX_VALUE; 31640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 31740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Only use chars in the HTTP ASCII printable character range for Text 31840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (type == DataType.TEXT) { 31940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen min = 32; 32040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen max = 126; 32140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 32240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen byte[] result = new byte[size]; 32340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "Generating data of size: " + size); 32440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 32540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (rng == null) { 32640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen rng = new LoggingRng(); 32740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 32840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 32940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen for (int i = 0; i < size; ++i) { 33040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen result[i] = (byte) (min + rng.nextInt(max - min + 1)); 33140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 33240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return result; 33340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 33440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 33540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 33640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to verify the size of a file. 33740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 33840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param pfd The input file to compare the size of 33940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param size The expected size of the file 34040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 34140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void verifyFileSize(ParcelFileDescriptor pfd, long size) { 34240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(pfd.getStatSize(), size); 34340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 34440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 34540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 34640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to verify the contents of a downloaded file versus a byte[]. 34740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 34840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param actual The file of whose contents to verify 34940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param expected The data we expect to find in the aforementioned file 35040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @throws IOException if there was a problem reading from the file 35140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 35240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void verifyFileContents(ParcelFileDescriptor actual, byte[] expected) 35340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen throws IOException { 35440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen AutoCloseInputStream input = new ParcelFileDescriptor.AutoCloseInputStream(actual); 35540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen long fileSize = actual.getStatSize(); 35640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 35740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertTrue(fileSize <= Integer.MAX_VALUE); 35840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(expected.length, fileSize); 35940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 36040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen byte[] actualData = new byte[expected.length]; 36140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(input.read(actualData), fileSize); 36240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen compareByteArrays(actualData, expected); 36340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 36440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 36540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 36640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to compare 2 byte arrays. 36740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 36840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param actual The array whose data we want to verify 36940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param expected The array of data we expect to see 37040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 37140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void compareByteArrays(byte[] actual, byte[] expected) { 37240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(actual.length, expected.length); 37340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int length = actual.length; 37440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen for (int i = 0; i < length; ++i) { 37540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // assert has a bit of overhead, so only do the assert when the values are not the same 37640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (actual[i] != expected[i]) { 37740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen fail("Byte arrays are not equal."); 37840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 37940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 38040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 38140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 38240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 38340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Verifies the contents of a downloaded file versus the contents of a File. 38440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 38540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param pfd The file whose data we want to verify 38640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param file The file containing the data we expect to see in the aforementioned file 38740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @throws IOException If there was a problem reading either of the two files 38840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 38940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void verifyFileContents(ParcelFileDescriptor pfd, File file) throws IOException { 39040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen byte[] actual = new byte[FILE_BLOCK_READ_SIZE]; 39140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen byte[] expected = new byte[FILE_BLOCK_READ_SIZE]; 39240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 39340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen AutoCloseInputStream input = new ParcelFileDescriptor.AutoCloseInputStream(pfd); 39440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 39540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(file.length(), pfd.getStatSize()); 39640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 39740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen DataInputStream inFile = new DataInputStream(new FileInputStream(file)); 39840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int actualRead = 0; 39940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int expectedRead = 0; 40040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 40140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (((actualRead = input.read(actual)) != -1) && 40240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen ((expectedRead = inFile.read(expected)) != -1)) { 40340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(actualRead, expectedRead); 40440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen compareByteArrays(actual, expected); 40540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 40640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 40740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 40840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 40940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Sets the MIME type of file that will be served from the mock server 41040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 41140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param type The MIME type to return from the server 41240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 41340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void setServerMimeType(DownloadFileType type) { 41440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mFileType = getMimeMapping(type); 41540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 41640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 41740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 41840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Gets the MIME content string for a given type 41940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 42040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param type The MIME type to return 42140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return the String representation of that MIME content type 42240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 42340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected String getMimeMapping(DownloadFileType type) { 42440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen switch (type) { 42540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen case APK: 42640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return "application/vnd.android.package-archive"; 42740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen case GIF: 42840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return "image/gif"; 42940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen case ZIP: 43040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return "application/x-zip-compressed"; 43140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen case GARBAGE: 43240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return "zip\\pidy/doo/da"; 43340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen case UNRECOGNIZED: 43440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return "application/new.undefined.type.of.app"; 43540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 43640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return "text/plain"; 43740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 43840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 43940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 44040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Gets the Uri that should be used to access the mock server 44140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 44240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param filename The name of the file to try to retrieve from the mock server 44340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return the Uri to use for access the file on the mock server 44440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 44540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected Uri getServerUri(String filename) throws Exception { 44640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen URL url = mServer.getUrl("/" + filename); 44740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return Uri.parse(url.toString()); 44840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 44940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 45040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 45140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Gets the Uri that should be used to access the mock server 45240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 45340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param filename The name of the file to try to retrieve from the mock server 45440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return the Uri to use for access the file on the mock server 45540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 45640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void logDBColumnData(Cursor cursor, String column) { 45740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int index = cursor.getColumnIndex(column); 45840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "columnName: " + column); 45940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "columnValue: " + cursor.getString(index)); 46040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 46140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 46240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 46340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to create and register a new MultipleDownloadCompletedReciever 46440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 46540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * This is used to track many simultaneous downloads by keeping count of all the downloads 46640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * that have completed. 46740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 46840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return A new receiver that records and can be queried on how many downloads have completed. 46940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 47040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected MultipleDownloadsCompletedReceiver registerNewMultipleDownloadsReceiver() { 47140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen MultipleDownloadsCompletedReceiver receiver = new MultipleDownloadsCompletedReceiver(); 47240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mContext.registerReceiver(receiver, new IntentFilter( 47340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen DownloadManager.ACTION_DOWNLOAD_COMPLETE)); 47440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return receiver; 47540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 47640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 47740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 47840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to verify a standard single-file download from the mock server, and clean up after 47940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * verification 48040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 48140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Note that this also calls the Download manager's remove, which cleans up the file from cache. 48240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 48340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param requestId The id of the download to remove 48440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param fileData The data to verify the file contains 48540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 48640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void verifyAndCleanupSingleFileDownload(long requestId, byte[] fileData) 48740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen throws Exception { 48840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int fileSize = fileData.length; 48940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(requestId); 49040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Cursor cursor = mDownloadManager.query(new Query().setFilterById(requestId)); 49140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 49240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen try { 49340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(1, cursor.getCount()); 49440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertTrue(cursor.moveToFirst()); 49540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 49640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mServer.checkForExceptions(); 49740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 49840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen verifyFileSize(pfd, fileSize); 49940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen verifyFileContents(pfd, fileData); 50040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } finally { 50140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen pfd.close(); 50240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen cursor.close(); 50340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mDownloadManager.remove(requestId); 50440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 50540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 50640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 50740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 50840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Enables or disables WiFi. 50940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 51040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Note: Needs the following permissions: 51140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * android.permission.ACCESS_WIFI_STATE 51240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * android.permission.CHANGE_WIFI_STATE 51340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param enable true if it should be enabled, false if it should be disabled 51440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 51540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void setWiFiStateOn(boolean enable) throws Exception { 516bd06f02d02e07ca15e420ee9e50e35253646ba64Neal Nguyen Log.i(LOG_TAG, "Setting WiFi State to: " + enable); 51740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE); 51840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 51940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen manager.setWifiEnabled(enable); 52040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 52140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen String timeoutMessage = "Timed out waiting for Wifi to be " 52240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen + (enable ? "enabled!" : "disabled!"); 52340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 52440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen WiFiChangedReceiver receiver = new WiFiChangedReceiver(mContext); 52540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mContext.registerReceiver(receiver, new IntentFilter( 52640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen ConnectivityManager.CONNECTIVITY_ACTION)); 52740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 52840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen synchronized (receiver) { 52940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen long timeoutTime = SystemClock.elapsedRealtime() + DEFAULT_MAX_WAIT_TIME; 53040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen boolean timedOut = false; 53140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 53240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (receiver.getWiFiIsOn() != enable && !timedOut) { 53340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen try { 534bd06f02d02e07ca15e420ee9e50e35253646ba64Neal Nguyen receiver.wait(DEFAULT_WAIT_POLL_TIME); 53540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 53640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (SystemClock.elapsedRealtime() > timeoutTime) { 53740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen timedOut = true; 53840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 53940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 54040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen catch (InterruptedException e) { 54140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // ignore InterruptedExceptions 54240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 54340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 54440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (timedOut) { 54540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen fail(timeoutMessage); 54640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 54740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 54840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(enable, receiver.getWiFiIsOn()); 54940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 55040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 55140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 55240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to enables or disables airplane mode. If successful, it also broadcasts an intent 55340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * indicating that the mode has changed. 55440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 55540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Note: Needs the following permission: 55640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * android.permission.WRITE_SETTINGS 55740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param enable true if airplane mode should be ON, false if it should be OFF 55840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 55940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void setAirplaneModeOn(boolean enable) throws Exception { 56040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int state = enable ? 1 : 0; 56140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 56240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Change the system setting 56340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 56440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen state); 56540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 56640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen String timeoutMessage = "Timed out waiting for airplane mode to be " + 56740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen (enable ? "enabled!" : "disabled!"); 56840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 56940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // wait for airplane mode to change state 57040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int currentWaitTime = 0; 57140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (Settings.System.getInt(mContext.getContentResolver(), 57240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Settings.System.AIRPLANE_MODE_ON, -1) != state) { 57340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen timeoutWait(currentWaitTime, DEFAULT_WAIT_POLL_TIME, DEFAULT_MAX_WAIT_TIME, 57440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen timeoutMessage); 57540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 57640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 57740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Post the intent 57840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); 57940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen intent.putExtra("state", true); 58040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mContext.sendBroadcast(intent); 58140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 58240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 58340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 58440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to create a large file of random data on the SD card. 58540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 58640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param filename (optional) The name of the file to create on the SD card; pass in null to 58740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * use a default temp filename. 58840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param type The type of file to create 58940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param subdirectory If not null, the subdirectory under the SD card where the file should go 59040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return The File that was created 59140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @throws IOException if there was an error while creating the file. 59240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 59340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected File createFileOnSD(String filename, long fileSize, DataType type, 59440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen String subdirectory) throws IOException { 59540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 59640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Build up the file path and name 59740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen String sdPath = Environment.getExternalStorageDirectory().getPath(); 59840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen StringBuilder fullPath = new StringBuilder(sdPath); 59940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (subdirectory != null) { 60040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen fullPath.append(File.separatorChar).append(subdirectory); 60140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 60240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 60340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen File file = null; 60440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (filename == null) { 60540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen file = File.createTempFile("DMTEST_", null, new File(fullPath.toString())); 60640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 60740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen else { 60840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen fullPath.append(File.separatorChar).append(filename); 60940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen file = new File(fullPath.toString()); 61040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen file.createNewFile(); 61140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 61240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 61340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Fill the file with random data 61440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen DataOutputStream output = new DataOutputStream(new FileOutputStream(file)); 61540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen final int CHUNK_SIZE = 1000000; // copy random data in 1000000-char chunks 61640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen long remaining = fileSize; 61740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int nextChunkSize = CHUNK_SIZE; 61840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen byte[] randomData = null; 61940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Random rng = new LoggingRng(); 62040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 62140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen try { 62240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (remaining > 0) { 62340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (remaining < CHUNK_SIZE) { 62440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen nextChunkSize = (int)remaining; 62540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen remaining = 0; 62640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 62740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen else { 62840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen remaining -= CHUNK_SIZE; 62940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 63040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 63140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen randomData = generateData(nextChunkSize, type, rng); 63240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen output.write(randomData); 63340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 63440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } catch (IOException e) { 63540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.e(LOG_TAG, "Error writing to file " + file.getAbsolutePath()); 63640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen file.delete(); 63740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen throw e; 63840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } finally { 63940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen output.close(); 64040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 64140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return file; 64240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 64340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 64440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 64540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to wait for a particular download to finish, or else a timeout to occur 64640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 64765c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * Does not wait for a receiver notification of the download. 64865c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * 64940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param id The download id to query on (wait for) 65040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 65165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen protected void waitForDownloadOrTimeout_skipNotification(long id) throws TimeoutException, 65240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen InterruptedException { 65340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen waitForDownloadOrTimeout(id, WAIT_FOR_DOWNLOAD_POLL_TIME, MAX_WAIT_FOR_DOWNLOAD_TIME); 65440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 65540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 65640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 65740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to wait for a particular download to finish, or else a timeout to occur 65840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 65965c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * Also guarantees a notification has been posted for the download. 66065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * 66165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * @param id The download id to query on (wait for) 66265c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen */ 66365c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen protected void waitForDownloadOrTimeout(long id) throws TimeoutException, 66465c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen InterruptedException { 66565c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen waitForDownloadOrTimeout_skipNotification(id); 66665c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen waitForReceiverNotifications(1); 66765c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } 66865c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen 66965c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen /** 67065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * Helper to wait for a particular download to finish, or else a timeout to occur 67165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * 67265c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * Also guarantees a notification has been posted for the download. 67365c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * 67440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param id The download id to query on (wait for) 67540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param poll The amount of time to wait 67640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete 67740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 67840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void waitForDownloadOrTimeout(long id, long poll, long timeoutMillis) 67940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen throws TimeoutException, InterruptedException { 68040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen doWaitForDownloadsOrTimeout(new Query().setFilterById(id), poll, timeoutMillis); 68165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen waitForReceiverNotifications(1); 68240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 68340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 68440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 68540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to wait for all downloads to finish, or else a specified timeout to occur 68640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 68765c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * Makes no guaranee that notifications have been posted for all downloads. 68865c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * 68940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param poll The amount of time to wait 69040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete 69140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 69240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void waitForDownloadsOrTimeout(long poll, long timeoutMillis) throws TimeoutException, 69340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen InterruptedException { 69440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen doWaitForDownloadsOrTimeout(new Query(), poll, timeoutMillis); 69540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 69640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 69740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 69840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to wait for all downloads to finish, or else a timeout to occur, but does not throw 69940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 70065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * Also guarantees a notification has been posted for the download. 70165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * 70240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param id The id of the download to query against 70340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param poll The amount of time to wait 70440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete 70540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return true if download completed successfully (didn't timeout), false otherwise 70640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 70740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected boolean waitForDownloadOrTimeoutNoThrow(long id, long poll, long timeoutMillis) { 70840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen try { 70940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen doWaitForDownloadsOrTimeout(new Query().setFilterById(id), poll, timeoutMillis); 71065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen waitForReceiverNotifications(1); 71140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } catch (TimeoutException e) { 71240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return false; 71340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 71440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return true; 71540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 71640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 71740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 71840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper function to synchronously wait, or timeout if the maximum threshold has been exceeded. 71940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 72040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param currentTotalWaitTime The total time waited so far 72140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param poll The amount of time to wait 72240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param maxTimeoutMillis The total wait time threshold; if we've waited more than this long, 72340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * we timeout and fail 72440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param timedOutMessage The message to display in the failure message if we timeout 72540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return The new total amount of time we've waited so far 72640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @throws TimeoutException if timed out waiting for SD card to mount 72740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 72840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected int timeoutWait(int currentTotalWaitTime, long poll, long maxTimeoutMillis, 72940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen String timedOutMessage) throws TimeoutException { 73040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen long now = SystemClock.elapsedRealtime(); 73140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen long end = now + poll; 73240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 73340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // if we get InterruptedException's, ignore them and just keep sleeping 73440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (now < end) { 73540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen try { 73640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Thread.sleep(end - now); 73740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } catch (InterruptedException e) { 73840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // ignore interrupted exceptions 73940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 74040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen now = SystemClock.elapsedRealtime(); 74140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 74240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 74340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen currentTotalWaitTime += poll; 74440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (currentTotalWaitTime > maxTimeoutMillis) { 74540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen throw new TimeoutException(timedOutMessage); 74640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 74740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return currentTotalWaitTime; 74840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 74940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 75040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 75140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to wait for all downloads to finish, or else a timeout to occur 75240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 75340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param query The query to pass to the download manager 75440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param poll The poll time to wait between checks 75540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param timeoutMillis The max amount of time (in ms) to wait for the download(s) to complete 75640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 75740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void doWaitForDownloadsOrTimeout(Query query, long poll, long timeoutMillis) 75840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen throws TimeoutException { 75940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int currentWaitTime = 0; 76040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (true) { 76140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen query.setFilterByStatus(DownloadManager.STATUS_PENDING | DownloadManager.STATUS_PAUSED 76240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen | DownloadManager.STATUS_RUNNING); 76340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Cursor cursor = mDownloadManager.query(query); 76440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 76540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen try { 76665c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen if (cursor.getCount() == 0) { 76765c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen Log.i(LOG_TAG, "All downloads should be done..."); 76840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen break; 76940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 77040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen currentWaitTime = timeoutWait(currentWaitTime, poll, timeoutMillis, 77140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen "Timed out waiting for all downloads to finish"); 77240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } finally { 77340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen cursor.close(); 77440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 77540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 77640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 77740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 77840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 77940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Synchronously waits for external store to be mounted (eg: SD Card). 78040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 78140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @throws InterruptedException if interrupted 78240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @throws Exception if timed out waiting for SD card to mount 78340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 78440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void waitForExternalStoreMount() throws Exception { 78540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen String extStorageState = Environment.getExternalStorageState(); 78640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int currentWaitTime = 0; 78740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (!extStorageState.equals(Environment.MEDIA_MOUNTED)) { 78840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "Waiting for SD card..."); 78940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen currentWaitTime = timeoutWait(currentWaitTime, DEFAULT_WAIT_POLL_TIME, 79040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen DEFAULT_MAX_WAIT_TIME, "Timed out waiting for SD Card to be ready!"); 79140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen extStorageState = Environment.getExternalStorageState(); 79240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 79340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 79440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 79540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 79640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Synchronously waits for a download to start. 79740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 79840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param dlRequest the download request id used by Download Manager to track the download. 79940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @throws Exception if timed out while waiting for SD card to mount 80040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 80140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void waitForDownloadToStart(long dlRequest) throws Exception { 80240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Cursor cursor = getCursor(dlRequest); 80340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen try { 80440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); 80540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int value = cursor.getInt(columnIndex); 80640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int currentWaitTime = 0; 80740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 80840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (value != DownloadManager.STATUS_RUNNING && 80940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen (value != DownloadManager.STATUS_FAILED) && 81040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen (value != DownloadManager.STATUS_SUCCESSFUL)) { 81140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "Waiting for download to start..."); 81240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, 81340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for download to start!"); 81440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen cursor.requery(); 81540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertTrue(cursor.moveToFirst()); 81640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); 81740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen value = cursor.getInt(columnIndex); 81840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 81940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertFalse("Download failed immediately after start", 82040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen value == DownloadManager.STATUS_FAILED); 82140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } finally { 82240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen cursor.close(); 82340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 82440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 82540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 82640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 82765c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * Convenience function to wait for just 1 notification of a download. 82865c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * 82965c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * @throws Exception if timed out while waiting 83065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen */ 83165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen protected void waitForReceiverNotification() throws Exception { 83265c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen waitForReceiverNotifications(1); 83365c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } 83465c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen 83565c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen /** 83665c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * Synchronously waits for our receiver to receive notification for a given number of 83765c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * downloads. 83865c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * 83965c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * @param targetNumber The number of notifications for unique downloads to wait for; pass in 84065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * -1 to not wait for notification. 84165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen * @throws Exception if timed out while waiting 84265c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen */ 84365c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen protected void waitForReceiverNotifications(int targetNumber) throws TimeoutException { 84465c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen int count = mReceiver.numDownloadsCompleted(); 84565c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen int currentWaitTime = 0; 84665c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen 84765c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen while (count < targetNumber) { 84865c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen Log.i(LOG_TAG, "Waiting for notification of downloads..."); 84965c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, 85065c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for download notifications!" 85165c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen + " Received " + count + "notifications."); 85265c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen count = mReceiver.numDownloadsCompleted(); 85365c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } 85465c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen } 85565c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen 85665c36e6133be04e008bc164b62d42884ff06a13aNeal Nguyen /** 85740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Synchronously waits for a file to increase in size (such as to monitor that a download is 85840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * progressing). 85940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 86040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param file The file whose size to track. 86140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @throws Exception if timed out while waiting for the file to grow in size. 86240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 86340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void waitForFileToGrow(File file) throws Exception { 86440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int currentWaitTime = 0; 86540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 86640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // File may not even exist yet, so wait until it does (or we timeout) 86740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (!file.exists()) { 86840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "Waiting for file to exist..."); 86940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, 87040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for file to be created."); 87140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 87240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 87340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Get original file size... 87440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen long originalSize = file.length(); 87540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 87640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (file.length() <= originalSize) { 87740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "Waiting for file to be written to..."); 87840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME, 87940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for file to be written to."); 88040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 88140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 88240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 88340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 88440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to remove all downloads that are registered with the DL Manager. 88540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 88640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Note: This gives us a clean slate b/c it includes downloads that are pending, running, 88740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * paused, or have completed. 88840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 88940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void removeAllCurrentDownloads() { 89040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "Removing all current registered downloads..."); 89140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Cursor cursor = mDownloadManager.query(new Query()); 89240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen try { 89340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (cursor.moveToFirst()) { 89440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen do { 89540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int index = cursor.getColumnIndex(DownloadManager.COLUMN_ID); 89640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen long downloadId = cursor.getLong(index); 89740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 89840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen mDownloadManager.remove(downloadId); 89940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } while (cursor.moveToNext()); 90040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 90140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } finally { 90240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen cursor.close(); 90340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 90440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 90540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 90640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 90740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to perform a standard enqueue of data to the mock server. 90840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 90940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param body The body to return in the response from the server 91040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 91140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected long doStandardEnqueue(byte[] body) throws Exception { 91240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Prepare the mock server with a standard response 91340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen enqueueResponse(HTTP_OK, body); 91440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return doCommonStandardEnqueue(); 91540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 91640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 91740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 91840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to perform a standard enqueue of data to the mock server. 91940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 92040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param body The body to return in the response from the server, contained in the file 92140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 92240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected long doStandardEnqueue(File body) throws Exception { 92340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen // Prepare the mock server with a standard response 92440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen enqueueResponse(HTTP_OK, body); 92540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return doCommonStandardEnqueue(); 92640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 92740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 92840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 92940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to do the additional steps (setting title and Uri of default filename) when 93040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * doing a standard enqueue request to the server. 93140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 93240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected long doCommonStandardEnqueue() throws Exception { 93340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Uri uri = getServerUri(DEFAULT_FILENAME); 93440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Request request = new Request(uri); 93540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen request.setTitle(DEFAULT_FILENAME); 93640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 93740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen long dlRequest = mDownloadManager.enqueue(request); 93840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, "request ID: " + dlRequest); 93940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return dlRequest; 94040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 94140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 94240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 94340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to verify an int value in a Cursor 94440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 94540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param cursor The cursor containing the query results 94640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param columnName The name of the column to query 94740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param expected The expected int value 94840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 94940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void verifyInt(Cursor cursor, String columnName, int expected) { 95040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int index = cursor.getColumnIndex(columnName); 95140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int actual = cursor.getInt(index); 95240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(expected, actual); 95340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 95440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 95540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 95640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Helper to verify a String value in a Cursor 95740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 95840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param cursor The cursor containing the query results 95940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param columnName The name of the column to query 96040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param expected The expected String value 96140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 96240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected void verifyString(Cursor cursor, String columnName, String expected) { 96340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int index = cursor.getColumnIndex(columnName); 96440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen String actual = cursor.getString(index); 96540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Log.i(LOG_TAG, ": " + actual); 96640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen assertEquals(expected, actual); 96740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 96840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 96940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen /** 97040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * Performs a query based on ID and returns a Cursor for the query. 97140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * 97240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @param id The id of the download in DL Manager; pass -1 to query all downloads 97340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen * @return A cursor for the query results 97440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen */ 97540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen protected Cursor getCursor(long id) throws Exception { 97640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Query query = new Query(); 97740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (id != -1) { 97840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen query.setFilterById(id); 97940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 98040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 98140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Cursor cursor = mDownloadManager.query(query); 98240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen int currentWaitTime = 0; 98340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 98440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen try { 98540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen while (!cursor.moveToFirst()) { 98640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen Thread.sleep(DEFAULT_WAIT_POLL_TIME); 98740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen currentWaitTime += DEFAULT_WAIT_POLL_TIME; 98840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen if (currentWaitTime > DEFAULT_MAX_WAIT_TIME) { 98940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen fail("timed out waiting for a non-null query result"); 99040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 99140ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen cursor.requery(); 99240ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 99340ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } catch (Exception e) { 99440ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen cursor.close(); 99540ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen throw e; 99640ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 99740ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen return cursor; 99840ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen } 99940ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen 100040ef0f49ea9fa7c39eb0018fdb4df4b73a11a77dNeal Nguyen}