blob: d7fabdd7aaaeb5d8439b7fd4f12a4039516c1de0 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.download;
import android.graphics.Bitmap;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.chrome.browser.download.ui.DownloadFilter;
import org.chromium.components.download.DownloadState;
import org.chromium.components.download.ResumeMode;
import org.chromium.components.offline_items_collection.ContentId;
import org.chromium.components.offline_items_collection.FailState;
import org.chromium.components.offline_items_collection.LegacyHelpers;
import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.components.offline_items_collection.OfflineItem.Progress;
import org.chromium.components.offline_items_collection.OfflineItemFilter;
import org.chromium.components.offline_items_collection.OfflineItemProgressUnit;
import org.chromium.components.offline_items_collection.OfflineItemState;
import org.chromium.components.offline_items_collection.OfflineItemVisuals;
import org.chromium.components.offline_items_collection.PendingState;
/**
* Class representing the state of a single download.
*/
public final class DownloadInfo {
private final String mUrl;
private final String mUserAgent;
private final String mMimeType;
private final String mCookie;
private final String mFileName;
private final String mDescription;
private final String mFilePath;
private final String mReferrer;
private final String mOriginalUrl;
private final long mBytesReceived;
private final long mBytesTotalSize;
private final String mDownloadGuid;
private final boolean mHasUserGesture;
private final String mContentDisposition;
private final boolean mIsGETRequest;
private final Progress mProgress;
private final long mTimeRemainingInMillis;
private final boolean mIsResumable;
private final boolean mIsPaused;
private final boolean mIsOffTheRecord;
private final boolean mIsOfflinePage;
private final int mState;
private final long mLastAccessTime;
private final boolean mIsDangerous;
// New variables to assist with the migration to OfflineItems.
private final ContentId mContentId;
private final boolean mIsOpenable;
private final boolean mIsTransient;
private final boolean mIsParallelDownload;
private final Bitmap mIcon;
@PendingState
private final int mPendingState;
@FailState
private final int mFailState;
private final boolean mShouldPromoteOrigin;
private DownloadInfo(Builder builder) {
mUrl = builder.mUrl;
mUserAgent = builder.mUserAgent;
mMimeType = builder.mMimeType;
mCookie = builder.mCookie;
mFileName = builder.mFileName;
mDescription = builder.mDescription;
mFilePath = builder.mFilePath;
mReferrer = builder.mReferrer;
mOriginalUrl = builder.mOriginalUrl;
mBytesReceived = builder.mBytesReceived;
mBytesTotalSize = builder.mBytesTotalSize;
mDownloadGuid = builder.mDownloadGuid;
mHasUserGesture = builder.mHasUserGesture;
mIsGETRequest = builder.mIsGETRequest;
mContentDisposition = builder.mContentDisposition;
mProgress = builder.mProgress;
mTimeRemainingInMillis = builder.mTimeRemainingInMillis;
mIsResumable = builder.mIsResumable;
mIsPaused = builder.mIsPaused;
mIsOffTheRecord = builder.mIsOffTheRecord;
mIsOfflinePage = builder.mIsOfflinePage;
mState = builder.mState;
mLastAccessTime = builder.mLastAccessTime;
mIsDangerous = builder.mIsDangerous;
if (builder.mContentId != null) {
mContentId = builder.mContentId;
} else {
mContentId = LegacyHelpers.buildLegacyContentId(mIsOfflinePage, mDownloadGuid);
}
mIsOpenable = builder.mIsOpenable;
mIsTransient = builder.mIsTransient;
mIsParallelDownload = builder.mIsParallelDownload;
mIcon = builder.mIcon;
mPendingState = builder.mPendingState;
mFailState = builder.mFailState;
mShouldPromoteOrigin = builder.mShouldPromoteOrigin;
}
public String getUrl() {
return mUrl;
}
public String getUserAgent() {
return mUserAgent;
}
public String getMimeType() {
return mMimeType;
}
public String getCookie() {
return mCookie;
}
public String getFileName() {
return mFileName;
}
public String getDescription() {
return mDescription;
}
public String getFilePath() {
return mFilePath;
}
public String getReferrer() {
return mReferrer;
}
public String getOriginalUrl() {
return mOriginalUrl;
}
public long getBytesReceived() {
return mBytesReceived;
}
public long getBytesTotalSize() {
return mBytesTotalSize;
}
public boolean isGETRequest() {
return mIsGETRequest;
}
public String getDownloadGuid() {
return mDownloadGuid;
}
public boolean hasUserGesture() {
return mHasUserGesture;
}
public String getContentDisposition() {
return mContentDisposition;
}
public Progress getProgress() {
return mProgress;
}
/**
* @return Remaining download time in milliseconds or -1 if it is unknown.
*/
public long getTimeRemainingInMillis() {
return mTimeRemainingInMillis;
}
public boolean isResumable() {
return mIsResumable;
}
public boolean isPaused() {
return mIsPaused;
}
public boolean isOffTheRecord() {
return mIsOffTheRecord;
}
public boolean isOfflinePage() {
return mIsOfflinePage;
}
public int state() {
return mState;
}
public long getLastAccessTime() {
return mLastAccessTime;
}
public boolean getIsDangerous() {
return mIsDangerous;
}
public ContentId getContentId() {
return mContentId;
}
public boolean getIsOpenable() {
return mIsOpenable;
}
public boolean getIsTransient() {
return mIsTransient;
}
public boolean getIsParallelDownload() {
return mIsParallelDownload;
}
public Bitmap getIcon() {
return mIcon;
}
public @PendingState int getPendingState() {
return mPendingState;
}
public @FailState int getFailState() {
return mFailState;
}
public boolean getShouldPromoteOrigin() {
return mShouldPromoteOrigin;
}
/**
* Helper method to build a {@link DownloadInfo} from an {@link OfflineItem}.
* @param item The {@link OfflineItem} to mimic.
* @param visuals The {@link OfflineItemVisuals} to mimic.
* @return A {@link DownloadInfo} containing the relevant fields from {@code item}.
*/
public static DownloadInfo fromOfflineItem(OfflineItem item, OfflineItemVisuals visuals) {
return builderFromOfflineItem(item, visuals).build();
}
/**
* Helper method to build a {@link DownloadInfo.Builder} from an {@link OfflineItem}.
* @param item The {@link OfflineItem} to mimic.
* @param visuals The {@link OfflineItemVisuals} to mimic.
* @return A {@link DownloadInfo.Builder} containing the relevant fields from
* {@code item}.
*/
public static DownloadInfo.Builder builderFromOfflineItem(
OfflineItem item, OfflineItemVisuals visuals) {
int state;
switch (item.state) {
case OfflineItemState.COMPLETE:
state = DownloadState.COMPLETE;
break;
case OfflineItemState.CANCELLED:
state = DownloadState.CANCELLED;
break;
case OfflineItemState.INTERRUPTED:
state = DownloadState.INTERRUPTED;
break;
case OfflineItemState.FAILED:
state = DownloadState.INTERRUPTED; // TODO(dtrainor): Validate what this state is.
break;
case OfflineItemState.PENDING: // TODO(dtrainor): Validate what this state is.
case OfflineItemState.IN_PROGRESS:
case OfflineItemState.PAUSED: // TODO(dtrainor): Validate what this state is.
default:
state = DownloadState.IN_PROGRESS;
break;
}
return new DownloadInfo.Builder()
.setContentId(item.id)
.setDownloadGuid(item.id.id)
.setFileName(item.title)
.setFilePath(item.filePath)
.setDescription(item.description)
.setIsTransient(item.isTransient)
.setLastAccessTime(item.lastAccessedTimeMs)
.setIsOpenable(item.isOpenable)
.setMimeType(item.mimeType)
.setUrl(item.pageUrl)
.setOriginalUrl(item.originalUrl)
.setIsOffTheRecord(item.isOffTheRecord)
.setState(state)
.setIsPaused(item.state == OfflineItemState.PAUSED)
.setIsResumable(item.isResumable)
.setBytesReceived(item.receivedBytes)
.setBytesTotalSize(item.totalSizeBytes)
.setProgress(item.progress)
.setTimeRemainingInMillis(item.timeRemainingMs)
.setIsDangerous(item.isDangerous)
.setIsParallelDownload(item.isAccelerated)
.setIcon(visuals == null ? null : visuals.icon)
.setPendingState(item.pendingState)
.setFailState(item.failState)
.setShouldPromoteOrigin(item.promoteOrigin);
}
/**
* Helper method to build an {@link OfflineItem} from a {@link DownloadInfo}.
* @param item The {@link DownloadInfo} to mimic.
* @return A {@link OfflineItem} containing the relevant fields from {@code item}.
*/
public static OfflineItem createOfflineItem(DownloadInfo downloadInfo) {
OfflineItem offlineItem = new OfflineItem();
offlineItem.id = downloadInfo.getContentId();
offlineItem.filePath = downloadInfo.getFilePath();
offlineItem.title = downloadInfo.getFileName();
offlineItem.description = downloadInfo.getDescription();
offlineItem.isTransient = downloadInfo.getIsTransient();
offlineItem.isAccelerated = downloadInfo.getIsParallelDownload();
offlineItem.isSuggested = false;
offlineItem.totalSizeBytes = downloadInfo.getBytesTotalSize();
offlineItem.receivedBytes = downloadInfo.getBytesReceived();
offlineItem.isResumable = downloadInfo.isResumable();
offlineItem.pageUrl = downloadInfo.getUrl();
offlineItem.originalUrl = downloadInfo.getOriginalUrl();
offlineItem.isOffTheRecord = downloadInfo.isOffTheRecord();
offlineItem.mimeType = downloadInfo.getMimeType();
offlineItem.progress = downloadInfo.getProgress();
offlineItem.timeRemainingMs = downloadInfo.getTimeRemainingInMillis();
offlineItem.isDangerous = downloadInfo.getIsDangerous();
offlineItem.pendingState = downloadInfo.getPendingState();
offlineItem.failState = downloadInfo.getFailState();
offlineItem.promoteOrigin = downloadInfo.getShouldPromoteOrigin();
offlineItem.lastAccessedTimeMs = downloadInfo.getLastAccessTime();
switch (downloadInfo.state()) {
case DownloadState.IN_PROGRESS:
offlineItem.state = downloadInfo.isPaused() ? OfflineItemState.PAUSED
: OfflineItemState.IN_PROGRESS;
break;
case DownloadState.COMPLETE:
offlineItem.state = downloadInfo.getBytesReceived() == 0
? OfflineItemState.FAILED
: OfflineItemState.COMPLETE;
break;
case DownloadState.CANCELLED:
offlineItem.state = OfflineItemState.CANCELLED;
break;
case DownloadState.INTERRUPTED:
DownloadItem downloadItem = new DownloadItem(false, downloadInfo);
@ResumeMode
int resumeMode = DownloadUtils.getResumeMode(
downloadInfo.getUrl(), downloadInfo.getFailState());
if (resumeMode == ResumeMode.INVALID || resumeMode == ResumeMode.USER_RESTART) {
// Fail but can restart from the beginning. The UI should let the user to retry.
offlineItem.state = OfflineItemState.INTERRUPTED;
}
// TODO(xingliu): isDownloadPaused and isDownloadPending rely on isAutoResumable
// is set correctly in {@link DownloadSharedPreferenceEntry}. The states of
// notification UI and download home currently may not match. Also pending is
// related to Java side auto resumption on good network condition.
else if (DownloadUtils.isDownloadPaused(downloadItem)) {
offlineItem.state = OfflineItemState.PAUSED;
} else if (DownloadUtils.isDownloadPending(downloadItem)) {
offlineItem.state = OfflineItemState.PENDING;
} else {
// Unknown failure state.
offlineItem.state = OfflineItemState.FAILED;
}
break;
default:
assert false;
}
switch (DownloadFilter.fromMimeType(downloadInfo.getMimeType())) {
case DownloadFilter.Type.PAGE:
offlineItem.filter = OfflineItemFilter.FILTER_PAGE;
break;
case DownloadFilter.Type.VIDEO:
offlineItem.filter = OfflineItemFilter.FILTER_VIDEO;
break;
case DownloadFilter.Type.AUDIO:
offlineItem.filter = OfflineItemFilter.FILTER_AUDIO;
break;
case DownloadFilter.Type.IMAGE:
offlineItem.filter = OfflineItemFilter.FILTER_IMAGE;
break;
case DownloadFilter.Type.DOCUMENT:
offlineItem.filter = OfflineItemFilter.FILTER_DOCUMENT;
break;
case DownloadFilter.Type.OTHER:
default:
offlineItem.filter = OfflineItemFilter.FILTER_OTHER;
break;
}
return offlineItem;
}
/**
* Helper class for building the DownloadInfo object.
*/
public static class Builder {
private String mUrl;
private String mUserAgent;
private String mMimeType;
private String mCookie;
private String mFileName;
private String mDescription;
private String mFilePath;
private String mReferrer;
private String mOriginalUrl;
private long mBytesReceived;
private long mBytesTotalSize;
private boolean mIsGETRequest;
private String mDownloadGuid;
private boolean mHasUserGesture;
private String mContentDisposition;
private Progress mProgress = Progress.createIndeterminateProgress();
private long mTimeRemainingInMillis;
private boolean mIsResumable = true;
private boolean mIsPaused;
private boolean mIsOffTheRecord;
private boolean mIsOfflinePage;
private int mState = DownloadState.IN_PROGRESS;
private long mLastAccessTime;
private boolean mIsDangerous;
private ContentId mContentId;
private boolean mIsOpenable = true;
private boolean mIsTransient;
private boolean mIsParallelDownload;
private Bitmap mIcon;
@PendingState
private int mPendingState;
@FailState
private int mFailState;
private boolean mShouldPromoteOrigin;
public Builder setUrl(String url) {
mUrl = url;
return this;
}
public Builder setUserAgent(String userAgent) {
mUserAgent = userAgent;
return this;
}
public Builder setMimeType(String mimeType) {
mMimeType = mimeType;
return this;
}
public Builder setCookie(String cookie) {
mCookie = cookie;
return this;
}
public Builder setFileName(String fileName) {
mFileName = fileName;
return this;
}
public Builder setDescription(String description) {
mDescription = description;
return this;
}
public Builder setFilePath(String filePath) {
mFilePath = filePath;
return this;
}
public Builder setReferrer(String referer) {
mReferrer = referer;
return this;
}
public Builder setOriginalUrl(String originalUrl) {
mOriginalUrl = originalUrl;
return this;
}
public Builder setBytesReceived(long bytesReceived) {
mBytesReceived = bytesReceived;
return this;
}
public Builder setBytesTotalSize(long bytesTotalSize) {
mBytesTotalSize = bytesTotalSize;
return this;
}
public Builder setIsGETRequest(boolean isGETRequest) {
mIsGETRequest = isGETRequest;
return this;
}
public Builder setDownloadGuid(String downloadGuid) {
mDownloadGuid = downloadGuid;
return this;
}
public Builder setHasUserGesture(boolean hasUserGesture) {
mHasUserGesture = hasUserGesture;
return this;
}
public Builder setContentDisposition(String contentDisposition) {
mContentDisposition = contentDisposition;
return this;
}
public Builder setProgress(OfflineItem.Progress progress) {
mProgress = progress;
return this;
}
public Builder setTimeRemainingInMillis(long timeRemainingInMillis) {
mTimeRemainingInMillis = timeRemainingInMillis;
return this;
}
public Builder setIsResumable(boolean isResumable) {
mIsResumable = isResumable;
return this;
}
public Builder setIsPaused(boolean isPaused) {
mIsPaused = isPaused;
return this;
}
public Builder setIsOffTheRecord(boolean isOffTheRecord) {
mIsOffTheRecord = isOffTheRecord;
return this;
}
public Builder setIsOfflinePage(boolean isOfflinePage) {
mIsOfflinePage = isOfflinePage;
return this;
}
public Builder setState(int downloadState) {
mState = downloadState;
return this;
}
public Builder setLastAccessTime(long lastAccessTime) {
mLastAccessTime = lastAccessTime;
return this;
}
public Builder setIsDangerous(boolean isDangerous) {
mIsDangerous = isDangerous;
return this;
}
public Builder setContentId(ContentId contentId) {
mContentId = contentId;
return this;
}
public Builder setIsOpenable(boolean isOpenable) {
mIsOpenable = isOpenable;
return this;
}
public Builder setIsTransient(boolean isTransient) {
mIsTransient = isTransient;
return this;
}
public Builder setIsParallelDownload(boolean isParallelDownload) {
mIsParallelDownload = isParallelDownload;
return this;
}
public Builder setIcon(Bitmap icon) {
mIcon = icon;
return this;
}
public Builder setPendingState(@PendingState int pendingState) {
mPendingState = pendingState;
return this;
}
public Builder setFailState(@FailState int failState) {
mFailState = failState;
return this;
}
public Builder setShouldPromoteOrigin(boolean shouldPromoteOrigin) {
mShouldPromoteOrigin = shouldPromoteOrigin;
return this;
}
public DownloadInfo build() {
return new DownloadInfo(this);
}
/**
* Create a builder from the DownloadInfo object.
* @param downloadInfo DownloadInfo object from which builder fields are populated.
* @return A builder initialized with fields from downloadInfo object.
*/
public static Builder fromDownloadInfo(final DownloadInfo downloadInfo) {
Builder builder = new Builder();
builder.setUrl(downloadInfo.getUrl())
.setUserAgent(downloadInfo.getUserAgent())
.setMimeType(downloadInfo.getMimeType())
.setCookie(downloadInfo.getCookie())
.setFileName(downloadInfo.getFileName())
.setDescription(downloadInfo.getDescription())
.setFilePath(downloadInfo.getFilePath())
.setReferrer(downloadInfo.getReferrer())
.setOriginalUrl(downloadInfo.getOriginalUrl())
.setBytesReceived(downloadInfo.getBytesReceived())
.setBytesTotalSize(downloadInfo.getBytesTotalSize())
.setDownloadGuid(downloadInfo.getDownloadGuid())
.setHasUserGesture(downloadInfo.hasUserGesture())
.setContentDisposition(downloadInfo.getContentDisposition())
.setIsGETRequest(downloadInfo.isGETRequest())
.setProgress(downloadInfo.getProgress())
.setTimeRemainingInMillis(downloadInfo.getTimeRemainingInMillis())
.setIsDangerous(downloadInfo.getIsDangerous())
.setIsResumable(downloadInfo.isResumable())
.setIsPaused(downloadInfo.isPaused())
.setIsOffTheRecord(downloadInfo.isOffTheRecord())
.setIsOfflinePage(downloadInfo.isOfflinePage())
.setState(downloadInfo.state())
.setLastAccessTime(downloadInfo.getLastAccessTime())
.setIsTransient(downloadInfo.getIsTransient())
.setIsParallelDownload(downloadInfo.getIsParallelDownload())
.setIcon(downloadInfo.getIcon())
.setPendingState(downloadInfo.getPendingState())
.setFailState(downloadInfo.getFailState())
.setShouldPromoteOrigin(downloadInfo.getShouldPromoteOrigin());
return builder;
}
}
@CalledByNative
private static DownloadInfo createDownloadInfo(String downloadGuid, String fileName,
String filePath, String url, String mimeType, long bytesReceived, long bytesTotalSize,
boolean isIncognito, int state, int percentCompleted, boolean isPaused,
boolean hasUserGesture, boolean isResumable, boolean isParallelDownload,
String originalUrl, String referrerUrl, long timeRemainingInMs, long lastAccessTime,
boolean isDangerous, @FailState int failState) {
String remappedMimeType = ChromeDownloadDelegate.remapGenericMimeType(
mimeType, url, fileName);
Progress progress = new Progress(bytesReceived,
percentCompleted == -1 ? null : bytesTotalSize, OfflineItemProgressUnit.BYTES);
return new DownloadInfo.Builder()
.setBytesReceived(bytesReceived)
.setBytesTotalSize(bytesTotalSize)
.setDescription(fileName)
.setDownloadGuid(downloadGuid)
.setFileName(fileName)
.setFilePath(filePath)
.setHasUserGesture(hasUserGesture)
.setIsOffTheRecord(isIncognito)
.setIsPaused(isPaused)
.setIsResumable(isResumable)
.setIsParallelDownload(isParallelDownload)
.setMimeType(remappedMimeType)
.setOriginalUrl(originalUrl)
.setProgress(progress)
.setReferrer(referrerUrl)
.setState(state)
.setTimeRemainingInMillis(timeRemainingInMs)
.setLastAccessTime(lastAccessTime)
.setIsDangerous(isDangerous)
.setUrl(url)
.setFailState(failState)
.build();
}
}