Visible downloads should run while blocked/dozing.
Jeff Sharkey [Thu, 28 Apr 2016 21:33:38 +0000 (15:33 -0600)]
Downloads with visible notifications should behave as if the
requesting app was running a foreground service.  The easiest way
to implement this for now is to ignore any BLOCKED network status
and use the new setWillBeForeground() API so job scheduling ignores
any active blocked/dozing status.

Bug: 26571724
Change-Id: I8ea2b2a7cdb5f469adc11b4d897ff55bd8a9db9a

src/com/android/providers/downloads/DownloadInfo.java
src/com/android/providers/downloads/DownloadThread.java
src/com/android/providers/downloads/Helpers.java
src/com/android/providers/downloads/RealSystemFacade.java
src/com/android/providers/downloads/SystemFacade.java
tests/src/com/android/providers/downloads/FakeSystemFacade.java

index c94dd6c..8996ede 100644 (file)
@@ -16,6 +16,9 @@
 
 package com.android.providers.downloads;
 
+import static android.provider.Downloads.Impl.VISIBILITY_VISIBLE;
+import static android.provider.Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED;
+
 import static com.android.providers.downloads.Constants.TAG;
 
 import android.app.DownloadManager;
@@ -247,6 +250,19 @@ public class DownloadInfo {
     }
 
     /**
+     * Return if this download is visible to the user while running.
+     */
+    public boolean isVisible() {
+        switch (mVisibility) {
+            case VISIBILITY_VISIBLE:
+            case VISIBILITY_VISIBLE_NOTIFY_COMPLETED:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
      * Add random fuzz to the given delay so it's anywhere between 1-1.5x the
      * requested delay.
      */
index c559367..3bcde17 100644 (file)
@@ -221,6 +221,7 @@ public class DownloadThread extends Thread {
     private long mLastUpdateBytes = 0;
     private long mLastUpdateTime = 0;
 
+    private boolean mIgnoreBlocked;
     private Network mNetwork;
 
     private int mNetworkType = ConnectivityManager.TYPE_NONE;
@@ -269,10 +270,15 @@ public class DownloadThread extends Thread {
             mInfoDelta.mStatus = STATUS_RUNNING;
             mInfoDelta.writeToDatabase();
 
+            // If we're showing a foreground notification for the requesting
+            // app, the download isn't affected by the blocked status of the
+            // requesting app
+            mIgnoreBlocked = mInfo.isVisible();
+
             // Use the caller's default network to make this connection, since
             // they might be subject to restrictions that we shouldn't let them
-            // circumvent.
-            mNetwork = mSystemFacade.getActiveNetwork(mInfo.mUid);
+            // circumvent
+            mNetwork = mSystemFacade.getActiveNetwork(mInfo.mUid, mIgnoreBlocked);
             if (mNetwork == null) {
                 throw new StopRequestException(STATUS_WAITING_FOR_NETWORK,
                         "No network associated with requesting UID");
@@ -280,7 +286,8 @@ public class DownloadThread extends Thread {
 
             // Remember which network this download started on; used to
             // determine if errors were due to network changes.
-            final NetworkInfo info = mSystemFacade.getNetworkInfo(mNetwork);
+            final NetworkInfo info = mSystemFacade.getNetworkInfo(mNetwork, mInfo.mUid,
+                    mIgnoreBlocked);
             if (info != null) {
                 mNetworkType = info.getType();
             }
@@ -323,7 +330,8 @@ public class DownloadThread extends Thread {
                 }
 
                 if (mInfoDelta.mNumFailed < Constants.MAX_RETRIES) {
-                    final NetworkInfo info = mSystemFacade.getNetworkInfo(mNetwork);
+                    final NetworkInfo info = mSystemFacade.getNetworkInfo(mNetwork, mInfo.mUid,
+                            mIgnoreBlocked);
                     if (info != null && info.getType() == mNetworkType && info.isConnected()) {
                         // Underlying network is still intact, use normal backoff
                         mInfoDelta.mStatus = STATUS_WAITING_TO_RETRY;
@@ -707,7 +715,8 @@ public class DownloadThread extends Thread {
                 .getRequiredNetworkType(mInfoDelta.mTotalBytes) != JobInfo.NETWORK_TYPE_UNMETERED;
         final boolean allowRoaming = mInfo.isRoamingAllowed();
 
-        final NetworkInfo info = mSystemFacade.getNetworkInfo(mNetwork);
+        final NetworkInfo info = mSystemFacade.getNetworkInfo(mNetwork, mInfo.mUid,
+                mIgnoreBlocked);
         if (info == null || !info.isConnected()) {
             throw new StopRequestException(STATUS_WAITING_FOR_NETWORK, "Network is disconnected");
         }
@@ -870,7 +879,9 @@ public class DownloadThread extends Thread {
         @Override
         public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) {
             // caller is NPMS, since we only register with them
-            mPolicyDirty = true;
+            if (uid == mInfo.mUid) {
+                mPolicyDirty = true;
+            }
         }
     };
 
index b073745..d43e102 100644 (file)
@@ -22,8 +22,6 @@ import static android.os.Environment.buildExternalStorageAppMediaDirs;
 import static android.os.Environment.buildExternalStorageAppObbDirs;
 import static android.provider.Downloads.Impl.FLAG_REQUIRES_CHARGING;
 import static android.provider.Downloads.Impl.FLAG_REQUIRES_DEVICE_IDLE;
-import static android.provider.Downloads.Impl.VISIBILITY_VISIBLE;
-import static android.provider.Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED;
 
 import static com.android.providers.downloads.Constants.TAG;
 
@@ -138,12 +136,9 @@ public class Helpers {
 
         // When this download will show a notification, run with a higher
         // priority, since it's effectively a foreground service
-        switch (info.mVisibility) {
-            case VISIBILITY_VISIBLE:
-            case VISIBILITY_VISIBLE_NOTIFY_COMPLETED:
-                // TODO: force app out of doze, since they're showing a notification
-                builder.setPriority(JobInfo.PRIORITY_FOREGROUND_APP);
-                break;
+        if (info.isVisible()) {
+            builder.setPriority(JobInfo.PRIORITY_FOREGROUND_APP);
+            builder.setFlags(JobInfo.FLAG_WILL_BE_FOREGROUND);
         }
 
         // We might have a backoff constraint due to errors
index da4e01e..2203eef 100644 (file)
@@ -42,15 +42,15 @@ class RealSystemFacade implements SystemFacade {
     }
 
     @Override
-    public Network getActiveNetwork(int uid) {
+    public Network getActiveNetwork(int uid, boolean ignoreBlocked) {
         return mContext.getSystemService(ConnectivityManager.class)
-                .getActiveNetworkForUid(uid);
+                .getActiveNetworkForUid(uid, ignoreBlocked);
     }
 
     @Override
-    public NetworkInfo getNetworkInfo(Network network) {
+    public NetworkInfo getNetworkInfo(Network network, int uid, boolean ignoreBlocked) {
         return mContext.getSystemService(ConnectivityManager.class)
-                .getNetworkInfo(network);
+                .getNetworkInfoForUid(network, uid, ignoreBlocked);
     }
 
     @Override
index e7852e9..5f020b1 100644 (file)
@@ -27,9 +27,9 @@ interface SystemFacade {
      */
     public long currentTimeMillis();
 
-    public Network getActiveNetwork(int uid);
+    public Network getActiveNetwork(int uid, boolean ignoreBlocked);
 
-    public NetworkInfo getNetworkInfo(Network network);
+    public NetworkInfo getNetworkInfo(Network network, int uid, boolean ignoreBlocked);
 
     /**
      * @return maximum size, in bytes, of downloads that may go over a mobile connection; or null if
index eaf5e43..3b9a83b 100644 (file)
@@ -55,7 +55,7 @@ public class FakeSystemFacade implements SystemFacade {
     }
 
     @Override
-    public Network getActiveNetwork(int uid) {
+    public Network getActiveNetwork(int uid, boolean ignoreBlocked) {
         if (mActiveNetworkType == null) {
             return null;
         } else {
@@ -75,7 +75,7 @@ public class FakeSystemFacade implements SystemFacade {
     }
 
     @Override
-    public NetworkInfo getNetworkInfo(Network network) {
+    public NetworkInfo getNetworkInfo(Network network, int uid, boolean ignoreBlocked) {
         if (mActiveNetworkType == null) {
             return null;
         } else {