package com.fsck.k9.view;
import java.io.InputStream;
import android.annotation.TargetApi;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.provider.Browser;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import timber.log.Timber;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.fsck.k9.K9;
import com.fsck.k9.mailstore.AttachmentResolver;
import com.fsck.k9.view.MessageWebView.OnPageFinishedListener;
/**
* {@link WebViewClient} that intercepts requests for {@code cid:} URIs to load the respective body part.
*/
abstract class K9WebViewClient extends WebViewClient {
private static final String CID_SCHEME = "cid";
private static final WebResourceResponse RESULT_DO_NOT_INTERCEPT = null;
private static final WebResourceResponse RESULT_DUMMY_RESPONSE = new WebResourceResponse(null, null, null);
private OnPageFinishedListener onPageFinishedListener;
@Nullable
private final AttachmentResolver attachmentResolver;
public static K9WebViewClient newInstance(@Nullable AttachmentResolver attachmentResolver) {
if (Build.VERSION.SDK_INT < 21) {
return new PreLollipopWebViewClient(attachmentResolver);
}
return new LollipopWebViewClient(attachmentResolver);
}
private K9WebViewClient(@Nullable AttachmentResolver attachmentResolver) {
this.attachmentResolver = attachmentResolver;
}
@Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
Uri uri = Uri.parse(url);
if (CID_SCHEME.equals(uri.getScheme())) {
return false;
}
Context context = webView.getContext();
Intent intent = createBrowserViewIntent(uri, context);
addActivityFlags(intent);
boolean overridingUrlLoading = false;
try {
context.startActivity(intent);
overridingUrlLoading = true;
} catch (ActivityNotFoundException ex) {
// If no application can handle the URL, assume that the WebView can handle it.
}
return overridingUrlLoading;
}
private Intent createBrowserViewIntent(Uri uri, Context context) {
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.addCategory(Intent.CATEGORY_BROWSABLE);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
return intent;
}
protected abstract void addActivityFlags(Intent intent);
protected WebResourceResponse shouldInterceptRequest(WebView webView, Uri uri) {
if (!CID_SCHEME.equals(uri.getScheme())) {
return RESULT_DO_NOT_INTERCEPT;
}
if (attachmentResolver == null) {
return RESULT_DUMMY_RESPONSE;
}
String cid = uri.getSchemeSpecificPart();
if (TextUtils.isEmpty(cid)) {
return RESULT_DUMMY_RESPONSE;
}
Uri attachmentUri = attachmentResolver.getAttachmentUriForContentId(cid);
if (attachmentUri == null) {
return RESULT_DUMMY_RESPONSE;
}
Context context = webView.getContext();
ContentResolver contentResolver = context.getContentResolver();
try {
String mimeType = contentResolver.getType(attachmentUri);
InputStream inputStream = contentResolver.openInputStream(attachmentUri);
return new WebResourceResponse(mimeType, null, inputStream);
} catch (Exception e) {
Timber.e(e, "Error while intercepting URI: %s", uri);
return RESULT_DUMMY_RESPONSE;
}
}
public void setOnPageFinishedListener(OnPageFinishedListener onPageFinishedListener) {
this.onPageFinishedListener = onPageFinishedListener;
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (onPageFinishedListener != null) {
onPageFinishedListener.onPageFinished();
}
}
@SuppressWarnings("deprecation")
private static class PreLollipopWebViewClient extends K9WebViewClient {
protected PreLollipopWebViewClient(AttachmentResolver attachmentResolver) {
super(attachmentResolver);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView webView, String url) {
return shouldInterceptRequest(webView, Uri.parse(url));
}
@Override
protected void addActivityFlags(Intent intent) {
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
}
}
@TargetApi(VERSION_CODES.LOLLIPOP)
private static class LollipopWebViewClient extends K9WebViewClient {
protected LollipopWebViewClient(AttachmentResolver attachmentResolver) {
super(attachmentResolver);
}
@Override
public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest request) {
return shouldInterceptRequest(webView, request.getUrl());
}
@Override
protected void addActivityFlags(Intent intent) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
}
}
}