summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/downloads
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/providers/downloads')
-rw-r--r--src/com/android/providers/downloads/DownloadInfo.java79
-rw-r--r--src/com/android/providers/downloads/DownloadService.java78
-rw-r--r--src/com/android/providers/downloads/DownloadThread.java15
-rw-r--r--src/com/android/providers/downloads/Helpers.java12
-rw-r--r--src/com/android/providers/downloads/RealSystemFacade.java37
-rw-r--r--src/com/android/providers/downloads/SystemFacade.java12
6 files changed, 114 insertions, 119 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();
}
}
}
diff --git a/src/com/android/providers/downloads/DownloadService.java b/src/com/android/providers/downloads/DownloadService.java
index b5cb2d45..e474d4d7 100644
--- a/src/com/android/providers/downloads/DownloadService.java
+++ b/src/com/android/providers/downloads/DownloadService.java
@@ -310,8 +310,6 @@ public class DownloadService extends Service {
}
mPendingUpdate = false;
}
- boolean networkAvailable = Helpers.isNetworkAvailable(mSystemFacade);
- boolean networkRoaming = Helpers.isNetworkRoaming(mSystemFacade);
long now = mSystemFacade.currentTimeMillis();
Cursor cursor = getContentResolver().query(Downloads.Impl.CONTENT_URI,
@@ -368,7 +366,7 @@ public class DownloadService extends Service {
int id = cursor.getInt(idColumn);
if (arrayPos == mDownloads.size()) {
- insertDownload(cursor, arrayPos, networkAvailable, networkRoaming, now);
+ insertDownload(cursor, arrayPos, now);
if (Constants.LOGVV) {
Log.v(Constants.TAG, "Array update: appending " +
id + " @ " + arrayPos);
@@ -405,9 +403,7 @@ public class DownloadService extends Service {
deleteDownload(arrayPos); // this advances in the array
} else if (arrayId == id) {
// This cursor row already exists in the stored array
- updateDownload(
- cursor, arrayPos,
- networkAvailable, networkRoaming, now);
+ updateDownload(cursor, arrayPos, now);
if (shouldScanFile(arrayPos)
&& (!mediaScannerConnected()
|| !scanFile(cursor, arrayPos))) {
@@ -432,9 +428,7 @@ public class DownloadService extends Service {
Log.v(Constants.TAG, "Array update: inserting " +
id + " @ " + arrayPos);
}
- insertDownload(
- cursor, arrayPos,
- networkAvailable, networkRoaming, now);
+ insertDownload(cursor, arrayPos, now);
if (shouldScanFile(arrayPos)
&& (!mediaScannerConnected()
|| !scanFile(cursor, arrayPos))) {
@@ -551,10 +545,8 @@ public class DownloadService extends Service {
* Keeps a local copy of the info about a download, and initiates the
* download if appropriate.
*/
- private void insertDownload(
- Cursor cursor, int arrayPos,
- boolean networkAvailable, boolean networkRoaming, long now) {
- DownloadInfo info = new DownloadInfo(getContentResolver(), cursor);
+ private void insertDownload(Cursor cursor, int arrayPos, long now) {
+ DownloadInfo info = new DownloadInfo(this, mSystemFacade, cursor);
if (Constants.LOGVV) {
Log.v(Constants.TAG, "Service adding new entry");
@@ -617,51 +609,18 @@ public class DownloadService extends Service {
ContentValues values = new ContentValues();
values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_NOT_ACCEPTABLE);
getContentResolver().update(uri, values, null, null);
- info.sendIntentIfRequested(uri, this);
+ info.sendIntentIfRequested(uri);
return;
}
}
- if (info.canUseNetwork(networkAvailable, networkRoaming)) {
- if (info.isReadyToStart(now)) {
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "Service spawning thread to handle new download " +
- info.mId);
- }
- if (info.mHasActiveThread) {
- throw new IllegalStateException("Multiple threads on same download on insert");
- }
- if (info.mStatus != Downloads.Impl.STATUS_RUNNING) {
- info.mStatus = Downloads.Impl.STATUS_RUNNING;
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_STATUS, info.mStatus);
- getContentResolver().update(
- ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, info.mId),
- values, null, null);
- }
- DownloadThread downloader = new DownloadThread(this, mSystemFacade, info);
- info.mHasActiveThread = true;
- downloader.start();
- }
- } else {
- if (info.mStatus == 0
- || info.mStatus == Downloads.Impl.STATUS_PENDING
- || info.mStatus == Downloads.Impl.STATUS_RUNNING) {
- info.mStatus = Downloads.Impl.STATUS_RUNNING_PAUSED;
- Uri uri = ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, info.mId);
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_RUNNING_PAUSED);
- getContentResolver().update(uri, values, null, null);
- }
- }
+ info.startIfReady(now);
}
/**
* Updates the local copy of the info about a download.
*/
- private void updateDownload(
- Cursor cursor, int arrayPos,
- boolean networkAvailable, boolean networkRoaming, long now) {
+ private void updateDownload(Cursor cursor, int arrayPos, long now) {
DownloadInfo info = (DownloadInfo) mDownloads.get(arrayPos);
int statusColumn = cursor.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS);
int failedColumn = cursor.getColumnIndexOrThrow(Constants.FAILED_CONNECTIONS);
@@ -715,26 +674,7 @@ public class DownloadService extends Service {
info.mMediaScanned =
cursor.getInt(cursor.getColumnIndexOrThrow(Constants.MEDIA_SCANNED)) == 1;
- if (info.canUseNetwork(networkAvailable, networkRoaming)) {
- if (info.isReadyToRestart(now)) {
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "Service spawning thread to handle updated download " +
- info.mId);
- }
- if (info.mHasActiveThread) {
- throw new IllegalStateException("Multiple threads on same download on update");
- }
- info.mStatus = Downloads.Impl.STATUS_RUNNING;
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_STATUS, info.mStatus);
- getContentResolver().update(
- ContentUris.withAppendedId(Downloads.Impl.CONTENT_URI, info.mId),
- values, null, null);
- DownloadThread downloader = new DownloadThread(this, mSystemFacade, info);
- info.mHasActiveThread = true;
- downloader.start();
- }
- }
+ info.startIfReady(now);
}
/**
diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java
index e7763e4e..d8271a2b 100644
--- a/src/com/android/providers/downloads/DownloadThread.java
+++ b/src/com/android/providers/downloads/DownloadThread.java
@@ -195,6 +195,12 @@ http_request_loop:
request.addHeader("Range", "bytes=" + bytesSoFar + "-");
}
+ // check connectivity just before sending
+ if (!mInfo.canUseNetwork()) {
+ finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED;
+ break http_request_loop;
+ }
+
HttpResponse response;
try {
response = client.execute(request);
@@ -437,8 +443,15 @@ http_request_loop:
if (headerContentLength != null) {
contentLength = Integer.parseInt(headerContentLength);
}
+ mInfo.mTotalBytes = contentLength;
values.put(Downloads.Impl.COLUMN_TOTAL_BYTES, contentLength);
mContext.getContentResolver().update(contentUri, values, null, null);
+ // check connectivity again now that we know the total size
+ if (!mInfo.canUseNetwork()) {
+ finalStatus = Downloads.Impl.STATUS_RUNNING_PAUSED;
+ request.abort();
+ break http_request_loop;
+ }
}
InputStream entityStream;
@@ -772,7 +785,7 @@ http_request_loop:
*/
private void notifyThroughIntent() {
Uri uri = Uri.parse(Downloads.Impl.CONTENT_URI + "/" + mInfo.mId);
- mInfo.sendIntentIfRequested(uri, mContext);
+ mInfo.sendIntentIfRequested(uri);
}
/**
diff --git a/src/com/android/providers/downloads/Helpers.java b/src/com/android/providers/downloads/Helpers.java
index 4a0f860b..0ad4edc0 100644
--- a/src/com/android/providers/downloads/Helpers.java
+++ b/src/com/android/providers/downloads/Helpers.java
@@ -23,14 +23,11 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.drm.mobile1.DrmRawContent;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
import android.net.Uri;
import android.os.Environment;
import android.os.StatFs;
import android.os.SystemClock;
import android.provider.Downloads;
-import android.telephony.TelephonyManager;
import android.util.Config;
import android.util.Log;
import android.webkit.MimeTypeMap;
@@ -515,14 +512,7 @@ public class Helpers {
* Returns whether the network is available
*/
public static boolean isNetworkAvailable(SystemFacade system) {
- return !system.getConnectedNetworkTypes().isEmpty();
- }
-
- /**
- * Returns whether the network is roaming
- */
- public static boolean isNetworkRoaming(SystemFacade system) {
- return system.isNetworkRoaming();
+ return system.getActiveNetworkType() != null;
}
/**
diff --git a/src/com/android/providers/downloads/RealSystemFacade.java b/src/com/android/providers/downloads/RealSystemFacade.java
index 41ca6b6e..89cf3b1d 100644
--- a/src/com/android/providers/downloads/RealSystemFacade.java
+++ b/src/com/android/providers/downloads/RealSystemFacade.java
@@ -6,8 +6,6 @@ import android.net.NetworkInfo;
import android.telephony.TelephonyManager;
import android.util.Log;
-import java.util.BitSet;
-
class RealSystemFacade implements SystemFacade {
private Context mContext;
@@ -19,30 +17,22 @@ class RealSystemFacade implements SystemFacade {
return System.currentTimeMillis();
}
- public BitSet getConnectedNetworkTypes() {
- BitSet connectedTypes = new BitSet();
-
+ public Integer getActiveNetworkType() {
ConnectivityManager connectivity =
(ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivity == null) {
Log.w(Constants.TAG, "couldn't get connectivity manager");
- return connectedTypes;
+ return null;
}
- NetworkInfo[] infos = connectivity.getAllNetworkInfo();
- if (infos != null) {
- for (NetworkInfo info : infos) {
- if (info.getState() == NetworkInfo.State.CONNECTED) {
- connectedTypes.set(info.getType());
- }
+ NetworkInfo activeInfo = connectivity.getActiveNetworkInfo();
+ if (activeInfo == null) {
+ if (Constants.LOGVV) {
+ Log.v(Constants.TAG, "network is not available");
}
+ return null;
}
-
- if (Constants.LOGVV) {
- boolean isConnected = !connectedTypes.isEmpty();
- Log.v(Constants.TAG, "network is " + (isConnected ? "" : "not ") + "available");
- }
- return connectedTypes;
+ return activeInfo.getType();
}
public boolean isNetworkRoaming() {
@@ -56,10 +46,13 @@ class RealSystemFacade implements SystemFacade {
NetworkInfo info = connectivity.getActiveNetworkInfo();
boolean isMobile = (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE);
boolean isRoaming = isMobile && TelephonyManager.getDefault().isNetworkRoaming();
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "network is mobile: " + isMobile);
- Log.v(Constants.TAG, "network is roaming: " + isRoaming);
+ if (Constants.LOGVV && isRoaming) {
+ Log.v(Constants.TAG, "network is roaming");
}
- return isMobile && isRoaming;
+ return isRoaming;
+ }
+
+ public Integer getMaxBytesOverMobile() {
+ return null;
}
}
diff --git a/src/com/android/providers/downloads/SystemFacade.java b/src/com/android/providers/downloads/SystemFacade.java
index e16e6a06..2addbf82 100644
--- a/src/com/android/providers/downloads/SystemFacade.java
+++ b/src/com/android/providers/downloads/SystemFacade.java
@@ -1,7 +1,6 @@
package com.android.providers.downloads;
-import java.util.BitSet;
interface SystemFacade {
/**
@@ -10,12 +9,19 @@ interface SystemFacade {
public long currentTimeMillis();
/**
- * @return Network types (as in ConnectivityManager.TYPE_*) of all connected networks.
+ * @return Network type (as in ConnectivityManager.TYPE_*) of currently active network, or null
+ * if there's no active connection.
*/
- public BitSet getConnectedNetworkTypes();
+ public Integer getActiveNetworkType();
/**
* @see android.telephony.TelephonyManager#isNetworkRoaming
*/
public boolean isNetworkRoaming();
+
+ /**
+ * @return maximum size, in bytes, of downloads that may go over a mobile connection; or null if
+ * there's no limit
+ */
+ public Integer getMaxBytesOverMobile();
}