Пример #1
0
  /**
   * Read the data from the URI.
   *
   * @param dest where to write it to.
   * @return true if we read the entire stream.
   */
  /* package */ CompletionStatus readFromUri(final String dest) {
    cumulativeBytesRead = 0L;
    if (null == uri) {
      failureMessage = MSG_BAD_URI;
      downloadErrorCode = DownloadError.BAD_URI.getValue();
      return CompletionStatus.FAILED;
    }
    if (!haveNetwork()) {
      Log.i(LOG_TAG, "No network appears available, insta-pausing download");
      failureMessage = MSG_NO_NETWORK;
      downloadErrorCode = DownloadError.NO_NETWORK.getValue();
      return CompletionStatus.PAUSED;
    }

    // Give the download policy a chance to veto based only on the URI
    final DownloadPolicyProvider dpp = provider.get();
    if (null != dpp) {
      final DownloadPolicyProvider.Response policyResponse = dpp.mayStartDownload(forUser, uri);
      if (policyResponse != null) {
        final boolean policyResponseResponse = policyResponse.getResponse();
        if (!policyResponseResponse) {
          failureMessage = MSG_VETO + policyResponse.getReason();
          downloadErrorCode = DownloadError.POLICY_ERROR.getValue();
          if (policyResponse.getShouldPause()) {
            return CompletionStatus.PAUSED;
          }
          return CompletionStatus.FAILED;
        }
      } else {
        Log.w(LOG_TAG, "DownloadPolicyProvider response was null!");
      }
    }

    // Acquire a wifi lock if required.
    networkStatusProvider.acquireWifiLock(downloadId);
    int retryAttempt = 0;
    while (retryAttempt < NUM_RETRIES) {
      start();
      InputStream stream = null;
      RandomAccessFile output = null;
      try {
        output = new RandomAccessFile(dest, "rw");

        final URL url = new URL(uri);
        final HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
        setupRequest(httpURLConnection);

        // Open connection and send headers.
        stream = httpURLConnection.getInputStream();

        // check response
        final int responseCode = httpURLConnection.getResponseCode();

        if (!gotSuccessResponse(responseCode)) {
          Log.w(LOG_TAG, "Did not get a 2xx response code back from request.");
          // Could use getErrorStream to read back error info.
          failureMessage = MSG_PREFIX_HTTP + responseCode;
          // get error code string
          downloadErrorCode = DownloadError.HTTP_ERROR.getValue();
          return CompletionStatus.FAILED;
        }

        if (!gotValidRangeResponse(responseCode)) {
          // we didn't get a 206, but instead a 200 indicating to re-read the entire entity
          Log.w(LOG_TAG, "Did not get a 206 response code back from request.");
          downloadOffset = 0L;
        }

        // if we don't currently have an eTag for this download, try to set from the response
        // headers.
        if (downloadTag == null) {
          downloadTag = httpURLConnection.getHeaderField(Downloader.HEADER_ETAG);
        }

        // update the mime type and other fields in the content provider whether the actual
        // read is vetoed or not
        updateProviderFromHeaders(httpURLConnection);

        // Give the download policy a chance to veto based on the URI and file type and size
        if (totalBytes == 0L) {
          totalBytes = getTotalLengthFromHeader(httpURLConnection);
        }
        final String mt = getMimeType(httpURLConnection);
        if (null != dpp) {
          final DownloadPolicyProvider.Response policyResponse =
              dpp.mayReadStream(forUser, uri, totalBytes, mt);
          if (policyResponse != null) {
            final boolean policyResponseResponse = policyResponse.getResponse();
            if (!policyResponseResponse) {
              // We are aborting the request, since the finally block closes the stream,
              // there is nothing additional to do here.
              failureMessage = MSG_VETO + policyResponse.getReason();
              downloadErrorCode = DownloadError.POLICY_ERROR.getValue();
              if (policyResponse.getShouldPause()) {
                return CompletionStatus.PAUSED;
              }
              return CompletionStatus.FAILED;
            }
          } else {
            Log.w(LOG_TAG, "DownloadPolicyProvider response was null!");
          }
        }

        output.seek(downloadOffset);
        final byte[] buffer = new byte[BUFFER_SIZE];
        cumulativeBytesRead = downloadOffset;
        int bytesRead;
        boolean interrupted = false;

        while ((bytesRead = stream.read(buffer)) > 0) {
          cumulativeBytesRead += bytesRead;
          output.write(buffer, 0, bytesRead);

          if (!isSilent) {
            sendProgress(cumulativeBytesRead, totalBytes);
          }

          if (Thread.interrupted() || !TaskCancelReason.UNEXPECTED.equals(getCancelReason())) {
            Log.i(LOG_TAG, "Download task is interrupted");
            switch (getCancelReason()) {
              case UNEXPECTED:
                Log.w(LOG_TAG, "Unexpected interruption of download task.");
                failureMessage = MSG_UNEXPECTED_INTERRUPTION;
                downloadErrorCode = DownloadError.DOWNLOAD_INTERRUPTED.getValue();
                retryAttempt = NUM_RETRIES;
                break;
              case PAUSED_BY_USER:
                // Set the failure message since this gets passed back as a completion description.
                failureMessage = MSG_PAUSED_DOWNLOAD;
                downloadErrorCode = DownloadError.USER_PAUSED.getValue();
                return CompletionStatus.PAUSED_BY_USER;
              case CANCELED_BY_USER:
                failureMessage = MSG_CANCELED_DOWNLOAD;
                downloadErrorCode = DownloadError.USER_CANCELED.getValue();
                interrupted = true;
                retryAttempt = Integer.MAX_VALUE;
                break;
            }
            break;
          }
        }

        if (!interrupted) {
          return CompletionStatus.SUCCEEDED;
        }
      } catch (final IOException ex) {
        Log.e(LOG_TAG, "Caught IO exception while downloading", ex);
        failureMessage = ex.getClass().getSimpleName() + ": " + ex.getMessage();
        downloadErrorCode = DownloadError.IO_EXCEPTION.getValue();
        retryAttempt++;
        downloadOffset = cumulativeBytesRead;
      } finally {
        safeClose(stream);
        safeClose(output);
      }

      // if we succeeded in getting any of the file, report a pause so that it can be resumed.
      if (haveDownloadProgress() && retryAttempt == NUM_RETRIES) {
        return CompletionStatus.PAUSED;
      }
    }
    return CompletionStatus.FAILED;
  }