summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/downloads/DownloadInfo.java
diff options
context:
space:
mode:
authorSteve Howard <showard@google.com>2010-07-15 19:59:40 -0700
committerSteve Howard <showard@google.com>2010-07-19 11:04:38 -0700
commit071bd7acb3185f4f1e807855605c5e6018e9742f (patch)
tree85e1d36689bb632b20b74faaac9596d660a7a46d /src/com/android/providers/downloads/DownloadInfo.java
parent1aa26989047495ff58d3e2598d3f9549465cbb65 (diff)
downloadandroid_packages_providers_DownloadProvider-071bd7acb3185f4f1e807855605c5e6018e9742f.tar.gz
android_packages_providers_DownloadProvider-071bd7acb3185f4f1e807855605c5e6018e9742f.tar.bz2
android_packages_providers_DownloadProvider-071bd7acb3185f4f1e807855605c5e6018e9742f.zip
Support for max download size that may go over mobile
This change introduces support for a maximum download size that may go over a mobile connection. Downloads above this limit will wait for a wifi connection. To accomplish this, I moved a lot of the logic for checking connectivity info into DownloadInfo itself. I then moved the code to call these checks from DownloadService, where it would call the checks before spawning a DownloadThread, into DownloadThread itself. This makes it simpler to check connectivity after we get Content-Length info. It also eliminates the risk of a race condition where connectivity changes between the check and the actual request execution. I realize this change reduces efficiency, because we now call into ConnectivityManager/TelephonyManager twice per DownloadThread, rather than once per DownloadService "tick". I feel that it's OK since its a small amount of computation running relatively infrequently. If we feel that it's a serious concern, and that the efficiency issues outweigh the race problem, I can go easily back to the old approach. I've left out the code to actually fetch the limit. I think this will come from system settings, but I want to double-check, so I'll put it in a separate change. Other changes: * simplify SystemFacade's interface to get connectivity info - rather than returning all connected types, just return the active type, since that should be all we care about * adding @LargeTest to PublicApiFunctionalTest Change-Id: Id1faa2c45bf2dade9fe779440721a1d42cbdfcd1
Diffstat (limited to 'src/com/android/providers/downloads/DownloadInfo.java')
-rw-r--r--src/com/android/providers/downloads/DownloadInfo.java79
1 files changed, 66 insertions, 13 deletions
diff --git a/src/com/android/providers/downloads/DownloadInfo.java b/src/com/android/providers/downloads/DownloadInfo.java
index 1ae10ce1..5cd50c92 100644
--- a/src/com/android/providers/downloads/DownloadInfo.java
+++ b/src/com/android/providers/downloads/DownloadInfo.java
@@ -16,12 +16,16 @@
package com.android.providers.downloads;
-import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
+import android.net.ConnectivityManager;
import android.net.Uri;
import android.provider.Downloads;
+import android.provider.Downloads.Impl;
+import android.util.Log;
import java.util.Collections;
import java.util.HashMap;
@@ -59,9 +63,15 @@ public class DownloadInfo {
public int mFuzz;
public volatile boolean mHasActiveThread;
+
private Map<String, String> mRequestHeaders = new HashMap<String, String>();
+ private SystemFacade mSystemFacade;
+ private Context mContext;
+
+ public DownloadInfo(Context context, SystemFacade systemFacade, Cursor cursor) {
+ mContext = context;
+ mSystemFacade = systemFacade;
- public DownloadInfo(ContentResolver resolver, Cursor cursor) {
int retryRedirect =
cursor.getInt(cursor.getColumnIndexOrThrow(Constants.RETRY_AFTER_X_REDIRECT_COUNT));
mId = cursor.getInt(cursor.getColumnIndexOrThrow(Downloads.Impl._ID));
@@ -101,14 +111,14 @@ public class DownloadInfo {
mMediaScanned = cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) == 1;
mFuzz = Helpers.sRandom.nextInt(1001);
- readRequestHeaders(resolver, mId);
+ readRequestHeaders(mId);
}
- private void readRequestHeaders(ContentResolver resolver, long downloadId) {
+ private void readRequestHeaders(long downloadId) {
Uri headerUri = Downloads.Impl.CONTENT_URI.buildUpon()
.appendPath(Long.toString(downloadId))
.appendPath(Downloads.Impl.RequestHeaders.URI_SEGMENT).build();
- Cursor cursor = resolver.query(headerUri, null, null, null, null);
+ Cursor cursor = mContext.getContentResolver().query(headerUri, null, null, null, null);
try {
int headerIndex =
cursor.getColumnIndexOrThrow(Downloads.Impl.RequestHeaders.COLUMN_HEADER);
@@ -133,7 +143,7 @@ public class DownloadInfo {
return Collections.unmodifiableMap(mRequestHeaders);
}
- public void sendIntentIfRequested(Uri contentUri, Context context) {
+ public void sendIntentIfRequested(Uri contentUri) {
if (mPackage != null && mClass != null) {
Intent intent = new Intent(Downloads.Impl.ACTION_DOWNLOAD_COMPLETED);
intent.setClassName(mPackage, mClass);
@@ -144,7 +154,7 @@ public class DownloadInfo {
// applications would have an easier time spoofing download results by
// sending spoofed intents.
intent.setData(contentUri);
- context.sendBroadcast(intent);
+ mContext.sendBroadcast(intent);
}
}
@@ -247,14 +257,57 @@ public class DownloadInfo {
/**
* Returns whether this download is allowed to use the network.
*/
- public boolean canUseNetwork(boolean available, boolean roaming) {
- if (!available) {
+ public boolean canUseNetwork() {
+ Integer networkType = mSystemFacade.getActiveNetworkType();
+ if (networkType == null) {
return false;
}
- if (mDestination == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING) {
- return !roaming;
- } else {
- return true;
+ if (!isSizeAllowedForNetwork(networkType)) {
+ return false;
+ }
+ if (mDestination == Downloads.Impl.DESTINATION_CACHE_PARTITION_NOROAMING
+ && mSystemFacade.isNetworkRoaming()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Check if the download's size prohibits it from running over the current network.
+ */
+ private boolean isSizeAllowedForNetwork(int networkType) {
+ if (mTotalBytes <= 0) {
+ return true; // we don't know the size yet
+ }
+ if (networkType == ConnectivityManager.TYPE_WIFI) {
+ return true; // anything goes over wifi
+ }
+ Integer maxBytesOverMobile = mSystemFacade.getMaxBytesOverMobile();
+ if (maxBytesOverMobile == null) {
+ return true; // no limit
+ }
+ return mTotalBytes <= maxBytesOverMobile;
+ }
+
+ void startIfReady(long now) {
+ if (isReadyToStart(now)) {
+ if (Constants.LOGV) {
+ Log.v(Constants.TAG, "Service spawning thread to handle download " + mId);
+ }
+ if (mHasActiveThread) {
+ throw new IllegalStateException("Multiple threads on same download");
+ }
+ if (mStatus != Impl.STATUS_RUNNING) {
+ mStatus = Impl.STATUS_RUNNING;
+ ContentValues values = new ContentValues();
+ values.put(Impl.COLUMN_STATUS, mStatus);
+ mContext.getContentResolver().update(
+ ContentUris.withAppendedId(Impl.CONTENT_URI, mId),
+ values, null, null);
+ }
+ DownloadThread downloader = new DownloadThread(mContext, mSystemFacade, this);
+ mHasActiveThread = true;
+ downloader.start();
}
}
}