/* * Copyright (C) 2010 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.frameworks.downloadmanagertests; import android.app.DownloadManager; import android.app.DownloadManager.Request; import android.database.Cursor; import android.net.Uri; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.util.Log; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.HashSet; /** * Class to test downloading files from a real (not mock) external server. */ public class DownloadManagerTestApp extends DownloadManagerBaseTest { protected static String DOWNLOAD_STARTED_FLAG = "DMTEST_DOWNLOAD_STARTED"; protected static String LOG_TAG = "com.android.frameworks.downloadmanagertests.DownloadManagerTestApp"; protected static final String DOWNLOAD_FILENAME = "External93mb.apk"; protected static final long DOWNLOAD_FILESIZE = 95251708; // Wait until download manager actually start downloading something // Will wait for 1 MB to be downloaded. private static final long EXPECTED_PROGRESS = 1024 * 1024; private static final String FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX = "file"; private static final String FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION = ".bin"; protected static long CONCURRENT_DOWNLOAD_FILESIZE = 1000000; // Values to be obtained from TestRunner private String externalDownloadUriValue = null; private String externalLargeDownloadUriValue = null; /** * {@inheritDoc } */ @Override public void setUp() throws Exception { super.setUp(); DownloadManagerTestRunner mRunner = (DownloadManagerTestRunner)getInstrumentation(); externalDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue); assertNotNull("download url is null", externalDownloadUriValue); externalLargeDownloadUriValue = normalizeUri(mRunner.externalDownloadUriValue); assertNotNull("large download url is null", externalLargeDownloadUriValue); } /** * Normalizes a uri to ensure it ends with a "/" * * @param uri The uri to normalize (or null) * @return The normalized uri, or null if null was passed in */ public String normalizeUri(String uri) { if (uri != null && !uri.endsWith("/")) { uri += "/"; } return uri; } /** * Gets the external URL of the file to download * * @return the Uri of the external file to download */ private Uri getExternalFileUri(String file) { return Uri.parse(externalDownloadUriValue + file); } /** * Gets the path to the file that flags that a download has started. The file contains the * DownloadManager id of the download being trackted between reboot sessions. * * @return The path of the file tracking that a download has started * @throws InterruptedException if interrupted * @throws Exception if timed out while waiting for SD card to mount */ protected String getDownloadStartedFilePath() { String path = Environment.getExternalStorageDirectory().getPath(); return path + File.separatorChar + DOWNLOAD_STARTED_FLAG; } /** * Common setup steps for downloads. * * Note that these are not included in setUp, so that individual tests can control their own * state between reboots, etc. */ protected void doCommonDownloadSetup() throws Exception { setWiFiStateOn(true); setAirplaneModeOn(false); waitForExternalStoreMount(); removeAllCurrentDownloads(); } /** * Initiates a download. * * Queues up a download to the download manager, and saves the DownloadManager's assigned * download ID for this download to a file. * * @throws Exception if unsuccessful */ public void initiateDownload() throws Exception { String filename = DOWNLOAD_FILENAME; mContext.deleteFile(DOWNLOAD_STARTED_FLAG); FileOutputStream fileOutput = mContext.openFileOutput(DOWNLOAD_STARTED_FLAG, 0); DataOutputStream outputFile = null; doCommonDownloadSetup(); try { long dlRequest = -1; // Make sure there are no pending downloads currently going on removeAllCurrentDownloads(); Uri remoteUri = getExternalFileUri(filename); Request request = new Request(remoteUri); dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); assertTrue("request id is -1 from download manager", dlRequest != -1); // Store ID of download for later retrieval outputFile = new DataOutputStream(fileOutput); outputFile.writeLong(dlRequest); } finally { if (outputFile != null) { outputFile.flush(); outputFile.close(); } } } /** * Waits for a previously-initiated download and verifies it has completed successfully. * * @throws Exception if unsuccessful */ public void verifyFileDownloadSucceeded() throws Exception { String filename = DOWNLOAD_FILENAME; long filesize = DOWNLOAD_FILESIZE; long dlRequest = -1; boolean rebootMarkerValid = false; DataInputStream dataInputFile = null; setWiFiStateOn(true); setAirplaneModeOn(false); try { FileInputStream inFile = mContext.openFileInput(DOWNLOAD_STARTED_FLAG); dataInputFile = new DataInputStream(inFile); dlRequest = dataInputFile.readLong(); } catch (Exception e) { // The file was't valid so we just leave the flag false Log.i(LOG_TAG, "Unable to determine initial download id."); throw e; } finally { if (dataInputFile != null) { dataInputFile.close(); } mContext.deleteFile(DOWNLOAD_STARTED_FLAG); } assertTrue("request id is -1 from download manager", dlRequest != -1); Cursor cursor = getCursor(dlRequest); ParcelFileDescriptor pfd = null; try { assertTrue("Unable to query last initiated download!", cursor.moveToFirst()); int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS); int status = cursor.getInt(columnIndex); int currentWaitTime = 0; assertTrue("download not finished", waitForDownload(dlRequest, 15 * 60 * 1000)); Log.i(LOG_TAG, "Verifying download information..."); // Verify specific info about the file (size, name, etc)... pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } catch (Exception e) { Log.i(LOG_TAG, "error: " + e.toString()); throw e; } finally { // Clean up... cursor.close(); mDownloadManager.remove(dlRequest); if (pfd != null) { pfd.close(); } } } /** * Tests downloading a large file over WiFi (~10 Mb). * * @throws Exception if unsuccessful */ public void runLargeDownloadOverWiFi() throws Exception { String filename = DOWNLOAD_FILENAME; long filesize = DOWNLOAD_FILESIZE; long dlRequest = -1; doCommonDownloadSetup(); // Make sure there are no pending downloads currently going on removeAllCurrentDownloads(); Uri remoteUri = getExternalFileUri(filename); Request request = new Request(remoteUri); request.setMimeType("application/vnd.android.package-archive"); dlRequest = mDownloadManager.enqueue(request); // Rather large file, so wait up to 15 mins... assertTrue("download not finished", waitForDownload(dlRequest, 15 * 60 * 1000)); Cursor cursor = getCursor(dlRequest); ParcelFileDescriptor pfd = null; try { Log.i(LOG_TAG, "Verifying download information..."); // Verify specific info about the file (size, name, etc)... pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { if (pfd != null) { pfd.close(); } mDownloadManager.remove(dlRequest); cursor.close(); } } /** * Tests that downloads resume when switching back and forth from having connectivity to * having no connectivity using both WiFi and airplane mode. * * Note: Device has no mobile access when running this test. * * @throws Exception if unsuccessful */ public void runDownloadMultipleSwitching() throws Exception { String filename = DOWNLOAD_FILENAME; long filesize = DOWNLOAD_FILESIZE; doCommonDownloadSetup(); String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath(); File downloadedFile = new File(localDownloadDirectory, filename); long dlRequest = -1; try { downloadedFile.delete(); // Make sure there are no pending downloads currently going on removeAllCurrentDownloads(); Uri remoteUri = getExternalFileUri(filename); Request request = new Request(remoteUri); // Local destination of downloaded file Uri localUri = Uri.fromFile(downloadedFile); Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath()); request.setDestinationUri(localUri); request.setAllowedNetworkTypes(Request.NETWORK_MOBILE | Request.NETWORK_WIFI); dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); // make sure we're starting to download some data... waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable setWiFiStateOn(false); // download disable Log.i(LOG_TAG, "Turning on airplane mode..."); setAirplaneModeOn(true); Thread.sleep(5 * 1000); // wait 5 secs // download disable setWiFiStateOn(true); Thread.sleep(5 * 1000); // wait 5 secs waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download enable Log.i(LOG_TAG, "Turning off airplane mode..."); setAirplaneModeOn(false); Thread.sleep(5 * 1000); // wait 5 seconds waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable Log.i(LOG_TAG, "Turning off WiFi..."); setWiFiStateOn(false); Thread.sleep(5 * 1000); // wait 5 secs // finally, turn WiFi back on and finish up the download Log.i(LOG_TAG, "Turning on WiFi..."); setWiFiStateOn(true); Log.i(LOG_TAG, "Waiting up to 10 minutes for download to complete..."); assertTrue("download not finished", waitForDownload(dlRequest, 10 * 60 * 1000)); ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { Log.i(LOG_TAG, "Cleaning up files..."); if (dlRequest != -1) { mDownloadManager.remove(dlRequest); } downloadedFile.delete(); } } /** * Tests that downloads resume when switching on/off WiFi at various intervals. * * Note: Device has no mobile access when running this test. * * @throws Exception if unsuccessful */ public void runDownloadMultipleWiFiEnableDisable() throws Exception { String filename = DOWNLOAD_FILENAME; long filesize = DOWNLOAD_FILESIZE; doCommonDownloadSetup(); String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath(); File downloadedFile = new File(localDownloadDirectory, filename); long dlRequest = -1; try { downloadedFile.delete(); // Make sure there are no pending downloads currently going on removeAllCurrentDownloads(); Uri remoteUri = getExternalFileUri(filename); Request request = new Request(remoteUri); // Local destination of downloaded file Uri localUri = Uri.fromFile(downloadedFile); Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath()); request.setDestinationUri(localUri); request.setAllowedNetworkTypes(Request.NETWORK_WIFI); dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); // are we making any progress? waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable Log.i(LOG_TAG, "Turning off WiFi..."); setWiFiStateOn(false); Thread.sleep(40 * 1000); // wait 40 seconds // enable download... Log.i(LOG_TAG, "Turning on WiFi again..."); setWiFiStateOn(true); waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable Log.i(LOG_TAG, "Turning off WiFi..."); setWiFiStateOn(false); Thread.sleep(20 * 1000); // wait 20 seconds // enable download... Log.i(LOG_TAG, "Turning on WiFi again..."); setWiFiStateOn(true); Log.i(LOG_TAG, "Waiting up to 10 minutes for download to complete..."); assertTrue("download not finished", waitForDownload(dlRequest, 10 * 60 * 1000)); ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { Log.i(LOG_TAG, "Cleaning up files..."); if (dlRequest != -1) { mDownloadManager.remove(dlRequest); } downloadedFile.delete(); } } /** * Tests that downloads resume when switching on/off Airplane mode numerous times at * various intervals. * * Note: Device has no mobile access when running this test. * * @throws Exception if unsuccessful */ public void runDownloadMultipleAirplaneModeEnableDisable() throws Exception { String filename = DOWNLOAD_FILENAME; long filesize = DOWNLOAD_FILESIZE; // make sure WiFi is enabled, and airplane mode is not on doCommonDownloadSetup(); String localDownloadDirectory = Environment.getExternalStorageDirectory().getPath(); File downloadedFile = new File(localDownloadDirectory, filename); long dlRequest = -1; try { downloadedFile.delete(); // Make sure there are no pending downloads currently going on removeAllCurrentDownloads(); Uri remoteUri = getExternalFileUri(filename); Request request = new Request(remoteUri); // Local destination of downloaded file Uri localUri = Uri.fromFile(downloadedFile); Log.i(LOG_TAG, "setting localUri to: " + localUri.getPath()); request.setDestinationUri(localUri); request.setAllowedNetworkTypes(Request.NETWORK_WIFI); dlRequest = mDownloadManager.enqueue(request); waitForDownloadToStart(dlRequest); // are we making any progress? waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // download disable Log.i(LOG_TAG, "Turning on Airplane mode..."); setAirplaneModeOn(true); Thread.sleep(60 * 1000); // wait 1 minute // download enable Log.i(LOG_TAG, "Turning off Airplane mode..."); setAirplaneModeOn(false); // make sure we're starting to download some data... waitToReceiveData(dlRequest, EXPECTED_PROGRESS); // reenable the connection to start up the download again Log.i(LOG_TAG, "Turning on Airplane mode again..."); setAirplaneModeOn(true); Thread.sleep(20 * 1000); // wait 20 seconds // Finish up the download... Log.i(LOG_TAG, "Turning off Airplane mode again..."); setAirplaneModeOn(false); Log.i(LOG_TAG, "Waiting up to 10 minutes for donwload to complete..."); assertTrue("download not finished", waitForDownload(dlRequest, 10 * 60 * 1000)); // wait up to 10 mins ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(dlRequest); verifyFileSize(pfd, filesize); } finally { Log.i(LOG_TAG, "Cleaning up files..."); if (dlRequest != -1) { mDownloadManager.remove(dlRequest); } downloadedFile.delete(); } } /** * Tests 15 concurrent downloads of 1,000,000-byte files. * * @throws Exception if test failed */ public void runDownloadMultipleSimultaneously() throws Exception { final int TOTAL_DOWNLOADS = 15; HashSet downloadIds = new HashSet(TOTAL_DOWNLOADS); // Make sure there are no pending downloads currently going on removeAllCurrentDownloads(); try { for (int i = 0; i < TOTAL_DOWNLOADS; ++i) { long dlRequest = -1; String filename = FILE_CONCURRENT_DOWNLOAD_FILE_PREFIX + i + FILE_CONCURRENT_DOWNLOAD_FILE_EXTENSION; Uri remoteUri = getExternalFileUri(filename); Request request = new Request(remoteUri); request.setTitle(filename); dlRequest = mDownloadManager.enqueue(request); assertTrue("request id is -1 from download manager", dlRequest != -1); downloadIds.add(dlRequest); } assertTrue("download not finished", waitForMultipleDownloads(downloadIds, 15 * 60 * 2000)); // wait 15 mins max } finally { removeAllCurrentDownloads(); } } }