DownloadManager - xjwangliang/android_source_note GitHub Wiki

Get mime from url.

MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
String mimeString = mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url));
public static boolean isDrmMimeType(Context context, String mimetype) {
        boolean result = false;
        if (context != null) {
            try {
                DrmManagerClient drmClient = new DrmManagerClient(context);
                if (drmClient != null && mimetype != null && mimetype.length() > 0) {
                    result = drmClient.canHandle("", mimetype);
                }
            } catch (IllegalArgumentException e) {
                Log.w(Constants.TAG,
                        "DrmManagerClient instance could not be created, context is Illegal.");
            } catch (IllegalStateException e) {
                Log.w(Constants.TAG, "DrmManagerClient didn't initialize properly.");
            }
        }
        return result;
    }

StorageManager检查存储空间

void verifySpaceBeforeWritingToFile(int destination, String path, long length)
            throws StopRequestException {
        // do this check only once for every 1MB of downloaded data
        if (incrementBytesDownloadedSinceLastCheckOnSpace(length) <
                FREQUENCY_OF_CHECKS_ON_SPACE_AVAILABILITY) {
            return;
        }
        verifySpace(destination, path, length);
    }

DownloadHandler防止重复下载

public synchronized void enqueueDownload(DownloadInfo info) {
    	// 等待队列中没有目标,尝试启动(等待队列和下载队列中有下载记录,do nothing)
        if (!mDownloadsQueue.containsKey(info.mId)) {
            if (Constants.LOGV) {
                Log.i(TAG, "enqueued download. id: " + info.mId + ", uri: " + info.mUri);
            }
            mDownloadsQueue.put(info.mId, info);
            startDownloadThreadLocked();
        }
    }

Test

    /**
     * Helper to create a large file of random data on the SD card.
     *
     * @param filename (optional) The name of the file to create on the SD card; pass in null to
     *          use a default temp filename.
     * @param type The type of file to create
     * @param subdirectory If not null, the subdirectory under the SD card where the file should go
     * @return The File that was created
     * @throws IOException if there was an error while creating the file.
     */
    protected File createFileOnSD(String filename, long fileSize, DataType type,
            String subdirectory) throws IOException {

        // Build up the file path and name
        String sdPath = Environment.getExternalStorageDirectory().getPath();
        StringBuilder fullPath = new StringBuilder(sdPath);
        if (subdirectory != null) {
            fullPath.append(File.separatorChar).append(subdirectory);
        }

        File file = null;
        if (filename == null) {
            file = File.createTempFile("DMTEST_", null, new File(fullPath.toString()));
        }
        else {
            fullPath.append(File.separatorChar).append(filename);
            file = new File(fullPath.toString());
            file.createNewFile();
        }

        // Fill the file with random data
        DataOutputStream output = new DataOutputStream(new FileOutputStream(file));
        final int CHUNK_SIZE = 1000000;  // copy random data in 1000000-char chunks
        long remaining = fileSize;
        int nextChunkSize = CHUNK_SIZE;
        byte[] randomData = null;
        Random rng = new LoggingRng();
        byte[] chunkSizeData = generateData(nextChunkSize, type, rng);

        try {
            while (remaining > 0) {
                if (remaining < CHUNK_SIZE) {
                    nextChunkSize = (int)remaining;
                    remaining = 0;
                    randomData = generateData(nextChunkSize, type, rng);
                }
                else {
                    remaining -= CHUNK_SIZE;
                    randomData = chunkSizeData;
                }
                output.write(randomData);
                Log.i(TAG, "while creating " + fileSize + " file, " +
                        "remaining bytes to be written: " + remaining);
            }
        } catch (IOException e) {
            Log.e(LOG_TAG, "Error writing to file " + file.getAbsolutePath());
            file.delete();
            throw e;
        } finally {
            output.close();
        }
        return file;
    }
 /**
     * Helper to wait for all downloads to finish, or else a timeout to occur
     *
     * @param query The query to pass to the download manager
     * @param poll The poll time to wait between checks
     * @param timeoutMillis The max amount of time (in ms) to wait for the download(s) to complete
     */
    protected void doWaitForDownloadsOrTimeout(Query query, long poll, long timeoutMillis)
            throws TimeoutException {
        int currentWaitTime = 0;
        while (true) {
            query.setFilterByStatus(DownloadManager.STATUS_PENDING | DownloadManager.STATUS_PAUSED
                    | DownloadManager.STATUS_RUNNING);
            Cursor cursor = mDownloadManager.query(query);

            try {
                if (cursor.getCount() == 0) {
                    Log.i(LOG_TAG, "All downloads should be done...");
                    break;
                }
                currentWaitTime = timeoutWait(currentWaitTime, poll, timeoutMillis,
                        "Timed out waiting for all downloads to finish");
            } finally {
                cursor.close();
            }
        }
    }
    
     /**
     * Helper function to synchronously wait, or timeout if the maximum threshold has been exceeded.
     *
     * @param currentTotalWaitTime The total time waited so far
     * @param poll The amount of time to wait
     * @param maxTimeoutMillis The total wait time threshold; if we've waited more than this long,
     *          we timeout and fail
     * @param timedOutMessage The message to display in the failure message if we timeout
     * @return The new total amount of time we've waited so far
     * @throws TimeoutException if timed out waiting for SD card to mount
     */
    protected int timeoutWait(int currentTotalWaitTime, long poll, long maxTimeoutMillis,
            String timedOutMessage) throws TimeoutException {
        long now = SystemClock.elapsedRealtime();
        long end = now + poll;

        // if we get InterruptedException's, ignore them and just keep sleeping
        while (now < end) {
            try {
                Thread.sleep(end - now);
            } catch (InterruptedException e) {
                // ignore interrupted exceptions
            }
            now = SystemClock.elapsedRealtime();
        }

        currentTotalWaitTime += poll;
        if (currentTotalWaitTime > maxTimeoutMillis) {
            throw new TimeoutException(timedOutMessage);
        }
        return currentTotalWaitTime;
    }

