Added AMP viewer

pull/194/merge
M66B 3 years ago
parent 2fbe0904cd
commit 3f59ddfd46

@ -352,6 +352,24 @@
</intent-filter>
</activity>
<activity
android:name=".ActivityAMP"
android:exported="true"
android:icon="@mipmap/ic_launcher"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="text/x-amp-html" />
<data android:host="*" />
</intent-filter>
</activity>
<activity
android:name=".ActivityBilling"
android:exported="false"

@ -351,6 +351,24 @@
</intent-filter>
</activity>
<activity
android:name=".ActivityAMP"
android:exported="true"
android:icon="@mipmap/ic_launcher"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="text/x-amp-html" />
<data android:host="*" />
</intent-filter>
</activity>
<activity
android:name=".ActivityBilling"
android:exported="false"

@ -351,6 +351,24 @@
</intent-filter>
</activity>
<activity
android:name=".ActivityAMP"
android:exported="true"
android:icon="@mipmap/ic_launcher"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="text/x-amp-html" />
<data android:host="*" />
</intent-filter>
</activity>
<activity
android:name=".ActivityBilling"
android:exported="false"

@ -351,6 +351,24 @@
</intent-filter>
</activity>
<activity
android:name=".ActivityAMP"
android:exported="true"
android:icon="@mipmap/ic_launcher"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="text/x-amp-html" />
<data android:host="*" />
</intent-filter>
</activity>
<activity
android:name=".ActivityBilling"
android:exported="false"

@ -0,0 +1,155 @@
package eu.faircode.email;
/*
This file is part of FairEmail.
FairEmail is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
FairEmail is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with FairEmail. If not, see <http://www.gnu.org/licenses/>.
Copyright 2018-2022 by Marcel Bokhorst (M66B)
*/
import android.Manifest;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.webkit.WebSettings;
import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.Group;
import androidx.preference.PreferenceManager;
import com.google.android.material.snackbar.Snackbar;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
public class ActivityAMP extends ActivityBase {
private WebView wvAmp;
private ContentLoadingProgressBar pbWait;
private Group grpReady;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setIcon(R.drawable.twotone_bolt_24);
getSupportActionBar().setSubtitle("AMP");
View view = LayoutInflater.from(this).inflate(R.layout.activity_amp, null);
setContentView(view);
wvAmp = findViewById(R.id.wvAmp);
pbWait = findViewById(R.id.pbWait);
grpReady = findViewById(R.id.grpReady);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean safe_browsing = prefs.getBoolean("safe_browsing", false);
WebSettings settings = wvAmp.getSettings();
settings.setUserAgentString(WebViewEx.getUserAgent(this, wvAmp));
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
settings.setBuiltInZoomControls(true);
settings.setDisplayZoomControls(false);
settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.TEXT_AUTOSIZING);
settings.setAllowFileAccess(false);
settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
settings.setSafeBrowsingEnabled(safe_browsing);
settings.setLoadsImagesAutomatically(true);
settings.setBlockNetworkLoads(false);
settings.setBlockNetworkImage(false);
settings.setJavaScriptEnabled(true);
// Initialize
grpReady.setVisibility(View.GONE);
load();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
load();
}
private void load() {
Uri uri = getIntent().getData();
Log.i("AMP uri=" + uri);
Bundle args = new Bundle();
args.putParcelable("uri", uri);
new SimpleTask<String>() {
@Override
protected void onPreExecute(Bundle args) {
pbWait.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(Bundle args) {
pbWait.setVisibility(View.GONE);
}
@Override
protected String onExecute(Context context, Bundle args) throws Throwable {
Uri uri = args.getParcelable("uri");
if (uri == null)
throw new FileNotFoundException();
if (!"content".equals(uri.getScheme()) &&
!Helper.hasPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE)) {
Log.w("AMP uri=" + uri);
throw new IllegalArgumentException(context.getString(R.string.title_no_stream));
}
ContentResolver resolver = context.getContentResolver();
try (InputStream is = resolver.openInputStream(uri)) {
return Helper.readStream(is);
}
}
@Override
protected void onExecuted(Bundle args, String amp) {
wvAmp.loadDataWithBaseURL(null, amp, "text/html", StandardCharsets.UTF_8.name(), null);
grpReady.setVisibility(View.VISIBLE);
}
@Override
protected void onException(Bundle args, @NonNull Throwable ex) {
if (ex instanceof IllegalArgumentException)
Snackbar.make(findViewById(android.R.id.content), ex.getMessage(), Snackbar.LENGTH_LONG)
.setGestureInsetBottomIgnored(true).show();
else
Log.unexpectedError(getSupportFragmentManager(), ex, false);
}
}.execute(this, args, "amp:decode");
}
}

