1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.providers.downloads; 18 19import static android.app.DownloadManager.STATUS_FAILED; 20import static android.app.DownloadManager.STATUS_SUCCESSFUL; 21import static android.text.format.DateUtils.MINUTE_IN_MILLIS; 22import static android.text.format.DateUtils.SECOND_IN_MILLIS; 23 24import android.app.DownloadManager; 25import android.database.Cursor; 26import android.net.Uri; 27import android.os.ParcelFileDescriptor; 28import android.os.SystemClock; 29import android.util.Log; 30 31import libcore.io.IoUtils; 32import libcore.io.Streams; 33 34import java.io.InputStream; 35import java.net.MalformedURLException; 36import java.net.UnknownHostException; 37import java.util.concurrent.TimeoutException; 38 39/** 40 * Code common to tests that use the download manager public API. 41 */ 42public abstract class AbstractPublicApiTest extends AbstractDownloadProviderFunctionalTest { 43 44 class Download { 45 final long mId; 46 47 private Download(long downloadId) { 48 this.mId = downloadId; 49 } 50 51 public int getStatus() { 52 return (int) getLongField(DownloadManager.COLUMN_STATUS); 53 } 54 55 public int getReason() { 56 return (int) getLongField(DownloadManager.COLUMN_REASON); 57 } 58 59 public int getStatusIfExists() { 60 Cursor cursor = mManager.query(new DownloadManager.Query().setFilterById(mId)); 61 try { 62 if (cursor.getCount() > 0) { 63 cursor.moveToFirst(); 64 return (int) cursor.getLong(cursor.getColumnIndexOrThrow( 65 DownloadManager.COLUMN_STATUS)); 66 } else { 67 // the row doesn't exist 68 return -1; 69 } 70 } finally { 71 cursor.close(); 72 } 73 } 74 75 String getStringField(String field) { 76 Cursor cursor = mManager.query(new DownloadManager.Query().setFilterById(mId)); 77 try { 78 assertEquals(1, cursor.getCount()); 79 cursor.moveToFirst(); 80 return cursor.getString(cursor.getColumnIndexOrThrow(field)); 81 } finally { 82 cursor.close(); 83 } 84 } 85 86 long getLongField(String field) { 87 Cursor cursor = mManager.query(new DownloadManager.Query().setFilterById(mId)); 88 try { 89 assertEquals(1, cursor.getCount()); 90 cursor.moveToFirst(); 91 return cursor.getLong(cursor.getColumnIndexOrThrow(field)); 92 } finally { 93 cursor.close(); 94 } 95 } 96 97 byte[] getRawContents() throws Exception { 98 ParcelFileDescriptor downloadedFile = mManager.openDownloadedFile(mId); 99 assertTrue("Invalid file descriptor: " + downloadedFile, 100 downloadedFile.getFileDescriptor().valid()); 101 final InputStream is = new ParcelFileDescriptor.AutoCloseInputStream( 102 downloadedFile); 103 try { 104 return Streams.readFully(is); 105 } finally { 106 IoUtils.closeQuietly(is); 107 } 108 } 109 110 String getContents() throws Exception { 111 return new String(getRawContents()); 112 } 113 114 void runUntilStatus(int status) throws TimeoutException { 115 final long startMillis = mSystemFacade.currentTimeMillis(); 116 startService(null); 117 waitForStatus(status, startMillis); 118 } 119 120 void runUntilStatus(int status, long timeout) throws TimeoutException { 121 final long startMillis = mSystemFacade.currentTimeMillis(); 122 startService(null); 123 waitForStatus(status, startMillis, timeout); 124 } 125 126 void waitForStatus(int expected, long afterMillis) throws TimeoutException { 127 waitForStatus(expected, afterMillis, 15 * SECOND_IN_MILLIS); 128 } 129 130 void waitForStatus(int expected, long afterMillis, long timeout) throws TimeoutException { 131 int actual = -1; 132 133 final long elapsedTimeout = SystemClock.elapsedRealtime() + timeout; 134 while (SystemClock.elapsedRealtime() < elapsedTimeout) { 135 if (getLongField(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP) >= afterMillis) { 136 actual = getStatus(); 137 if (actual == STATUS_SUCCESSFUL || actual == STATUS_FAILED) { 138 assertEquals(expected, actual); 139 return; 140 } else if (actual == expected) { 141 return; 142 } 143 144 if (timeout > MINUTE_IN_MILLIS) { 145 final int percent = (int) (100 146 * getLongField(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR) 147 / getLongField(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); 148 Log.d(LOG_TAG, percent + "% complete"); 149 } 150 } 151 152 if (timeout > MINUTE_IN_MILLIS) { 153 SystemClock.sleep(SECOND_IN_MILLIS * 3); 154 } else { 155 SystemClock.sleep(100); 156 } 157 } 158 159 throw new TimeoutException("Expected status " + expected + "; only reached " + actual); 160 } 161 162 // max time to wait before giving up on the current download operation. 163 private static final int MAX_TIME_TO_WAIT_FOR_OPERATION = 5; 164 // while waiting for the above time period, sleep this long to yield to the 165 // download thread 166 private static final int TIME_TO_SLEEP = 1000; 167 168 // waits until progress_so_far is >= (progress)% 169 boolean runUntilProgress(int progress) throws InterruptedException { 170 startService(null); 171 172 int sleepCounter = MAX_TIME_TO_WAIT_FOR_OPERATION * 1000 / TIME_TO_SLEEP; 173 int numBytesReceivedSoFar = 0; 174 int totalBytes = 0; 175 for (int i = 0; i < sleepCounter; i++) { 176 Cursor cursor = mManager.query(new DownloadManager.Query().setFilterById(mId)); 177 try { 178 assertEquals(1, cursor.getCount()); 179 cursor.moveToFirst(); 180 numBytesReceivedSoFar = cursor.getInt( 181 cursor.getColumnIndexOrThrow( 182 DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); 183 totalBytes = cursor.getInt( 184 cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); 185 } finally { 186 cursor.close(); 187 } 188 Log.i(LOG_TAG, "in runUntilProgress, numBytesReceivedSoFar: " + 189 numBytesReceivedSoFar + ", totalBytes: " + totalBytes); 190 if (totalBytes == 0) { 191 fail("total_bytes should not be zero"); 192 return false; 193 } else { 194 if (numBytesReceivedSoFar * 100 / totalBytes >= progress) { 195 // progress_so_far is >= progress%. we are done 196 return true; 197 } 198 } 199 // download not done yet. sleep a while and try again 200 Thread.sleep(TIME_TO_SLEEP); 201 } 202 Log.i(LOG_TAG, "FAILED in runUntilProgress, numBytesReceivedSoFar: " + 203 numBytesReceivedSoFar + ", totalBytes: " + totalBytes); 204 return false; // failed 205 } 206 } 207 208 protected static final String PACKAGE_NAME = "my.package.name"; 209 protected static final String REQUEST_PATH = "/path"; 210 211 protected DownloadManager mManager; 212 213 public AbstractPublicApiTest(FakeSystemFacade systemFacade) { 214 super(systemFacade); 215 } 216 217 @Override 218 protected void setUp() throws Exception { 219 super.setUp(); 220 mManager = new DownloadManager(mResolver, PACKAGE_NAME); 221 } 222 223 protected DownloadManager.Request getRequest() 224 throws MalformedURLException, UnknownHostException { 225 return getRequest(getServerUri(REQUEST_PATH)); 226 } 227 228 protected DownloadManager.Request getRequest(String path) { 229 return new DownloadManager.Request(Uri.parse(path)); 230 } 231 232 protected Download enqueueRequest(DownloadManager.Request request) { 233 return new Download(mManager.enqueue(request)); 234 } 235} 236