1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.chrome.browser.download; 6 7 import org.chromium.base.annotations.CalledByNative; 8 import org.chromium.components.download.DownloadState; 9 import org.chromium.components.download.ResumeMode; 10 import org.chromium.components.offline_items_collection.ContentId; 11 import org.chromium.components.offline_items_collection.OfflineItem; 12 import org.chromium.components.offline_items_collection.OfflineItem.Progress; 13 import org.chromium.components.offline_items_collection.OfflineItemFilter; 14 import org.chromium.components.offline_items_collection.OfflineItemState; 15 16 /** 17 * A generic class representing a download item. The item can be either downloaded through the 18 * Android DownloadManager, or through Chrome's network stack. 19 * 20 * This represents the native DownloadItem at a specific point in time -- the native side 21 * DownloadManager must be queried for the correct status. 22 */ 23 public class DownloadItem { 24 private final ContentId mContentId = new ContentId(); 25 private boolean mUseAndroidDownloadManager; 26 private DownloadInfo mDownloadInfo; 27 private long mDownloadId = DownloadConstants.INVALID_DOWNLOAD_ID; 28 private long mStartTime; 29 private long mEndTime; 30 private boolean mHasBeenExternallyRemoved; 31 DownloadItem(boolean useAndroidDownloadManager, DownloadInfo info)32 public DownloadItem(boolean useAndroidDownloadManager, DownloadInfo info) { 33 mUseAndroidDownloadManager = useAndroidDownloadManager; 34 mDownloadInfo = info; 35 if (mDownloadInfo != null) mContentId.namespace = mDownloadInfo.getContentId().namespace; 36 mContentId.id = getId(); 37 } 38 39 /** 40 * Sets the system download ID retrieved from Android DownloadManager. 41 * 42 * @param downloadId ID from the Android DownloadManager. 43 */ setSystemDownloadId(long downloadId)44 public void setSystemDownloadId(long downloadId) { 45 mDownloadId = downloadId; 46 47 // Update our ContentId in case it changed. 48 mContentId.id = getId(); 49 } 50 51 /** 52 * @return System download ID from the Android DownloadManager. 53 */ getSystemDownloadId()54 public long getSystemDownloadId() { 55 return mDownloadId; 56 } 57 58 /** 59 * @return A {@link ContentId} that represents this downloaded item. The id will match 60 * {@link #getId()}. 61 */ getContentId()62 public ContentId getContentId() { 63 return mContentId; 64 } 65 66 /** 67 * @return String ID that uniquely identifies the download. 68 */ getId()69 public String getId() { 70 if (mUseAndroidDownloadManager) { 71 return String.valueOf(mDownloadId); 72 } 73 return mDownloadInfo.getDownloadGuid(); 74 } 75 76 /** 77 * @return Info about the download. 78 */ getDownloadInfo()79 public DownloadInfo getDownloadInfo() { 80 return mDownloadInfo; 81 } 82 83 /** 84 * Sets the system download info. 85 * 86 * @param info Download information. 87 */ setDownloadInfo(DownloadInfo info)88 public void setDownloadInfo(DownloadInfo info) { 89 mDownloadInfo = info; 90 } 91 92 /** 93 * Sets the download start time. 94 * 95 * @param startTime Download start time from System.currentTimeMillis(). 96 */ setStartTime(long startTime)97 public void setStartTime(long startTime) { 98 mStartTime = startTime; 99 } 100 101 /** 102 * Gets the download start time. 103 * 104 * @return Download start time from System.currentTimeMillis(). 105 */ getStartTime()106 public long getStartTime() { 107 return mStartTime; 108 } 109 110 /** 111 * Sets the download end time. 112 * 113 * @param endTime Download end time from System.currentTimeMillis(). 114 */ setEndTime(long endTime)115 public void setEndTime(long endTime) { 116 mEndTime = endTime; 117 } 118 119 /** 120 * Gets the download end time. 121 * 122 * @return Download end time from System.currentTimeMillis(). 123 */ getEndTime()124 public long getEndTime() { 125 return mEndTime; 126 } 127 128 /** 129 * Sets whether the file associated with this item has been removed through an external 130 * action. 131 * 132 * @param hasBeenExternallyRemoved Whether the file associated with this item has been removed 133 * from the file system through a means other than the browser 134 * download ui. 135 */ setHasBeenExternallyRemoved(boolean hasBeenExternallyRemoved)136 public void setHasBeenExternallyRemoved(boolean hasBeenExternallyRemoved) { 137 mHasBeenExternallyRemoved = hasBeenExternallyRemoved; 138 } 139 140 /** 141 * @return Whether the file associated with this item has been removed from the file system 142 * through a means other than the browser download ui. 143 */ hasBeenExternallyRemoved()144 public boolean hasBeenExternallyRemoved() { 145 return mHasBeenExternallyRemoved; 146 } 147 148 /** 149 * Helper method to build an {@link OfflineItem} from a {@link DownloadItem}. 150 * @param item The {@link DownloadItem} to mimic. 151 * @return A {@link OfflineItem} containing the relevant fields from {@code item}. 152 */ createOfflineItem(DownloadItem item)153 public static OfflineItem createOfflineItem(DownloadItem item) { 154 OfflineItem offlineItem = new OfflineItem(); 155 DownloadInfo downloadInfo = item.getDownloadInfo(); 156 offlineItem.id = downloadInfo.getContentId(); 157 offlineItem.filePath = downloadInfo.getFilePath(); 158 offlineItem.title = downloadInfo.getFileName(); 159 offlineItem.description = downloadInfo.getDescription(); 160 offlineItem.isTransient = downloadInfo.getIsTransient(); 161 offlineItem.isAccelerated = downloadInfo.getIsParallelDownload(); 162 offlineItem.isSuggested = false; 163 offlineItem.totalSizeBytes = downloadInfo.getBytesTotalSize(); 164 offlineItem.receivedBytes = downloadInfo.getBytesReceived(); 165 offlineItem.isResumable = downloadInfo.isResumable(); 166 offlineItem.pageUrl = downloadInfo.getUrl(); 167 offlineItem.originalUrl = downloadInfo.getOriginalUrl(); 168 offlineItem.isOffTheRecord = downloadInfo.isOffTheRecord(); 169 offlineItem.mimeType = downloadInfo.getMimeType(); 170 offlineItem.progress = downloadInfo.getProgress(); 171 offlineItem.timeRemainingMs = downloadInfo.getTimeRemainingInMillis(); 172 offlineItem.isDangerous = downloadInfo.getIsDangerous(); 173 offlineItem.pendingState = downloadInfo.getPendingState(); 174 offlineItem.failState = downloadInfo.getFailState(); 175 offlineItem.promoteOrigin = downloadInfo.getShouldPromoteOrigin(); 176 offlineItem.lastAccessedTimeMs = downloadInfo.getLastAccessTime(); 177 offlineItem.creationTimeMs = item.getStartTime(); 178 offlineItem.completionTimeMs = item.getEndTime(); 179 offlineItem.externallyRemoved = item.hasBeenExternallyRemoved(); 180 offlineItem.canRename = item.getDownloadInfo().state() == DownloadState.COMPLETE; 181 offlineItem.schedule = downloadInfo.getOfflineItemSchedule(); 182 switch (downloadInfo.state()) { 183 case DownloadState.IN_PROGRESS: 184 offlineItem.state = downloadInfo.isPaused() ? OfflineItemState.PAUSED 185 : OfflineItemState.IN_PROGRESS; 186 break; 187 case DownloadState.COMPLETE: 188 offlineItem.state = downloadInfo.getBytesReceived() == 0 189 ? OfflineItemState.FAILED 190 : OfflineItemState.COMPLETE; 191 break; 192 case DownloadState.CANCELLED: 193 offlineItem.state = OfflineItemState.CANCELLED; 194 break; 195 case DownloadState.INTERRUPTED: 196 @ResumeMode 197 int resumeMode = DownloadUtils.getResumeMode( 198 downloadInfo.getUrl(), downloadInfo.getFailState()); 199 if (resumeMode == ResumeMode.INVALID || resumeMode == ResumeMode.USER_RESTART) { 200 // Fail but can restart from the beginning. The UI should let the user to retry. 201 offlineItem.state = OfflineItemState.INTERRUPTED; 202 } 203 // TODO(xingliu): isDownloadPaused and isDownloadPending rely on isAutoResumable 204 // is set correctly in {@link DownloadSharedPreferenceEntry}. The states of 205 // notification UI and download home currently may not match. Also pending is 206 // related to Java side auto resumption on good network condition. 207 else if (downloadInfo.isPaused()) { 208 offlineItem.state = OfflineItemState.PAUSED; 209 } else if (DownloadUtils.isDownloadPending(item)) { 210 offlineItem.state = OfflineItemState.PENDING; 211 } else { 212 // Unknown failure state. 213 offlineItem.state = OfflineItemState.FAILED; 214 } 215 break; 216 default: 217 assert false; 218 } 219 220 switch (DownloadFilter.fromMimeType(downloadInfo.getMimeType())) { 221 case DownloadFilter.Type.PAGE: 222 offlineItem.filter = OfflineItemFilter.PAGE; 223 break; 224 case DownloadFilter.Type.VIDEO: 225 offlineItem.filter = OfflineItemFilter.VIDEO; 226 break; 227 case DownloadFilter.Type.AUDIO: 228 offlineItem.filter = OfflineItemFilter.AUDIO; 229 break; 230 case DownloadFilter.Type.IMAGE: 231 offlineItem.filter = OfflineItemFilter.IMAGE; 232 break; 233 case DownloadFilter.Type.DOCUMENT: 234 offlineItem.filter = OfflineItemFilter.DOCUMENT; 235 break; 236 case DownloadFilter.Type.OTHER: 237 default: 238 offlineItem.filter = OfflineItemFilter.OTHER; 239 break; 240 } 241 242 return offlineItem; 243 } 244 245 @CalledByNative createDownloadItem(DownloadInfo downloadInfo, long startTimestamp, long endTimestamp, boolean hasBeenExternallyRemoved)246 private static DownloadItem createDownloadItem(DownloadInfo downloadInfo, long startTimestamp, 247 long endTimestamp, boolean hasBeenExternallyRemoved) { 248 DownloadItem downloadItem = new DownloadItem(false, downloadInfo); 249 downloadItem.setStartTime(startTimestamp); 250 downloadItem.setEndTime(endTimestamp); 251 downloadItem.setHasBeenExternallyRemoved(hasBeenExternallyRemoved); 252 return downloadItem; 253 } 254 255 /** 256 * @return Whether or not the download has an indeterminate percentage. 257 */ isIndeterminate()258 public boolean isIndeterminate() { 259 Progress progress = getDownloadInfo().getProgress(); 260 return progress == null || progress.isIndeterminate(); 261 } 262 } 263