Commit d20d0c26 authored by John Abd-El-Malek's avatar John Abd-El-Malek Committed by Commit Bot

Add system notification UI for downloads in WebLayer.

This closely matches Android Download Manager's UI with the exception of skipping the "% downloaded" part since it seemed redundant with the progress bar. The embedder can disable the UI if they choose.

The few UI strings need to be translated. The button strings can be reused from Chrome, but we need to figure out what the rest of the text should say and add translations if they're not shared.

Bug: 1025603
Change-Id: I61ba3b821c417de13191a67a85487b61b5f9c86f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2002980Reviewed-by: default avatarBo <boliu@chromium.org>
Reviewed-by: default avatarClark DuVall <cduvall@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Commit-Queue: John Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#734589}
parent 2d23c49b
...@@ -77,6 +77,7 @@ public class DownloadCallbackTest { ...@@ -77,6 +77,7 @@ public class DownloadCallbackTest {
@Override @Override
public void onDownloadStarted(Download download) { public void onDownloadStarted(Download download) {
mSeenStarted = true; mSeenStarted = true;
download.disableNotification();
} }
@Override @Override
...@@ -85,6 +86,7 @@ public class DownloadCallbackTest { ...@@ -85,6 +86,7 @@ public class DownloadCallbackTest {
mLocation = download.getLocation().toString(); mLocation = download.getLocation().toString();
mState = download.getState(); mState = download.getState();
mError = download.getError(); mError = download.getError();
mMimetype = download.getMimeType();
} }
@Override @Override
...@@ -213,5 +215,6 @@ public class DownloadCallbackTest { ...@@ -213,5 +215,6 @@ public class DownloadCallbackTest {
"org.chromium.weblayer.shell/cache/weblayer/Downloads/")); "org.chromium.weblayer.shell/cache/weblayer/Downloads/"));
Assert.assertEquals(DownloadState.COMPLETE, mCallback.mState); Assert.assertEquals(DownloadState.COMPLETE, mCallback.mState);
Assert.assertEquals(DownloadError.NO_ERROR, mCallback.mError); Assert.assertEquals(DownloadError.NO_ERROR, mCallback.mError);
Assert.assertEquals("text/html", mCallback.mMimetype);
} }
} }
...@@ -80,6 +80,7 @@ class DownloadBrowserTest : public WebLayerBrowserTest, ...@@ -80,6 +80,7 @@ class DownloadBrowserTest : public WebLayerBrowserTest,
base::FilePath download_location() { return download_location_; } base::FilePath download_location() { return download_location_; }
int64_t total_bytes() { return total_bytes_; } int64_t total_bytes() { return total_bytes_; }
DownloadError download_state() { return download_state_; } DownloadError download_state() { return download_state_; }
std::string mime_type() { return mime_type_; }
int completed_count() { return completed_count_; } int completed_count() { return completed_count_; }
int failed_count() { return failed_count_; } int failed_count() { return failed_count_; }
int download_dropped_count() { return download_dropped_count_; } int download_dropped_count() { return download_dropped_count_; }
...@@ -118,6 +119,7 @@ class DownloadBrowserTest : public WebLayerBrowserTest, ...@@ -118,6 +119,7 @@ class DownloadBrowserTest : public WebLayerBrowserTest,
download_location_ = download->GetLocation(); download_location_ = download->GetLocation();
total_bytes_ = download->GetTotalBytes(); total_bytes_ = download->GetTotalBytes();
download_state_ = download->GetError(); download_state_ = download->GetError();
mime_type_ = download->GetMimeType();
CHECK_EQ(download->GetReceivedBytes(), total_bytes_); CHECK_EQ(download->GetReceivedBytes(), total_bytes_);
CHECK_EQ(download->GetState(), DownloadState::kComplete); CHECK_EQ(download->GetState(), DownloadState::kComplete);
completed_run_loop_->Quit(); completed_run_loop_->Quit();
...@@ -142,6 +144,7 @@ class DownloadBrowserTest : public WebLayerBrowserTest, ...@@ -142,6 +144,7 @@ class DownloadBrowserTest : public WebLayerBrowserTest,
base::FilePath download_location_; base::FilePath download_location_;
int64_t total_bytes_ = 0; int64_t total_bytes_ = 0;
DownloadError download_state_ = DownloadError::kNoError; DownloadError download_state_ = DownloadError::kNoError;
std::string mime_type_;
int completed_count_ = 0; int completed_count_ = 0;
int failed_count_ = 0; int failed_count_ = 0;
int download_dropped_count_ = 0; int download_dropped_count_ = 0;
...@@ -204,6 +207,7 @@ IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, Basic) { ...@@ -204,6 +207,7 @@ IN_PROC_BROWSER_TEST_F(DownloadBrowserTest, Basic) {
EXPECT_EQ(failed_count(), 0); EXPECT_EQ(failed_count(), 0);
EXPECT_EQ(download_dropped_count(), 0); EXPECT_EQ(download_dropped_count(), 0);
EXPECT_EQ(download_state(), DownloadError::kNoError); EXPECT_EQ(download_state(), DownloadError::kNoError);
EXPECT_EQ(mime_type(), "text/html");
// Check that the size on disk matches what's expected. // Check that the size on disk matches what's expected.
{ {
......
...@@ -54,6 +54,13 @@ base::android::ScopedJavaLocalRef<jstring> DownloadImpl::GetLocation( ...@@ -54,6 +54,13 @@ base::android::ScopedJavaLocalRef<jstring> DownloadImpl::GetLocation(
return base::android::ScopedJavaLocalRef<jstring>( return base::android::ScopedJavaLocalRef<jstring>(
base::android::ConvertUTF8ToJavaString(env, GetLocation().value())); base::android::ConvertUTF8ToJavaString(env, GetLocation().value()));
} }
base::android::ScopedJavaLocalRef<jstring> DownloadImpl::GetMimeTypeImpl(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj) {
return base::android::ScopedJavaLocalRef<jstring>(
base::android::ConvertUTF8ToJavaString(env, GetMimeType()));
}
#endif #endif
DownloadState DownloadImpl::GetState() { DownloadState DownloadImpl::GetState() {
...@@ -110,6 +117,10 @@ base::FilePath DownloadImpl::GetLocation() { ...@@ -110,6 +117,10 @@ base::FilePath DownloadImpl::GetLocation() {
return item_->GetTargetFilePath(); return item_->GetTargetFilePath();
} }
std::string DownloadImpl::GetMimeType() {
return item_->GetMimeType();
}
DownloadError DownloadImpl::GetError() { DownloadError DownloadImpl::GetError() {
auto reason = item_->GetLastReason(); auto reason = item_->GetLastReason();
if (reason == download::DOWNLOAD_INTERRUPT_REASON_NONE) if (reason == download::DOWNLOAD_INTERRUPT_REASON_NONE)
......
...@@ -57,6 +57,10 @@ class DownloadImpl : public Download, public base::SupportsUserData::Data { ...@@ -57,6 +57,10 @@ class DownloadImpl : public Download, public base::SupportsUserData::Data {
base::android::ScopedJavaLocalRef<jstring> GetLocation( base::android::ScopedJavaLocalRef<jstring> GetLocation(
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj); const base::android::JavaParamRef<jobject>& obj);
// Add Impl suffix to avoid compiler clash with the C++ interface method.
base::android::ScopedJavaLocalRef<jstring> GetMimeTypeImpl(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
int GetError(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj) { int GetError(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj) {
return static_cast<int>(GetError()); return static_cast<int>(GetError());
} }
...@@ -74,6 +78,7 @@ class DownloadImpl : public Download, public base::SupportsUserData::Data { ...@@ -74,6 +78,7 @@ class DownloadImpl : public Download, public base::SupportsUserData::Data {
void Resume() override; void Resume() override;
void Cancel() override; void Cancel() override;
base::FilePath GetLocation() override; base::FilePath GetLocation() override;
std::string GetMimeType() override;
DownloadError GetError() override; DownloadError GetError() override;
private: private:
......
...@@ -21,10 +21,12 @@ import org.chromium.weblayer_private.interfaces.ObjectWrapper; ...@@ -21,10 +21,12 @@ import org.chromium.weblayer_private.interfaces.ObjectWrapper;
@JNINamespace("weblayer") @JNINamespace("weblayer")
public final class DownloadCallbackProxy { public final class DownloadCallbackProxy {
private long mNativeDownloadCallbackProxy; private long mNativeDownloadCallbackProxy;
private BrowserImpl mBrowser;
private IDownloadCallbackClient mClient; private IDownloadCallbackClient mClient;
DownloadCallbackProxy(long tab, IDownloadCallbackClient client) { DownloadCallbackProxy(BrowserImpl browser, long tab, IDownloadCallbackClient client) {
assert client != null; assert client != null;
mBrowser = browser;
mClient = client; mClient = client;
mNativeDownloadCallbackProxy = mNativeDownloadCallbackProxy =
DownloadCallbackProxyJni.get().createDownloadCallbackProxy(this, tab); DownloadCallbackProxyJni.get().createDownloadCallbackProxy(this, tab);
...@@ -70,27 +72,31 @@ public final class DownloadCallbackProxy { ...@@ -70,27 +72,31 @@ public final class DownloadCallbackProxy {
@CalledByNative @CalledByNative
private DownloadImpl createDownload(long nativeDownloadImpl) { private DownloadImpl createDownload(long nativeDownloadImpl) {
return new DownloadImpl(mClient, nativeDownloadImpl); return new DownloadImpl(mBrowser, mClient, nativeDownloadImpl);
} }
@CalledByNative @CalledByNative
private void downloadStarted(DownloadImpl download) throws RemoteException { private void downloadStarted(DownloadImpl download) throws RemoteException {
mClient.downloadStarted(download.getClientDownload()); mClient.downloadStarted(download.getClientDownload());
download.downloadStarted();
} }
@CalledByNative @CalledByNative
private void downloadProgressChanged(DownloadImpl download) throws RemoteException { private void downloadProgressChanged(DownloadImpl download) throws RemoteException {
mClient.downloadProgressChanged(download.getClientDownload()); mClient.downloadProgressChanged(download.getClientDownload());
download.downloadProgressChanged();
} }
@CalledByNative @CalledByNative
private void downloadCompleted(DownloadImpl download) throws RemoteException { private void downloadCompleted(DownloadImpl download) throws RemoteException {
mClient.downloadCompleted(download.getClientDownload()); mClient.downloadCompleted(download.getClientDownload());
download.downloadCompleted();
} }
@CalledByNative @CalledByNative
private void downloadFailed(DownloadImpl download) throws RemoteException { private void downloadFailed(DownloadImpl download) throws RemoteException {
mClient.downloadFailed(download.getClientDownload()); mClient.downloadFailed(download.getClientDownload());
download.downloadFailed();
} }
@NativeMethods @NativeMethods
......
...@@ -220,7 +220,7 @@ public final class TabImpl extends ITab.Stub { ...@@ -220,7 +220,7 @@ public final class TabImpl extends ITab.Stub {
StrictModeWorkaround.apply(); StrictModeWorkaround.apply();
if (client != null) { if (client != null) {
if (mDownloadCallbackProxy == null) { if (mDownloadCallbackProxy == null) {
mDownloadCallbackProxy = new DownloadCallbackProxy(mNativeTab, client); mDownloadCallbackProxy = new DownloadCallbackProxy(mBrowser, mNativeTab, client);
} else { } else {
mDownloadCallbackProxy.setClient(client); mDownloadCallbackProxy.setClient(client);
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package org.chromium.weblayer_private; package org.chromium.weblayer_private;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.AssetManager; import android.content.res.AssetManager;
...@@ -255,6 +256,13 @@ public final class WebLayerImpl extends IWebLayer.Stub { ...@@ -255,6 +256,13 @@ public final class WebLayerImpl extends IWebLayer.Stub {
return CrashReporterControllerImpl.getInstance(); return CrashReporterControllerImpl.getInstance();
} }
@Override
public void onReceivedDownloadNotification(IObjectWrapper appContextWrapper, Intent intent) {
StrictModeWorkaround.apply();
Context context = ObjectWrapper.unwrap(appContextWrapper, Context.class);
DownloadImpl.forwardIntent(context, intent);
}
/** /**
* Creates a remote context. This should only be used for backwards compatibility when the * Creates a remote context. This should only be used for backwards compatibility when the
* client was not sending the remote context. * client was not sending the remote context.
......
...@@ -16,4 +16,6 @@ interface IDownload { ...@@ -16,4 +16,6 @@ interface IDownload {
void cancel() = 5; void cancel() = 5;
String getLocation() = 6; String getLocation() = 6;
int getError() = 7; int getError() = 7;
String getMimeType() = 8;
void disableNotification() = 9;
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
package org.chromium.weblayer_private.interfaces; package org.chromium.weblayer_private.interfaces;
import android.content.Intent;
import org.chromium.weblayer_private.interfaces.IClientDownload; import org.chromium.weblayer_private.interfaces.IClientDownload;
import org.chromium.weblayer_private.interfaces.IDownload; import org.chromium.weblayer_private.interfaces.IDownload;
import org.chromium.weblayer_private.interfaces.IObjectWrapper; import org.chromium.weblayer_private.interfaces.IObjectWrapper;
...@@ -19,4 +20,5 @@ interface IDownloadCallbackClient { ...@@ -19,4 +20,5 @@ interface IDownloadCallbackClient {
void downloadProgressChanged(IClientDownload download) = 4; void downloadProgressChanged(IClientDownload download) = 4;
void downloadCompleted(IClientDownload download) = 5; void downloadCompleted(IClientDownload download) = 5;
void downloadFailed(IClientDownload download) = 6; void downloadFailed(IClientDownload download) = 6;
Intent createIntent() = 7;
} }
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
package org.chromium.weblayer_private.interfaces; package org.chromium.weblayer_private.interfaces;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import org.chromium.weblayer_private.interfaces.IBrowserFragment; import org.chromium.weblayer_private.interfaces.IBrowserFragment;
...@@ -67,4 +68,7 @@ interface IWebLayer { ...@@ -67,4 +68,7 @@ interface IWebLayer {
ICrashReporterController getCrashReporterController( ICrashReporterController getCrashReporterController(
in IObjectWrapper appContext, in IObjectWrapper appContext,
in IObjectWrapper remoteContext) = 10; in IObjectWrapper remoteContext) = 10;
// Forwards download intent notifications to the implementation.
void onReceivedDownloadNotification(in IObjectWrapper appContext, in Intent intent) = 11;
} }
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef WEBLAYER_PUBLIC_DOWNLOAD_H_ #ifndef WEBLAYER_PUBLIC_DOWNLOAD_H_
#define WEBLAYER_PUBLIC_DOWNLOAD_H_ #define WEBLAYER_PUBLIC_DOWNLOAD_H_
#include <string>
namespace base { namespace base {
class FilePath; class FilePath;
} }
...@@ -77,6 +79,9 @@ class Download { ...@@ -77,6 +79,9 @@ class Download {
// available until the download completes successfully. // available until the download completes successfully.
virtual base::FilePath GetLocation() = 0; virtual base::FilePath GetLocation() = 0;
// Returns the effective MIME type of downloaded content.
virtual std::string GetMimeType() = 0;
// Return information about the error, if any, that was encountered during the // Return information about the error, if any, that was encountered during the
// download. // download.
virtual DownloadError GetError() = 0; virtual DownloadError GetError() = 0;
......
...@@ -52,5 +52,17 @@ ...@@ -52,5 +52,17 @@
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" <meta-data android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/weblayer_file_paths" /> android:resource="@xml/weblayer_file_paths" />
</provider> </provider>
<receiver android:name="org.chromium.weblayer.DownloadBroadcastReceiver"
android:exported="false">
<intent-filter>
<!-- these need to be in sync with DownloadImpl.java-->
<action android:name="org.chromium.weblayer.downloads.OPEN"/>
<action android:name="org.chromium.weblayer.downloads.DELETE"/>
<action android:name="org.chromium.weblayer.downloads.PAUSE"/>
<action android:name="org.chromium.weblayer.downloads.RESUME"/>
<action android:name="org.chromium.weblayer.downloads.CANCEL"/>
</intent-filter>
</receiver>
</application> </application>
</manifest> </manifest>
...@@ -33,6 +33,7 @@ android_library("java") { ...@@ -33,6 +33,7 @@ android_library("java") {
"org/chromium/weblayer/CrashReporterCallback.java", "org/chromium/weblayer/CrashReporterCallback.java",
"org/chromium/weblayer/CrashReporterController.java", "org/chromium/weblayer/CrashReporterController.java",
"org/chromium/weblayer/Download.java", "org/chromium/weblayer/Download.java",
"org/chromium/weblayer/DownloadBroadcastReceiver.java",
"org/chromium/weblayer/DownloadCallback.java", "org/chromium/weblayer/DownloadCallback.java",
"org/chromium/weblayer/DownloadError.java", "org/chromium/weblayer/DownloadError.java",
"org/chromium/weblayer/DownloadState.java", "org/chromium/weblayer/DownloadState.java",
......
...@@ -26,6 +26,18 @@ public final class Download extends IClientDownload.Stub { ...@@ -26,6 +26,18 @@ public final class Download extends IClientDownload.Stub {
mDownloadImpl = impl; mDownloadImpl = impl;
} }
/**
* By default downloads will show a system notification. Call this to disable it.
*/
public void disableNotification() {
ThreadCheck.ensureOnUiThread();
try {
mDownloadImpl.disableNotification();
} catch (RemoteException e) {
throw new APICallException(e);
}
}
@DownloadState @DownloadState
public int getState() { public int getState() {
ThreadCheck.ensureOnUiThread(); ThreadCheck.ensureOnUiThread();
...@@ -111,6 +123,19 @@ public final class Download extends IClientDownload.Stub { ...@@ -111,6 +123,19 @@ public final class Download extends IClientDownload.Stub {
} }
} }
/**
* Returns the effective MIME type of downloaded content.
*/
@NonNull
public String getMimeType() {
ThreadCheck.ensureOnUiThread();
try {
return mDownloadImpl.getMimeType();
} catch (RemoteException e) {
throw new APICallException(e);
}
}
/** /**
* Return information about the error, if any, that was encountered during the download. * Return information about the error, if any, that was encountered during the download.
*/ */
......
// Copyright 2020 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.weblayer;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import org.chromium.weblayer_private.interfaces.ObjectWrapper;
/**
* Listens to events from the download system notifications.
*/
public class DownloadBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
WebLayer.loadAsync(context, webLayer -> {
try {
webLayer.getImpl().onReceivedDownloadNotification(
ObjectWrapper.wrap(context), intent);
} catch (RemoteException e) {
throw new RuntimeException(e);
}
});
} catch (UnsupportedVersionException e) {
throw new RuntimeException(e);
}
}
}
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
package org.chromium.weblayer; package org.chromium.weblayer;
import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.RemoteException; import android.os.RemoteException;
import android.webkit.ValueCallback; import android.webkit.ValueCallback;
...@@ -328,6 +329,15 @@ public final class Tab { ...@@ -328,6 +329,15 @@ public final class Tab {
StrictModeWorkaround.apply(); StrictModeWorkaround.apply();
mCallback.onDownloadFailed((Download) download); mCallback.onDownloadFailed((Download) download);
} }
@Override
public Intent createIntent() {
StrictModeWorkaround.apply();
// Intent objects need to be created in the client library so they can refer to the
// broadcast receiver that will handle them. The broadcast receiver needs to be in the
// client library because it's referenced in the manifest.
return new Intent(WebLayer.getAppContext(), DownloadBroadcastReceiver.class);
}
} }
private static final class ErrorPageCallbackClientImpl extends IErrorPageCallbackClient.Stub { private static final class ErrorPageCallbackClientImpl extends IErrorPageCallbackClient.Stub {
......
...@@ -47,6 +47,9 @@ public final class WebLayer { ...@@ -47,6 +47,9 @@ public final class WebLayer {
@Nullable @Nullable
private static Context sRemoteContext; private static Context sRemoteContext;
@Nullable
private static Context sAppContext;
@Nullable @Nullable
private static WebLayerLoader sLoader; private static WebLayerLoader sLoader;
...@@ -123,6 +126,10 @@ public final class WebLayer { ...@@ -123,6 +126,10 @@ public final class WebLayer {
return sLoader; return sLoader;
} }
IWebLayer getImpl() {
return mImpl;
}
/** /**
* Returns the supported version. Using any functions defined in a newer version than * Returns the supported version. Using any functions defined in a newer version than
* returned by {@link getSupportedMajorVersion} result in throwing an * returned by {@link getSupportedMajorVersion} result in throwing an
...@@ -151,6 +158,12 @@ public final class WebLayer { ...@@ -151,6 +158,12 @@ public final class WebLayer {
return sLoader.getMajorVersion(); return sLoader.getMajorVersion();
} }
// Internal getter for the app Context. This should only be used when you know WebLayer has
// been initialized.
static Context getAppContext() {
return sAppContext;
}
/** /**
* Returns the Chrome version of the WebLayer implementation. This will return a full version * Returns the Chrome version of the WebLayer implementation. This will return a full version
* string such as "79.0.3945.0", while {@link getSupportedMajorVersion} will only return the * string such as "79.0.3945.0", while {@link getSupportedMajorVersion} will only return the
...@@ -405,6 +418,7 @@ public final class WebLayer { ...@@ -405,6 +418,7 @@ public final class WebLayer {
} }
Class<?> webViewFactoryClass = Class.forName("android.webkit.WebViewFactory"); Class<?> webViewFactoryClass = Class.forName("android.webkit.WebViewFactory");
String implPackageName = getImplPackageName(appContext); String implPackageName = getImplPackageName(appContext);
sAppContext = appContext;
if (implPackageName != null) { if (implPackageName != null) {
sRemoteContext = createRemoteContextFromPackageName(appContext, implPackageName); sRemoteContext = createRemoteContextFromPackageName(appContext, implPackageName);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
......
...@@ -8,4 +8,5 @@ ...@@ -8,4 +8,5 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path name="images" path="images/"/> <files-path name="images" path="images/"/>
<external-path name="external_files" path="."/>
</paths> </paths>
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
package org.chromium.weblayer.shell; package org.chromium.weblayer.shell;
import android.app.DownloadManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
...@@ -281,11 +280,7 @@ public class WebLayerShellActivity extends FragmentActivity { ...@@ -281,11 +280,7 @@ public class WebLayerShellActivity extends FragmentActivity {
@Override @Override
public boolean onInterceptDownload(Uri uri, String userAgent, String contentDisposition, public boolean onInterceptDownload(Uri uri, String userAgent, String contentDisposition,
String mimetype, long contentLength) { String mimetype, long contentLength) {
DownloadManager.Request request = new DownloadManager.Request(uri); return false;
request.setNotificationVisibility(
DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
getSystemService(DownloadManager.class).enqueue(request);
return true;
} }
@Override @Override
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment