182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori/*
282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * Copyright (C) 2010 The Android Open Source Project
382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori *
482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * Licensed under the Apache License, Version 2.0 (the "License");
582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * you may not use this file except in compliance with the License.
682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * You may obtain a copy of the License at
782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori *
882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori *      http://www.apache.org/licenses/LICENSE-2.0
982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori *
1082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * Unless required by applicable law or agreed to in writing, software
1182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * distributed under the License is distributed on an "AS IS" BASIS,
1282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * See the License for the specific language governing permissions and
1482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * limitations under the License.
1582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori */
1682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
1782e891b3259350a92b55969a6380ca1240ee0829Vasu Noripackage com.android.frameworks.downloadmanagertests;
1882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
1982e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.app.DownloadManager;
2082e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.app.DownloadManager.Query;
2182e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.content.BroadcastReceiver;
2282e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.content.Context;
2382e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.content.Intent;
2482e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.content.IntentFilter;
2582e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.database.Cursor;
2682e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.net.ConnectivityManager;
2782e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.net.NetworkInfo;
2882e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.net.wifi.WifiManager;
2982e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.os.Environment;
30a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavineimport android.os.Handler;
31a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavineimport android.os.Looper;
3282e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.os.ParcelFileDescriptor;
3382e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.os.SystemClock;
3482e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.provider.Settings;
3582e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.test.InstrumentationTestCase;
3682e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport android.util.Log;
3782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
3882e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport java.util.HashSet;
3982e891b3259350a92b55969a6380ca1240ee0829Vasu Noriimport java.util.Set;
40b14ad8cc8cb0ed774072b077694b21fd0a6f33beJeff Sharkeyimport java.util.concurrent.TimeoutException;
4182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
4282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori/**
4382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori * Base class for Instrumented tests for the Download Manager.
4482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori */
4582e891b3259350a92b55969a6380ca1240ee0829Vasu Noripublic class DownloadManagerBaseTest extends InstrumentationTestCase {
4682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
4782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected DownloadManager mDownloadManager = null;
4882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected String mFileType = "text/plain";
4982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected Context mContext = null;
5082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int DEFAULT_FILE_SIZE = 10 * 1024;  // 10kb
5182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int FILE_BLOCK_READ_SIZE = 1024 * 1024;
5282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
5382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final String LOG_TAG = "android.net.DownloadManagerBaseTest";
5482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int HTTP_OK = 200;
5582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int HTTP_REDIRECT = 307;
5682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int HTTP_PARTIAL_CONTENT = 206;
5782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int HTTP_NOT_FOUND = 404;
5882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int HTTP_SERVICE_UNAVAILABLE = 503;
5982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
6082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int DEFAULT_MAX_WAIT_TIME = 2 * 60 * 1000;  // 2 minutes
6182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int DEFAULT_WAIT_POLL_TIME = 5 * 1000;  // 5 seconds
6282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
6382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int WAIT_FOR_DOWNLOAD_POLL_TIME = 1 * 1000;  // 1 second
6482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int MAX_WAIT_FOR_DOWNLOAD_TIME = 5 * 60 * 1000; // 5 minutes
6582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected static final int MAX_WAIT_FOR_LARGE_DOWNLOAD_TIME = 15 * 60 * 1000; // 15 minutes
6682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
67a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    private DownloadFinishedListener mListener;
68a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    private Thread mListenerThread;
6982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
7082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
7182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    public static class WiFiChangedReceiver extends BroadcastReceiver {
7282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        private Context mContext = null;
7382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
7482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        /**
7582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         * Constructor
7682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         *
7782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         * Sets the current state of WiFi.
7882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         *
7982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         * @param context The current app {@link Context}.
8082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         */
8182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        public WiFiChangedReceiver(Context context) {
8282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            mContext = context;
8382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
8482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
8582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        /**
8682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         * {@inheritDoc}
8782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         */
8882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        @Override
8982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        public void onReceive(Context context, Intent intent) {
9082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            if (intent.getAction().equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION)) {
9182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                Log.i(LOG_TAG, "ConnectivityManager state change: " + intent.getAction());
9282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                synchronized (this) {
9382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    this.notify();
9482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                }
9582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            }
9682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
9782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
9882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        /**
9982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         * Gets the current state of WiFi.
10082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         *
10182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         * @return Returns true if WiFi is on, false otherwise.
10282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori         */
10382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        public boolean getWiFiIsOn() {
10482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            ConnectivityManager connManager = (ConnectivityManager)mContext.getSystemService(
10582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    Context.CONNECTIVITY_SERVICE);
10682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            NetworkInfo info = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
10782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            Log.i(LOG_TAG, "WiFi Connection state is currently: " + info.isConnected());
10882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            return info.isConnected();
10982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
11082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
11182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
11282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
113a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * Broadcast receiver to listen for broadcast from DownloadManager indicating that downloads
114a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * are finished.
115a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     */
116a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    private class DownloadFinishedListener extends BroadcastReceiver implements Runnable {
117a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        private Handler mHandler = null;
118a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        private Looper mLooper;
119a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        private Set<Long> mFinishedDownloads = new HashSet<Long>();
120a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine
121a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        /**
122a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * Event loop for the thread that listens to broadcasts.
123a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         */
124a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        @Override
125a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        public void run() {
126a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            Looper.prepare();
127a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            synchronized (this) {
128a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                mLooper = Looper.myLooper();
129a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                mHandler = new Handler();
130a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                notifyAll();
131a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            }
132a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            Looper.loop();
133a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        }
134a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine
135a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        /**
136a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * Handles the incoming notifications from DownloadManager.
137a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         */
138a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        @Override
139a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        public void onReceive(Context context, Intent intent) {
140a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(intent.getAction())) {
141a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                long id = intent.getExtras().getLong(DownloadManager.EXTRA_DOWNLOAD_ID);
142a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                Log.i(LOG_TAG, "Received Notification for download: " + id);
143a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                synchronized (this) {
144a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    if(!mFinishedDownloads.contains(id)) {
145a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                        mFinishedDownloads.add(id);
146a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                        notifyAll();
147a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    } else {
148a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                        Log.i(LOG_TAG,
149a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                              String.format("Notification for %d was already received", id));
150a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    }
151a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                }
152a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            }
153a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        }
154a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine
155a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        /**
156a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * Returns the handler for this thread. Need this to make sure that the events are handled
157a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * in it is own thread and don't interfere with the instrumentation thread.
158a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @return Handler for the receiver thread.
159a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @throws InterruptedException
160a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         */
161a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        private Handler getHandler() throws InterruptedException {
162a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            synchronized (this) {
163a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                if (mHandler != null) return mHandler;
164a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                while (mHandler == null) {
165a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    wait();
166a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                }
167a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                return mHandler;
168a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            }
169a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        }
170a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine
171a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        /**
172a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * Stops the thread that receives notification from DownloadManager.
173a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         */
174a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        public void cancel() {
175a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            synchronized(this) {
176a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                if (mLooper != null) {
177a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    mLooper.quit();
178a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                }
179a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            }
180a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        }
181a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine
182a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        /**
183a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * Waits for a given download to finish, or until the timeout expires.
184a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @param id id of the download to wait for.
185a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @param timeout maximum time to wait, in milliseconds
186a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @return true if the download finished, false otherwise.
187a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @throws InterruptedException
188a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         */
189a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        public boolean waitForDownloadToFinish(long id, long timeout) throws InterruptedException {
190a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            long startTime = SystemClock.uptimeMillis();
191a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            synchronized (this) {
192a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                while (!mFinishedDownloads.contains(id)) {
193a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    if (SystemClock.uptimeMillis() - startTime > timeout) {
194a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                        Log.i(LOG_TAG, String.format("Timeout while waiting for %d to finish", id));
195a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                        return false;
196a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    } else {
197a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                        wait(timeout);
198a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    }
199a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                }
200a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                return true;
201a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            }
202a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        }
203a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine
204a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        /**
205a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * Waits for multiple downloads to finish, or until timeout expires.
206a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @param ids ids of the downloads to wait for.
207a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @param timeout maximum time to wait, in milliseconds
208a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @return true of all the downloads finished, false otherwise.
209a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         * @throws InterruptedException
210a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine         */
211a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        public boolean waitForMultipleDownloadsToFinish(Set<Long> ids, long timeout)
212a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                throws InterruptedException {
213a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            long startTime = SystemClock.uptimeMillis();
214a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            synchronized (this) {
215a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                while (!mFinishedDownloads.containsAll(ids)) {
216a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    if (SystemClock.uptimeMillis() - startTime > timeout) {
217a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                        Log.i(LOG_TAG, "Timeout waiting for multiple downloads to finish");
218a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                        return false;
219a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    } else {
220a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                        wait(timeout);
221a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    }
222a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                }
223a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                return true;
224a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            }
225a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        }
226a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    }
227a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine
228a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    /**
22982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * {@inheritDoc}
23082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
23182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    @Override
23282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    public void setUp() throws Exception {
233a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        super.setUp();
23482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        mContext = getInstrumentation().getContext();
23582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        mDownloadManager = (DownloadManager)mContext.getSystemService(Context.DOWNLOAD_SERVICE);
236a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        mListener = registerDownloadsListener();
237a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    }
238a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine
239a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    @Override
240a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    public void tearDown() throws Exception {
241a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        mContext.unregisterReceiver(mListener);
242a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        mListener.cancel();
243a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        mListenerThread.join();
244a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        super.tearDown();
24582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
24682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
24782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
24882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Helper to verify the size of a file.
24982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
25082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param pfd The input file to compare the size of
25182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param size The expected size of the file
25282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
25382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected void verifyFileSize(ParcelFileDescriptor pfd, long size) {
25482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        assertEquals(pfd.getStatSize(), size);
25582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
25682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
25782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
25882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Helper to create and register a new MultipleDownloadCompletedReciever
25982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
26082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * This is used to track many simultaneous downloads by keeping count of all the downloads
26182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * that have completed.
26282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
26382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @return A new receiver that records and can be queried on how many downloads have completed.
264a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * @throws InterruptedException
26582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
266a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    protected DownloadFinishedListener registerDownloadsListener() throws InterruptedException {
267a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        DownloadFinishedListener listener = new DownloadFinishedListener();
268a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        mListenerThread = new Thread(listener);
269a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        mListenerThread.start();
270a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        mContext.registerReceiver(listener, new IntentFilter(
271a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                DownloadManager.ACTION_DOWNLOAD_COMPLETE), null, listener.getHandler());
272a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        return listener;
27382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
27482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
27582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
27682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Enables or disables WiFi.
27782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
27882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Note: Needs the following permissions:
27982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *  android.permission.ACCESS_WIFI_STATE
28082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *  android.permission.CHANGE_WIFI_STATE
28182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param enable true if it should be enabled, false if it should be disabled
28282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
28382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected void setWiFiStateOn(boolean enable) throws Exception {
28482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        Log.i(LOG_TAG, "Setting WiFi State to: " + enable);
28582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
28682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
28782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        manager.setWifiEnabled(enable);
28882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
28982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        String timeoutMessage = "Timed out waiting for Wifi to be "
29082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            + (enable ? "enabled!" : "disabled!");
29182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
29282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        WiFiChangedReceiver receiver = new WiFiChangedReceiver(mContext);
29382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        mContext.registerReceiver(receiver, new IntentFilter(
29482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                ConnectivityManager.CONNECTIVITY_ACTION));
29582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
29682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        synchronized (receiver) {
29782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            long timeoutTime = SystemClock.elapsedRealtime() + DEFAULT_MAX_WAIT_TIME;
29882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            boolean timedOut = false;
29982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
30082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            while (receiver.getWiFiIsOn() != enable && !timedOut) {
30182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                try {
30282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    receiver.wait(DEFAULT_WAIT_POLL_TIME);
30382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
30482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    if (SystemClock.elapsedRealtime() > timeoutTime) {
30582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                        timedOut = true;
30682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    }
30782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                }
30882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                catch (InterruptedException e) {
30982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    // ignore InterruptedExceptions
31082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                }
31182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            }
31282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            if (timedOut) {
31382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                fail(timeoutMessage);
31482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            }
31582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
31682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        assertEquals(enable, receiver.getWiFiIsOn());
31782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
31882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
31982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
32082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Helper to enables or disables airplane mode. If successful, it also broadcasts an intent
32182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * indicating that the mode has changed.
32282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
32382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Note: Needs the following permission:
32482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *  android.permission.WRITE_SETTINGS
32582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param enable true if airplane mode should be ON, false if it should be OFF
32682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
32782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected void setAirplaneModeOn(boolean enable) throws Exception {
32882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        int state = enable ? 1 : 0;
32982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
33082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        // Change the system setting
33135fae68cc3eb21c15069c58d275a46537cc04f4aTsu Chiang Chuang        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
33282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                state);
33382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
33482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        String timeoutMessage = "Timed out waiting for airplane mode to be " +
33582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                (enable ? "enabled!" : "disabled!");
33682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
33782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        // wait for airplane mode to change state
33882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        int currentWaitTime = 0;
33982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        while (Settings.System.getInt(mContext.getContentResolver(),
34035fae68cc3eb21c15069c58d275a46537cc04f4aTsu Chiang Chuang                Settings.Global.AIRPLANE_MODE_ON, -1) != state) {
34182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            timeoutWait(currentWaitTime, DEFAULT_WAIT_POLL_TIME, DEFAULT_MAX_WAIT_TIME,
34282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    timeoutMessage);
34382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
34482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
34582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        // Post the intent
34682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
34782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        intent.putExtra("state", true);
34882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        mContext.sendBroadcast(intent);
34982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
35082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
35182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
352a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * Helper to wait for a particular download to finish, or else a timeout to occur.
35382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
35482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param id The download id to query on (wait for)
35582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param poll The amount of time to wait
35682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param timeoutMillis The max time (in ms) to wait for the download(s) to complete
35782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
358a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    protected boolean waitForDownload(long id, long timeoutMillis)
359a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            throws InterruptedException {
360a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        return mListener.waitForDownloadToFinish(id, timeoutMillis);
36182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
36282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
363a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    protected boolean waitForMultipleDownloads(Set<Long> ids, long timeout)
364a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            throws InterruptedException {
365a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        return mListener.waitForMultipleDownloadsToFinish(ids, timeout);
36682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
36782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
36882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
369a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * Checks with the download manager if the give download is finished.
370a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * @param id id of the download to check
371a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * @return true if download is finished, false otherwise.
37282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
373a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    private boolean hasDownloadFinished(long id) {
374a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        Query q = new Query();
375a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        q.setFilterById(id);
376a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        q.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
377a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        Cursor cursor = mDownloadManager.query(q);
378a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        boolean finished = cursor.getCount() == 1;
379a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        cursor.close();
380a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        return finished;
38182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
38282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
38382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
38482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Helper function to synchronously wait, or timeout if the maximum threshold has been exceeded.
38582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
38682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param currentTotalWaitTime The total time waited so far
38782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param poll The amount of time to wait
38882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param maxTimeoutMillis The total wait time threshold; if we've waited more than this long,
38982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *          we timeout and fail
39082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param timedOutMessage The message to display in the failure message if we timeout
39182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @return The new total amount of time we've waited so far
39282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @throws TimeoutException if timed out waiting for SD card to mount
39382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
39482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    private int timeoutWait(int currentTotalWaitTime, long poll, long maxTimeoutMillis,
39582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            String timedOutMessage) throws TimeoutException {
39682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        long now = SystemClock.elapsedRealtime();
39782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        long end = now + poll;
39882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
39982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        // if we get InterruptedException's, ignore them and just keep sleeping
40082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        while (now < end) {
40182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            try {
40282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                Thread.sleep(end - now);
40382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            } catch (InterruptedException e) {
40482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                // ignore interrupted exceptions
40582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            }
40682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            now = SystemClock.elapsedRealtime();
40782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
40882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
40982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        currentTotalWaitTime += poll;
41082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        if (currentTotalWaitTime > maxTimeoutMillis) {
41182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            throw new TimeoutException(timedOutMessage);
41282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
41382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        return currentTotalWaitTime;
41482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
41582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
41682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
41782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Synchronously waits for external store to be mounted (eg: SD Card).
41882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
41982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @throws InterruptedException if interrupted
42082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @throws Exception if timed out waiting for SD card to mount
42182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
42282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected void waitForExternalStoreMount() throws Exception {
42382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        String extStorageState = Environment.getExternalStorageState();
42482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        int currentWaitTime = 0;
42582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        while (!extStorageState.equals(Environment.MEDIA_MOUNTED)) {
42682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            Log.i(LOG_TAG, "Waiting for SD card...");
42782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            currentWaitTime = timeoutWait(currentWaitTime, DEFAULT_WAIT_POLL_TIME,
42882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    DEFAULT_MAX_WAIT_TIME, "Timed out waiting for SD Card to be ready!");
42982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            extStorageState = Environment.getExternalStorageState();
43082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
43182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
43282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
43382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
43482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Synchronously waits for a download to start.
43582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
43682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param dlRequest the download request id used by Download Manager to track the download.
43782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @throws Exception if timed out while waiting for SD card to mount
43882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
43982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected void waitForDownloadToStart(long dlRequest) throws Exception {
44082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        Cursor cursor = getCursor(dlRequest);
44182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        try {
44282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            int columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
44382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            int value = cursor.getInt(columnIndex);
44482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            int currentWaitTime = 0;
44582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
44682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            while (value != DownloadManager.STATUS_RUNNING &&
44782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    (value != DownloadManager.STATUS_FAILED) &&
44882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    (value != DownloadManager.STATUS_SUCCESSFUL)) {
44982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                Log.i(LOG_TAG, "Waiting for download to start...");
45082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME,
45182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                        MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for download to start!");
45282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                cursor.requery();
45382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                assertTrue(cursor.moveToFirst());
45482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                columnIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS);
45582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                value = cursor.getInt(columnIndex);
45682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            }
45782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            assertFalse("Download failed immediately after start",
45882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    value == DownloadManager.STATUS_FAILED);
45982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        } finally {
46082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            cursor.close();
46182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
46282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
46382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
46482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
465a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * Synchronously waits for the download manager to start incrementing the number of
466a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * bytes downloaded so far.
46782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
468a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * @param id DownloadManager download id that needs to be checked.
469962e12883b6a07ff5b33bd9d269869e4da50b799Maxim Siniavine     * @param bytesToReceive how many bytes do we need to wait to receive.
470a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine     * @throws Exception if timed out while waiting for the file to grow in size.
47182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
472962e12883b6a07ff5b33bd9d269869e4da50b799Maxim Siniavine    protected void waitToReceiveData(long id, long bytesToReceive) throws Exception {
47382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        int currentWaitTime = 0;
474962e12883b6a07ff5b33bd9d269869e4da50b799Maxim Siniavine        long expectedSize = getBytesDownloaded(id) + bytesToReceive;
475a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        long currentSize = 0;
476962e12883b6a07ff5b33bd9d269869e4da50b799Maxim Siniavine        while ((currentSize = getBytesDownloaded(id)) <= expectedSize) {
477962e12883b6a07ff5b33bd9d269869e4da50b799Maxim Siniavine            Log.i(LOG_TAG, String.format("expect: %d, cur: %d. Waiting for file to be written to...",
478962e12883b6a07ff5b33bd9d269869e4da50b799Maxim Siniavine                    expectedSize, currentSize));
47982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            currentWaitTime = timeoutWait(currentWaitTime, WAIT_FOR_DOWNLOAD_POLL_TIME,
480a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                    MAX_WAIT_FOR_DOWNLOAD_TIME, "Timed out waiting for file to be written to.");
48182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
48282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
48382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
484a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine    private long getBytesDownloaded(long id) {
485a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        DownloadManager.Query q = new DownloadManager.Query();
486a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        q.setFilterById(id);
487a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        Cursor response = mDownloadManager.query(q);
488a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        if (response.getCount() < 1) {
489a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            Log.i(LOG_TAG, String.format("Query to download manager returned nothing for id %d",id));
490a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            response.close();
491a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            return -1;
49282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
493a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        while(response.moveToNext()) {
494a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            int index = response.getColumnIndex(DownloadManager.COLUMN_ID);
495a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            if (id == response.getLong(index)) {
496a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine                break;
497a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            }
49882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
499a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        int index = response.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
500a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        if (index < 0) {
501a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            Log.i(LOG_TAG, String.format("No downloaded bytes for id %d", id));
502a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            response.close();
503a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine            return -1;
504a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        }
505a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        long size = response.getLong(index);
506a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        response.close();
507a305d7229fb99a536293b5d52cdb9ce3c820d6c8Maxim Siniavine        return size;
50882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
50982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
51082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
51182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Helper to remove all downloads that are registered with the DL Manager.
51282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
51382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Note: This gives us a clean slate b/c it includes downloads that are pending, running,
51482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * paused, or have completed.
51582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
51682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected void removeAllCurrentDownloads() {
51782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        Log.i(LOG_TAG, "Removing all current registered downloads...");
51882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        Cursor cursor = mDownloadManager.query(new Query());
51982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        try {
52082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            if (cursor.moveToFirst()) {
52182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                do {
52282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    int index = cursor.getColumnIndex(DownloadManager.COLUMN_ID);
52382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    long downloadId = cursor.getLong(index);
52482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
52582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    mDownloadManager.remove(downloadId);
52682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                } while (cursor.moveToNext());
52782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            }
52882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        } finally {
52982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            cursor.close();
53082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
53182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
53282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
53382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    /**
53482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * Performs a query based on ID and returns a Cursor for the query.
53582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     *
53682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @param id The id of the download in DL Manager; pass -1 to query all downloads
53782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     * @return A cursor for the query results
53882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori     */
53982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    protected Cursor getCursor(long id) throws Exception {
54082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        Query query = new Query();
54182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        if (id != -1) {
54282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            query.setFilterById(id);
54382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
54482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
54582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        Cursor cursor = mDownloadManager.query(query);
54682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        int currentWaitTime = 0;
54782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori
54882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        try {
54982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            while (!cursor.moveToFirst()) {
55082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                Thread.sleep(DEFAULT_WAIT_POLL_TIME);
55182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                currentWaitTime += DEFAULT_WAIT_POLL_TIME;
55282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                if (currentWaitTime > DEFAULT_MAX_WAIT_TIME) {
55382e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                    fail("timed out waiting for a non-null query result");
55482e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                }
55582e891b3259350a92b55969a6380ca1240ee0829Vasu Nori                cursor.requery();
55682e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            }
55782e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        } catch (Exception e) {
55882e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            cursor.close();
55982e891b3259350a92b55969a6380ca1240ee0829Vasu Nori            throw e;
56082e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        }
56182e891b3259350a92b55969a6380ca1240ee0829Vasu Nori        return cursor;
56282e891b3259350a92b55969a6380ca1240ee0829Vasu Nori    }
563fbfe6d971d63860c02a71d69c3c7c29a2e958734Neal Nguyen}
564