/**
     * Enables or disables WiFi.
     *
     * Note: Needs the following permissions:
     *  android.permission.ACCESS_WIFI_STATE
     *  android.permission.CHANGE_WIFI_STATE
     * @param enable true if it should be enabled, false if it should be disabled
     */
    protected void setWiFiStateOn(boolean enable) throws Exception {
        Log.i(LOG_TAG, "Setting WiFi State to: " + enable);
        WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);

        manager.setWifiEnabled(enable);

        String timeoutMessage = "Timed out waiting for Wifi to be "
            + (enable ? "enabled!" : "disabled!");

        WiFiChangedReceiver receiver = new WiFiChangedReceiver(mContext);
        mContext.registerReceiver(receiver, new IntentFilter(
                ConnectivityManager.CONNECTIVITY_ACTION));

        synchronized (receiver) {
            long timeoutTime = SystemClock.elapsedRealtime() + DEFAULT_MAX_WAIT_TIME;
            boolean timedOut = false;

            while (receiver.getWiFiIsOn() != enable && !timedOut) {
                try {
                    receiver.wait(DEFAULT_WAIT_POLL_TIME);

                    if (SystemClock.elapsedRealtime() > timeoutTime) {
                        timedOut = true;
                    }
                }
                catch (InterruptedException e) {
                    // ignore InterruptedExceptions
                }
            }
            if (timedOut) {
                fail(timeoutMessage);
            }
        }
        assertEquals(enable, receiver.getWiFiIsOn());
    }
    
    
        public static class WiFiChangedReceiver extends BroadcastReceiver {
        private Context mContext = null;

        /**
         * Constructor
         *
         * Sets the current state of WiFi.
         *
         * @param context The current app {@link Context}.
         */
        public WiFiChangedReceiver(Context context) {
            mContext = context;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION)) {
                Log.i(LOG_TAG, "ConnectivityManager state change: " + intent.getAction());
                synchronized (this) {
                    this.notify();
                }
            }
        }

        /**
         * Gets the current state of WiFi.
         *
         * @return Returns true if WiFi is on, false otherwise.
         */
        public boolean getWiFiIsOn() {
            ConnectivityManager connManager = (ConnectivityManager)mContext.getSystemService(
                    Context.CONNECTIVITY_SERVICE);
            NetworkInfo info = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            Log.i(LOG_TAG, "WiFi Connection state is currently: " + info.isConnected());
            return info.isConnected();
        }
    }
    
     /**
     * Helper to enables or disables airplane mode. If successful, it also broadcasts an intent
     * indicating that the mode has changed.
     *
     * Note: Needs the following permission:
     *  android.permission.WRITE_SETTINGS
     * @param enable true if airplane mode should be ON, false if it should be OFF
     */
    protected void setAirplaneModeOn(boolean enable) throws Exception {
        int state = enable ? 1 : 0;

        // Change the system setting
        Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
                state);

        String timeoutMessage = "Timed out waiting for airplane mode to be " +
                (enable ? "enabled!" : "disabled!");

        // wait for airplane mode to change state
        int currentWaitTime = 0;
        while (Settings.System.getInt(mContext.getContentResolver(),
                Settings.System.AIRPLANE_MODE_ON, -1) != state) {
            timeoutWait(currentWaitTime, DEFAULT_WAIT_POLL_TIME, DEFAULT_MAX_WAIT_TIME,
                    timeoutMessage);
        }

        // Post the intent
        Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
        intent.putExtra("state", true);
        mContext.sendBroadcast(intent);
    }
    
    
    
    
    
    
    
    
    ////////////////////////////////////////////////////////////
 
 ParcelFileDescriptor pfd = mDownloadManager.openDownloadedFile(requestId);
    
        /**
     * Helper to verify the size of a file.
     *
     * @param pfd The input file to compare the size of
     * @param size The expected size of the file
     */
    protected void verifyFileSize(ParcelFileDescriptor pfd, long size) {
        assertEquals(pfd.getStatSize(), size);
    }

    /**
     * Helper to verify the contents of a downloaded file versus a byte[].
     *
     * @param actual The file of whose contents to verify
     * @param expected The data we expect to find in the aforementioned file
     * @throws IOException if there was a problem reading from the file
     */
    protected void verifyFileContents(ParcelFileDescriptor actual, byte[] expected)
            throws IOException {
        AutoCloseInputStream input = new ParcelFileDescriptor.AutoCloseInputStream(actual);
        long fileSize = actual.getStatSize();

        assertTrue(fileSize <= Integer.MAX_VALUE);
        assertEquals(expected.length, fileSize);

        byte[] actualData = new byte[expected.length];
        assertEquals(input.read(actualData), fileSize);
        compareByteArrays(actualData, expected);
    }

    /**
     * Helper to compare 2 byte arrays.
     *
     * @param actual The array whose data we want to verify
     * @param expected The array of data we expect to see
     */
    protected void compareByteArrays(byte[] actual, byte[] expected) {
        assertEquals(actual.length, expected.length);
        int length = actual.length;
        for (int i = 0; i < length; ++i) {
            // assert has a bit of overhead, so only do the assert when the values are not the same
            if (actual[i] != expected[i]) {
                fail("Byte arrays are not equal.");
            }
        }
    }