Index: chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java |
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..45d34c3dacf2ad7fda79fb735cddcbd6718c9192 |
--- /dev/null |
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java |
@@ -0,0 +1,520 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.chrome.browser.download; |
+ |
+import android.app.DownloadManager; |
+import android.content.Context; |
+import android.os.Handler; |
+import android.os.HandlerThread; |
+import android.test.InstrumentationTestCase; |
+import android.test.suitebuilder.annotation.MediumTest; |
+import android.test.suitebuilder.annotation.SmallTest; |
+import android.util.Log; |
+import android.util.Pair; |
+ |
+import org.chromium.base.test.util.AdvancedMockContext; |
+import org.chromium.base.test.util.Feature; |
+import org.chromium.base.test.util.UrlUtils; |
+import org.chromium.chrome.browser.download.DownloadManagerServiceTest.MockDownloadNotifier.MethodID; |
+import org.chromium.chrome.test.util.TestHttpServerClient; |
+import org.chromium.content.browser.DownloadInfo; |
+import org.chromium.content.browser.DownloadInfo.Builder; |
+import org.chromium.content.browser.test.util.Criteria; |
+import org.chromium.content.browser.test.util.CriteriaHelper; |
+ |
+import java.util.Collections; |
+import java.util.HashSet; |
+import java.util.Queue; |
+import java.util.Random; |
+import java.util.Set; |
+import java.util.concurrent.ConcurrentLinkedQueue; |
+ |
+/** |
+ * Test for DownloadManagerService. |
+ */ |
+public class DownloadManagerServiceTest extends InstrumentationTestCase { |
+ private static final int UPDATE_DELAY_FOR_TEST = 1; |
+ private static final int DELAY_BETWEEN_CALLS = 10; |
+ private static final int LONG_UPDATE_DELAY_FOR_TEST = 500; |
+ private static final String INSTALL_NOTIFY_URI = "http://test/test"; |
+ private final Random mRandom = new Random(); |
+ |
+ /** |
+ * The MockDownloadNotifier. Currently there is no support for creating mock objects this is a |
+ * simple mock object that provides testing support for checking a sequence of calls. |
+ */ |
+ static class MockDownloadNotifier |
+ implements org.chromium.chrome.browser.download.DownloadNotifier { |
+ /** |
+ * The Ids of different methods in this mock object. |
+ */ |
+ static enum MethodID { |
+ DOWNLOAD_SUCCESSFUL, |
+ DOWNLOAD_FAILED, |
+ DOWNLOAD_PROGRESS, |
+ CANCEL_DOWNLOAD_ID |
+ } |
+ |
+ private final Queue<Pair<MethodID, Object>> mExpectedCalls = |
+ new ConcurrentLinkedQueue<Pair<MethodID, Object>>(); |
+ |
+ public MockDownloadNotifier expect(MethodID method, Object param) { |
+ mExpectedCalls.clear(); |
+ mExpectedCalls.add(getMethodSignature(method, param)); |
+ return this; |
+ } |
+ |
+ public void waitTillExpectedCallsComplete() { |
+ boolean result = false; |
+ try { |
+ result = CriteriaHelper.pollForCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return mExpectedCalls.isEmpty(); |
+ } |
+ }); |
+ } catch (InterruptedException e) { |
+ fail("Failed while waiting for all calls to complete." + e); |
+ } |
+ assertTrue("Failed while waiting for all calls to complete.", result); |
+ } |
+ |
+ public MockDownloadNotifier andThen(MethodID method, Object param) { |
+ mExpectedCalls.add(getMethodSignature(method, param)); |
+ return this; |
+ } |
+ |
+ static Pair<MethodID, Object> getMethodSignature(MethodID methodId, Object param) { |
+ return new Pair<MethodID, Object>(methodId, param); |
+ } |
+ |
+ void assertCorrectExpectedCall(MethodID methodId, Object param) { |
+ Log.w("MockDownloadNotifier", "Called: " + methodId); |
+ assertFalse("Unexpected call:, no call expected, but got: " + methodId, |
+ mExpectedCalls.isEmpty()); |
+ Pair<MethodID, Object> actual = getMethodSignature(methodId, param); |
+ Pair<MethodID, Object> expected = mExpectedCalls.poll(); |
+ assertEquals("Unexpected call", expected.first, actual.first); |
+ assertTrue("Incorrect arguments", MatchHelper.macthes(expected.second, actual.second)); |
+ } |
+ |
+ @Override |
+ public void notifyDownloadSuccessful(DownloadInfo downloadInfo) { |
+ assertCorrectExpectedCall(MethodID.DOWNLOAD_SUCCESSFUL, downloadInfo); |
+ } |
+ |
+ @Override |
+ public void notifyDownloadFailed(DownloadInfo downloadInfo) { |
+ assertCorrectExpectedCall(MethodID.DOWNLOAD_FAILED, downloadInfo); |
+ |
+ } |
+ |
+ @Override |
+ public void notifyDownloadProgress(DownloadInfo downloadInfo, long startTime) { |
+ assertCorrectExpectedCall(MethodID.DOWNLOAD_PROGRESS, downloadInfo); |
+ } |
+ |
+ @Override |
+ public void cancelNotification(int downloadId) { |
+ assertCorrectExpectedCall(MethodID.CANCEL_DOWNLOAD_ID, downloadId); |
+ } |
+ |
+ } |
+ |
+ /** |
+ * A set that each object can be matched ^only^ once. Once matched, the object |
+ * will be removed from the set. This is useful to write expectations |
+ * for a sequence of calls where order of calls is not defined. Client can |
+ * do the following. OneTimeMatchSet matchSet = new OneTimeMatchSet(possibleValue1, |
+ * possibleValue2, possibleValue3); mockObject.expect(method1, matchSet).andThen(method1, |
+ * matchSet).andThen(method3, matchSet); .... Some work. |
+ * mockObject.waitTillExpectedCallsComplete(); assertTrue(matchSet.mMatches.empty()); |
+ */ |
+ private static class OneTimeMatchSet { |
+ private final HashSet<Object> mMatches; |
+ |
+ OneTimeMatchSet(Object... params) { |
+ mMatches = new HashSet<Object>(); |
+ Collections.addAll(mMatches, params); |
+ } |
+ |
+ public boolean matches(Object obj) { |
+ if (obj == null) return false; |
+ if (this == obj) return true; |
+ if (!mMatches.contains(obj)) return false; |
+ |
+ // Remove the object since it has been matched. |
+ mMatches.remove(obj); |
+ return true; |
+ } |
+ } |
+ |
+ /** |
+ * Class that helps matching 2 objects with either of them may be a OneTimeMatchSet object. |
+ */ |
+ private static class MatchHelper { |
+ public static boolean macthes(Object obj1, Object obj2) { |
+ if (obj1 == null) return obj2 == null; |
+ if (obj1.equals(obj2)) return true; |
+ if (obj1 instanceof OneTimeMatchSet) { |
+ return ((OneTimeMatchSet) obj1).matches(obj2); |
+ } else if (obj2 instanceof OneTimeMatchSet) { |
+ return ((OneTimeMatchSet) obj2).matches(obj1); |
+ } |
+ return false; |
+ } |
+ } |
+ |
+ static class MockOMADownloadHandler extends OMADownloadHandler { |
+ protected boolean mSuccess; |
+ protected String mNofityURI; |
+ protected DownloadInfo mDownloadInfo; |
+ protected long mDownloadId; |
+ |
+ MockOMADownloadHandler(Context context) { |
+ super(context); |
+ } |
+ |
+ protected void setDownloadId(long downloadId) { |
+ mDownloadId = downloadId; |
+ } |
+ |
+ @Override |
+ public void onDownloadCompleted(DownloadInfo downloadInfo, String notifyURI) { |
+ mSuccess = true; |
+ mNofityURI = notifyURI; |
+ } |
+ |
+ @Override |
+ public boolean isPendingOMADownload(long downloadId) { |
+ return mDownloadId == downloadId; |
+ } |
+ |
+ @Override |
+ public DownloadInfo updateDownloadInfo(DownloadInfo downloadInfo, long newDownloadId) { |
+ mDownloadInfo = downloadInfo; |
+ mDownloadId = newDownloadId; |
+ mDownloadInfo = DownloadInfo.Builder.fromDownloadInfo(downloadInfo) |
+ .setDownloadId((int) newDownloadId) |
+ .build(); |
+ return mDownloadInfo; |
+ } |
+ |
+ @Override |
+ public String getInstallNotifyInfo(long downloadId) { |
+ return INSTALL_NOTIFY_URI; |
+ } |
+ } |
+ |
+ private static class DownloadManagerServiceForTest extends DownloadManagerService { |
+ public DownloadManagerServiceForTest(Context context, MockDownloadNotifier mockNotifier, |
+ long updateDelayInMillis) { |
+ super(context, mockNotifier, getTestHandler(), updateDelayInMillis); |
+ } |
+ } |
+ |
+ private static Handler getTestHandler() { |
+ HandlerThread handlerThread = new HandlerThread("handlerThread"); |
+ handlerThread.start(); |
+ return new Handler(handlerThread.getLooper()); |
+ } |
+ |
+ private DownloadInfo getDownloadInfo() { |
+ return new Builder().setContentLength(100) |
+ .setDownloadId(mRandom.nextInt(1000)) |
+ .setHasDownloadId(true) |
+ .build(); |
+ } |
+ |
+ private Context getTestContext() { |
+ return new AdvancedMockContext(getInstrumentation().getTargetContext()); |
+ } |
+ |
+ @MediumTest |
+ @Feature({"Downloads"}) |
+ public void testDownloadProgressIsCalled() throws InterruptedException { |
+ MockDownloadNotifier notifier = new MockDownloadNotifier(); |
+ DownloadManagerServiceForTest dService = new DownloadManagerServiceForTest( |
+ getTestContext(), notifier, UPDATE_DELAY_FOR_TEST); |
+ DownloadInfo downloadInfo = getDownloadInfo(); |
+ |
+ notifier.expect(MethodID.DOWNLOAD_PROGRESS, downloadInfo); |
+ dService.onDownloadUpdated(downloadInfo); |
+ notifier.waitTillExpectedCallsComplete(); |
+ |
+ // Now post multiple download updated calls and make sure all are received. |
+ DownloadInfo update1 = Builder.fromDownloadInfo(downloadInfo) |
+ .setPercentCompleted(10).build(); |
+ DownloadInfo update2 = Builder.fromDownloadInfo(downloadInfo) |
+ .setPercentCompleted(30).build(); |
+ DownloadInfo update3 = Builder.fromDownloadInfo(downloadInfo) |
+ .setPercentCompleted(30).build(); |
+ notifier.expect(MethodID.DOWNLOAD_PROGRESS, update1) |
+ .andThen(MethodID.DOWNLOAD_PROGRESS, update2) |
+ .andThen(MethodID.DOWNLOAD_PROGRESS, update3); |
+ |
+ dService.onDownloadUpdated(update1); |
+ Thread.sleep(DELAY_BETWEEN_CALLS); |
+ dService.onDownloadUpdated(update2); |
+ Thread.sleep(DELAY_BETWEEN_CALLS); |
+ dService.onDownloadUpdated(update3); |
+ notifier.waitTillExpectedCallsComplete(); |
+ } |
+ |
+ @MediumTest |
+ @Feature({"Downloads"}) |
+ public void testOnlyOneProgressForFastUpdates() throws InterruptedException { |
+ MockDownloadNotifier notifier = new MockDownloadNotifier(); |
+ DownloadManagerServiceForTest dService = new DownloadManagerServiceForTest( |
+ getTestContext(), notifier, LONG_UPDATE_DELAY_FOR_TEST); |
+ DownloadInfo downloadInfo = getDownloadInfo(); |
+ DownloadInfo update1 = Builder.fromDownloadInfo(downloadInfo) |
+ .setPercentCompleted(10).build(); |
+ DownloadInfo update2 = Builder.fromDownloadInfo(downloadInfo) |
+ .setPercentCompleted(30).build(); |
+ DownloadInfo update3 = Builder.fromDownloadInfo(downloadInfo) |
+ .setPercentCompleted(30).build(); |
+ |
+ // Should only get one update call, the last update. |
+ notifier.expect(MethodID.DOWNLOAD_PROGRESS, update3); |
+ dService.onDownloadUpdated(update1); |
+ Thread.sleep(DELAY_BETWEEN_CALLS); |
+ dService.onDownloadUpdated(update2); |
+ Thread.sleep(DELAY_BETWEEN_CALLS); |
+ dService.onDownloadUpdated(update3); |
+ Thread.sleep(DELAY_BETWEEN_CALLS); |
+ notifier.waitTillExpectedCallsComplete(); |
+ } |
+ |
+ @MediumTest |
+ @Feature({"Downloads"}) |
+ public void testDownloadCompletedIsCalled() throws InterruptedException { |
+ MockDownloadNotifier notifier = new MockDownloadNotifier(); |
+ DownloadManagerServiceForTest dService = new DownloadManagerServiceForTest( |
+ getTestContext(), notifier, UPDATE_DELAY_FOR_TEST); |
+ // Try calling download completed directly. |
+ DownloadInfo successful = Builder.fromDownloadInfo(getDownloadInfo()) |
+ .setIsSuccessful(true).build(); |
+ |
+ // First the progress notification should be removed and then |
+ // a new successful notification should be added. |
+ notifier.expect(MethodID.CANCEL_DOWNLOAD_ID, successful.getDownloadId()) |
+ .andThen(MethodID.DOWNLOAD_SUCCESSFUL, successful); |
+ |
+ dService.onDownloadCompleted(successful); |
+ notifier.waitTillExpectedCallsComplete(); |
+ |
+ // Now check that a cancel works. |
+ DownloadInfo failure = Builder.fromDownloadInfo(getDownloadInfo()) |
+ .setIsSuccessful(false).build(); |
+ notifier.expect(MethodID.CANCEL_DOWNLOAD_ID, failure.getDownloadId()) |
+ .andThen(MethodID.DOWNLOAD_FAILED, failure); |
+ |
+ // Now check that a successful notification appears after a download progress. |
+ DownloadInfo progress = getDownloadInfo(); |
+ successful = Builder.fromDownloadInfo(progress) |
+ .setIsSuccessful(true).build(); |
+ notifier.expect(MethodID.DOWNLOAD_PROGRESS, progress) |
+ .andThen(MethodID.CANCEL_DOWNLOAD_ID, progress.getDownloadId()) |
+ .andThen(MethodID.DOWNLOAD_SUCCESSFUL, successful); |
+ dService.onDownloadUpdated(progress); |
+ Thread.sleep(DELAY_BETWEEN_CALLS); |
+ dService.onDownloadCompleted(successful); |
+ notifier.waitTillExpectedCallsComplete(); |
+ } |
+ |
+ @MediumTest |
+ @Feature({"Downloads"}) |
+ public void testMultipleDownloadProgress() { |
+ MockDownloadNotifier notifier = new MockDownloadNotifier(); |
+ DownloadManagerServiceForTest dService = new DownloadManagerServiceForTest( |
+ getTestContext(), notifier, UPDATE_DELAY_FOR_TEST); |
+ |
+ DownloadInfo download1 = getDownloadInfo(); |
+ DownloadInfo download2 = getDownloadInfo(); |
+ DownloadInfo download3 = getDownloadInfo(); |
+ OneTimeMatchSet matchSet = new OneTimeMatchSet(download1, download2, download3); |
+ notifier.expect(MethodID.DOWNLOAD_PROGRESS, matchSet) |
+ .andThen(MethodID.DOWNLOAD_PROGRESS, matchSet) |
+ .andThen(MethodID.DOWNLOAD_PROGRESS, matchSet); |
+ dService.onDownloadUpdated(download1); |
+ dService.onDownloadUpdated(download2); |
+ dService.onDownloadUpdated(download3); |
+ |
+ notifier.waitTillExpectedCallsComplete(); |
+ assertTrue("All downloads should be updated.", matchSet.mMatches.isEmpty()); |
+ } |
+ |
+ @MediumTest |
+ @Feature({"Downloads"}) |
+ public void testInProgressDownloadsAreCancelled() { |
+ MockDownloadNotifier notifier = new MockDownloadNotifier(); |
+ DownloadManagerServiceForTest dService = new DownloadManagerServiceForTest( |
+ getTestContext(), notifier, UPDATE_DELAY_FOR_TEST); |
+ |
+ DownloadInfo download1 = getDownloadInfo(); |
+ DownloadInfo download2 = getDownloadInfo(); |
+ DownloadInfo download3 = getDownloadInfo(); |
+ OneTimeMatchSet matchSet = new OneTimeMatchSet(download1, download2, download3); |
+ notifier.expect(MethodID.DOWNLOAD_PROGRESS, matchSet) |
+ .andThen(MethodID.DOWNLOAD_PROGRESS, matchSet) |
+ .andThen(MethodID.DOWNLOAD_PROGRESS, matchSet); |
+ |
+ dService.onDownloadUpdated(download1); |
+ dService.onDownloadUpdated(download2); |
+ dService.onDownloadUpdated(download3); |
+ |
+ notifier.waitTillExpectedCallsComplete(); |
+ assertTrue("All downloads should be updated.", matchSet.mMatches.isEmpty()); |
+ |
+ // Check if notifications are removed when clearPendingNotifications is called. |
+ matchSet = new OneTimeMatchSet(download1.getDownloadId(), |
+ download2.getDownloadId(), download3.getDownloadId()); |
+ notifier.expect(MethodID.CANCEL_DOWNLOAD_ID, matchSet) |
+ .andThen(MethodID.CANCEL_DOWNLOAD_ID, matchSet) |
+ .andThen(MethodID.CANCEL_DOWNLOAD_ID, matchSet); |
+ |
+ dService.clearPendingDownloadNotifications(); |
+ notifier.waitTillExpectedCallsComplete(); |
+ assertTrue("All downloads should be removed.", matchSet.mMatches.isEmpty()); |
+ } |
+ |
+ /** |
+ * Test to make sure {@link DownloadManagerService#clearPendingDownloadNotifications} |
+ * will clear the OMA notifications and pass the notification URI to {@link OMADownloadHandler}. |
+ */ |
+ @MediumTest |
+ @Feature({"Downloads"}) |
+ public void testClearPendingOMADownloads() throws InterruptedException { |
+ DownloadManager manager = |
+ (DownloadManager) getTestContext().getSystemService(Context.DOWNLOAD_SERVICE); |
+ long downloadId = manager.addCompletedDownload( |
+ "test", "test", false, "text/html", |
+ UrlUtils.getTestFilePath("clank/download/download.txt"), 4, true); |
+ MockDownloadNotifier notifier = new MockDownloadNotifier(); |
+ DownloadManagerServiceForTest dService = new DownloadManagerServiceForTest( |
+ getTestContext(), notifier, UPDATE_DELAY_FOR_TEST); |
+ final MockOMADownloadHandler handler = new MockOMADownloadHandler(getTestContext()); |
+ dService.setOMADownloadHandler(handler); |
+ dService.addOMADownloadToSharedPrefs(String.valueOf(downloadId) + "," + INSTALL_NOTIFY_URI); |
+ dService.clearPendingDownloadNotifications(); |
+ boolean result = CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return handler.mSuccess; |
+ } |
+ }); |
+ assertTrue(result); |
+ assertEquals(handler.mNofityURI, "http://test/test"); |
+ manager.remove(downloadId); |
+ } |
+ |
+ /** |
+ * Test that calling {@link DownloadManagerService#enqueueDownloadManagerRequest} for an |
+ * OMA download will enqueue a new DownloadManager request and insert an entry into the |
+ * SharedPrefs. |
+ */ |
+ @MediumTest |
+ @Feature({"Downloads"}) |
+ public void testEnqueueOMADownloads() throws InterruptedException { |
+ DownloadInfo info = new DownloadInfo.Builder() |
+ .setDownloadId(0) |
+ .setMimeType(OMADownloadHandler.OMA_DRM_MESSAGE_MIME) |
+ .setFileName("test.gzip") |
+ .setUrl(TestHttpServerClient.getUrl("clank/test/data/android/download/test.gzip")) |
+ .build(); |
+ MockDownloadNotifier notifier = new MockDownloadNotifier(); |
+ DownloadManagerServiceForTest dService = new DownloadManagerServiceForTest( |
+ getTestContext(), notifier, UPDATE_DELAY_FOR_TEST); |
+ final MockOMADownloadHandler handler = new MockOMADownloadHandler(getTestContext()); |
+ dService.setOMADownloadHandler(handler); |
+ handler.setDownloadId(0); |
+ dService.enqueueDownloadManagerRequest(info, true); |
+ boolean result = CriteriaHelper.pollForUIThreadCriteria(new Criteria() { |
+ @Override |
+ public boolean isSatisfied() { |
+ return handler.mDownloadId != 0; |
+ } |
+ }); |
+ assertTrue(result); |
+ handler.mDownloadId = handler.mDownloadInfo.getDownloadId(); |
+ Set<String> downloads = dService.getStoredDownloadInfo( |
+ DownloadManagerService.PENDING_OMA_DOWNLOADS); |
+ assertEquals(1, downloads.size()); |
+ DownloadManagerService.OMAEntry entry = DownloadManagerService.OMAEntry.parseOMAEntry( |
+ (String) (downloads.toArray()[0])); |
+ assertEquals(entry.mDownloadId, handler.mDownloadId); |
+ assertEquals(entry.mInstallNotifyURI, INSTALL_NOTIFY_URI); |
+ DownloadManager manager = |
+ (DownloadManager) getTestContext().getSystemService(Context.DOWNLOAD_SERVICE); |
+ manager.remove(handler.mDownloadId); |
+ } |
+ |
+ /** |
+ * Test to make sure {@link DownloadManagerService#shouldOpenAfterDownload} |
+ * returns the right result for varying MIME types and Content-Dispositions. |
+ */ |
+ @SmallTest |
+ @Feature({"ChromeDownloadListener"}) |
+ public void testShouldOpenAfterDownload() { |
+ // Should not open any download type MIME types. |
+ assertFalse( |
+ DownloadManagerService.shouldOpenAfterDownload(new DownloadInfo.Builder() |
+ .setMimeType("application/download") |
+ .setHasUserGesture(true) |
+ .build())); |
+ assertFalse( |
+ DownloadManagerService.shouldOpenAfterDownload(new DownloadInfo.Builder() |
+ .setMimeType("application/x-download") |
+ .setHasUserGesture(true) |
+ .build())); |
+ assertFalse( |
+ DownloadManagerService.shouldOpenAfterDownload(new DownloadInfo.Builder() |
+ .setMimeType("application/octet-stream") |
+ .setHasUserGesture(true) |
+ .build())); |
+ |
+ // Should open PDFs. |
+ assertTrue( |
+ DownloadManagerService.shouldOpenAfterDownload(new DownloadInfo.Builder() |
+ .setMimeType("application/pdf") |
+ .setHasUserGesture(true) |
+ .build())); |
+ assertTrue( |
+ DownloadManagerService.shouldOpenAfterDownload(new DownloadInfo.Builder() |
+ .setContentDisposition("filename=test.pdf") |
+ .setMimeType("application/pdf") |
+ .setHasUserGesture(true) |
+ .build())); |
+ |
+ // Require user gesture. |
+ assertFalse( |
+ DownloadManagerService.shouldOpenAfterDownload(new DownloadInfo.Builder() |
+ .setMimeType("application/pdf") |
+ .setHasUserGesture(false) |
+ .build())); |
+ assertFalse( |
+ DownloadManagerService.shouldOpenAfterDownload(new DownloadInfo.Builder() |
+ .setContentDisposition("filename=test.pdf") |
+ .setMimeType("application/pdf") |
+ .setHasUserGesture(false) |
+ .build())); |
+ |
+ // But should not open any PDFs with Content-Disposition: attachment. |
+ assertFalse( |
+ DownloadManagerService.shouldOpenAfterDownload(new DownloadInfo.Builder() |
+ .setContentDisposition("attachment") |
+ .setMimeType("application/pdf") |
+ .setHasUserGesture(true) |
+ .build())); |
+ assertFalse( |
+ DownloadManagerService.shouldOpenAfterDownload(new DownloadInfo.Builder() |
+ .setContentDisposition("attachment; filename=test.pdf") |
+ .setMimeType("application/pdf") |
+ .setHasUserGesture(true) |
+ .build())); |
+ } |
+ |
+} |