Merge "Implement checks before performing background attachment download" into honeycomb
This commit is contained in:
commit
c0a8b2cfb0
@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.Cursor;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
@ -37,18 +38,41 @@ import java.util.List;
|
||||
* based on the attachment's filename and mime type.
|
||||
*/
|
||||
public class AttachmentInfo {
|
||||
// Projection which can be used with the constructor taking a Cursor argument
|
||||
public static final String[] PROJECTION = new String[] {Attachment.RECORD_ID, Attachment.SIZE,
|
||||
Attachment.FILENAME, Attachment.MIME_TYPE, Attachment.ACCOUNT_KEY};
|
||||
// Offsets into PROJECTION
|
||||
public static final int COLUMN_ID = 0;
|
||||
public static final int COLUMN_SIZE = 1;
|
||||
public static final int COLUMN_FILENAME = 2;
|
||||
public static final int COLUMN_MIME_TYPE = 3;
|
||||
public static final int COLUMN_ACCOUNT_KEY = 4;
|
||||
|
||||
public final long mId;
|
||||
public final long mSize;
|
||||
public final String mName;
|
||||
public final String mContentType;
|
||||
public final long mSize;
|
||||
public final long mId;
|
||||
public final long mAccountKey;
|
||||
public final boolean mAllowView;
|
||||
public final boolean mAllowSave;
|
||||
|
||||
public AttachmentInfo(Context context, Attachment attachment) {
|
||||
mSize = attachment.mSize;
|
||||
mContentType = AttachmentProvider.inferMimeType(attachment.mFileName, attachment.mMimeType);
|
||||
mName = attachment.mFileName;
|
||||
mId = attachment.mId;
|
||||
this(context, attachment.mId, attachment.mSize, attachment.mFileName, attachment.mMimeType,
|
||||
attachment.mAccountKey);
|
||||
}
|
||||
|
||||
public AttachmentInfo(Context context, Cursor c) {
|
||||
this(context, c.getLong(COLUMN_ID), c.getLong(COLUMN_SIZE), c.getString(COLUMN_FILENAME),
|
||||
c.getString(COLUMN_MIME_TYPE), c.getLong(COLUMN_ACCOUNT_KEY));
|
||||
}
|
||||
|
||||
public AttachmentInfo(Context context, long id, long size, String fileName, String mimeType,
|
||||
long accountKey) {
|
||||
mSize = size;
|
||||
mContentType = AttachmentProvider.inferMimeType(fileName, mimeType);
|
||||
mName = fileName;
|
||||
mId = id;
|
||||
mAccountKey = accountKey;
|
||||
boolean canView = true;
|
||||
boolean canSave = true;
|
||||
|
||||
@ -121,7 +145,11 @@ public class AttachmentInfo {
|
||||
* An attachment is eligible for download if it can either be viewed or saved (or both)
|
||||
* @return whether the attachment is eligible for download
|
||||
*/
|
||||
public boolean eligibleForDownload() {
|
||||
public boolean isEligibleForDownload() {
|
||||
return mAllowView || mAllowSave;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "{Attachment " + mId + ":" + mName + "," + mContentType + "," + mSize + "}";
|
||||
}
|
||||
}
|
||||
|
@ -16,12 +16,13 @@
|
||||
|
||||
package com.android.email.service;
|
||||
|
||||
import com.android.email.AttachmentInfo;
|
||||
import com.android.email.Controller.ControllerService;
|
||||
import com.android.email.Email;
|
||||
import com.android.email.ExchangeUtils.NullEmailService;
|
||||
import com.android.email.NotificationController;
|
||||
import com.android.email.Preferences;
|
||||
import com.android.email.Utility;
|
||||
import com.android.email.Controller.ControllerService;
|
||||
import com.android.email.ExchangeUtils.NullEmailService;
|
||||
import com.android.email.provider.AttachmentProvider;
|
||||
import com.android.email.provider.EmailContent;
|
||||
import com.android.email.provider.EmailContent.Account;
|
||||
@ -83,9 +84,8 @@ public class AttachmentDownloadService extends Service implements Runnable {
|
||||
// Limit on the number of simultaneous downloads per account
|
||||
// Note that a limit of 1 is currently enforced by both Services (MailService and Controller)
|
||||
private static final int MAX_SIMULTANEOUS_DOWNLOADS_PER_ACCOUNT = 1;
|
||||
|
||||
private static final Uri SINGLE_ATTACHMENT_URI =
|
||||
EmailContent.uriWithLimit(Attachment.CONTENT_URI, 1);
|
||||
// Limit on the number of attachments we'll check for background download
|
||||
private static final int MAX_ATTACHMENTS_TO_CHECK = 25;
|
||||
|
||||
/*package*/ static AttachmentDownloadService sRunningService = null;
|
||||
|
||||
@ -319,42 +319,41 @@ public class AttachmentDownloadService extends Service implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
// Respect the user's preference for background downloads
|
||||
if (!mPreferences.getBackgroundAttachments()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Then, try opportunistic download of appropriate attachments
|
||||
int backgroundDownloads = MAX_SIMULTANEOUS_DOWNLOADS - mDownloadsInProgress.size();
|
||||
// Always leave one slot for user requested download
|
||||
if (backgroundDownloads > (MAX_SIMULTANEOUS_DOWNLOADS - 1)) {
|
||||
boolean repeat = true;
|
||||
while (repeat) {
|
||||
// We'll take the most recent unloaded attachment
|
||||
Long prefetchId = Utility.getFirstRowLong(mContext, SINGLE_ATTACHMENT_URI,
|
||||
Attachment.ID_PROJECTION, AttachmentColumns.CONTENT_URI
|
||||
+ " isnull AND " + Attachment.FLAGS + "=0", null,
|
||||
Attachment.RECORD_ID + " DESC", Attachment.ID_PROJECTION_COLUMN);
|
||||
if (prefetchId == null) break;
|
||||
if (Email.DEBUG) {
|
||||
Log.d(TAG, ">> Prefetch attachment " + prefetchId);
|
||||
}
|
||||
Attachment att = Attachment.restoreAttachmentWithId(mContext, prefetchId);
|
||||
// If att is null, the attachment must have been deleted out from under us
|
||||
if (att == null) continue;
|
||||
if (getServiceClassForAccount(att.mAccountKey) == null) {
|
||||
// Clean up this orphaned attachment; there's no point in keeping it
|
||||
// around; then try to find another one
|
||||
EmailContent.delete(mContext, Attachment.CONTENT_URI, prefetchId);
|
||||
continue;
|
||||
}
|
||||
repeat = false;
|
||||
// TODO It's possible that we're just over limit for this particular account
|
||||
// Handle this so that attachments from other accounts (if any) can be tried
|
||||
if (canPrefetchForAccount(att.mAccountKey, mContext.getCacheDir())) {
|
||||
DownloadRequest req = new DownloadRequest(mContext, att);
|
||||
mDownloadSet.tryStartDownload(req);
|
||||
// We'll load up the newest 25 attachments that aren't loaded or queued
|
||||
Uri lookupUri = EmailContent.uriWithLimit(Attachment.CONTENT_URI,
|
||||
MAX_ATTACHMENTS_TO_CHECK);
|
||||
Cursor c = mContext.getContentResolver().query(lookupUri, AttachmentInfo.PROJECTION,
|
||||
AttachmentColumns.CONTENT_URI + " isnull AND " + Attachment.FLAGS + "=0",
|
||||
null, Attachment.RECORD_ID + " DESC");
|
||||
File cacheDir = mContext.getCacheDir();
|
||||
try {
|
||||
while (c.moveToNext()) {
|
||||
long accountKey = c.getLong(AttachmentInfo.COLUMN_ACCOUNT_KEY);
|
||||
long id = c.getLong(AttachmentInfo.COLUMN_ID);
|
||||
if (getServiceClassForAccount(accountKey) == null) {
|
||||
// Clean up this orphaned attachment; there's no point in keeping it
|
||||
// around; then try to find another one
|
||||
EmailContent.delete(mContext, Attachment.CONTENT_URI, id);
|
||||
} else if (canPrefetchForAccount(accountKey, cacheDir)) {
|
||||
// Check that the attachment meets system requirements for download
|
||||
AttachmentInfo info = new AttachmentInfo(mContext, c);
|
||||
if (info.isEligibleForDownload()) {
|
||||
Attachment att = Attachment.restoreAttachmentWithId(mContext, id);
|
||||
if (att != null) {
|
||||
// Start this download and we're done
|
||||
DownloadRequest req = new DownloadRequest(mContext, att);
|
||||
mDownloadSet.tryStartDownload(req);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -745,6 +744,12 @@ public class AttachmentDownloadService extends Service implements Runnable {
|
||||
* @return true if download is allowed, false otherwise
|
||||
*/
|
||||
/*package*/ boolean canPrefetchForAccount(long accountId, File dir) {
|
||||
Account account = Account.restoreAccountWithId(mContext, accountId);
|
||||
// Check account, just in case
|
||||
if (account == null) return false;
|
||||
// First, check preference and quickly return if prefetch isn't allowed
|
||||
if ((account.mFlags & Account.FLAGS_BACKGROUND_ATTACHMENTS) == 0) return false;
|
||||
|
||||
long totalStorage = dir.getTotalSpace();
|
||||
long usableStorage = dir.getUsableSpace();
|
||||
long minAvailable = (long)(totalStorage * PREFETCH_MINIMUM_STORAGE_AVAILABLE);
|
||||
|
Loading…
Reference in New Issue
Block a user