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