@ -20,7 +20,6 @@ package eu.faircode.email;
*/
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
@ -35,7 +34,6 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.FileProvider;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.Lifecycle;
@ -295,67 +293,9 @@ public class AdapterAttachment extends RecyclerView.Adapter<AdapterAttachment.Vi
}
private void onShare(EntityAttachment attachment) {
if ("text/x-amp-html".equals(attachment.type)) {
// https://amp.dev/about/email/
new AlertDialog.Builder(context)
.setIcon(R.drawable.twotone_bolt_24)
.setTitle(R.string.title_ask_show_amp)
.setMessage(R.string.title_ask_show_html)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
onAmp(attachment);
}
})
.setNegativeButton(android.R.string.cancel, null)
.show();
} else {
String title = (attachment.name == null ? attachment.cid : attachment.name);
Helper.share(context, attachment.getFile(context), attachment.getMimeType(), title);
}
}
private void onAmp(EntityAttachment attachment) {
Bundle args = new Bundle();
args.putLong("id", attachment.id);
new SimpleTask<String>() {
@Override
protected String onExecute(Context context, Bundle args) throws Throwable {
long id = args.getLong("id");
DB db = DB.getInstance(context);
EntityAttachment attachment = db.attachment().getAttachment(id);
if (attachment == null)
return null;
File file = attachment.getFile(context);
return Helper.readText(file);
}
@Override
protected void onExecuted(Bundle args, String html) {
if (html == null)
return;
Bundle hargs = new Bundle();
hargs.putString("html", html);
hargs.putBoolean("overview_mode", true);
hargs.putBoolean("safe_browsing", true);
hargs.putBoolean("force_light", true);
hargs.putBoolean("javascript", true);
FragmentDialogOpenFull dialog = new FragmentDialogOpenFull();
dialog.setArguments(hargs);
dialog.show(parentFragment.getParentFragmentManager(), "amp");
}
@Override
protected void onException(Bundle args, Throwable ex) {
Log.unexpectedError(parentFragment.getParentFragmentManager(), ex);
}
}.execute(context, owner, args, "attachment:amp");
}
private void onDownload(EntityAttachment attachment) {
Bundle args = new Bundle();

@ -62,7 +62,6 @@ public class FragmentDialogOpenFull extends FragmentDialogBase {
boolean overview_mode = args.getBoolean("overview_mode");
boolean safe_browsing = args.getBoolean("safe_browsing");
boolean force_light = args.getBoolean("force_light");
boolean javascript = args.getBoolean("javascript");
final Context context = getContext();
@ -90,8 +89,6 @@ public class FragmentDialogOpenFull extends FragmentDialogBase {
if (WebViewEx.isFeatureSupported(WebViewFeature.FORCE_DARK))
WebSettingsCompat.setForceDark(settings, dark ? FORCE_DARK_ON : FORCE_DARK_OFF);
settings.setJavaScriptEnabled(javascript);
settings.setLoadsImagesAutomatically(true);
settings.setBlockNetworkLoads(false);
settings.setBlockNetworkImage(false);

@ -0,0 +1,29 @@
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="eu.faircode.email.ActivityAMP">
<WebView
android:id="@+id/wvAmp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<eu.faircode.email.ContentLoadingProgressBar
android:id="@+id/pbWait"
style="@style/Base.Widget.AppCompat.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Group
android:id="@+id/grpReady"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="wvAmp" />
</androidx.constraintlayout.widget.ConstraintLayout>

@ -1211,7 +1211,6 @@
<string name="title_ask_show_html_images">Always show images on showing original messages</string>
<string name="title_ask_show_image">Showing images can leak privacy sensitive information</string>
<string name="title_ask_show_image_hint">Images recognized as tracking images will not be shown</string>
<string name="title_ask_show_amp">Show AMP variant of the message?</string>
<string name="title_ask_delete_local">Delete local messages? Messages will remain on the remote server.</string>
<string name="title_ask_help">Help improve FairEmail</string>
<string name="title_ask_reporting">Send error reports?</string>

@ -352,6 +352,24 @@
</intent-filter>
</activity>
<activity
android:name=".ActivityAMP"
android:exported="true"
android:icon="@mipmap/ic_launcher"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:mimeType="text/x-amp-html" />
<data android:host="*" />
</intent-filter>
</activity>
<activity
android:name=".ActivityBilling"
android:exported="false"

Loading…
Cancel
Save