Skip to content

Commit 731a863

Browse files
committed
handle WebView crashes by showing an alert page
1 parent 0b4b603 commit 731a863

File tree

3 files changed

+90
-25
lines changed

3 files changed

+90
-25
lines changed

app/src/main/java/app/grapheneos/pdfviewer/PdfViewer.java

+60-15
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import android.view.View;
1717
import android.webkit.CookieManager;
1818
import android.webkit.JavascriptInterface;
19+
import android.webkit.RenderProcessGoneDetail;
1920
import android.webkit.WebResourceRequest;
2021
import android.webkit.WebResourceResponse;
2122
import android.webkit.WebSettings;
@@ -58,6 +59,7 @@
5859
public class PdfViewer extends AppCompatActivity implements LoaderManager.LoaderCallbacks<List<CharSequence>> {
5960
private static final String TAG = "PdfViewer";
6061

62+
private static final String STATE_WEBVIEW_CRASHED = "webview_crashed";
6163
private static final String STATE_URI = "uri";
6264
private static final String STATE_PAGE = "page";
6365
private static final String STATE_ZOOM_RATIO = "zoomRatio";
@@ -116,6 +118,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
116118
private static final int STATE_END = 2;
117119
private static final int PADDING = 10;
118120

121+
private boolean webViewCrashed;
119122
private Uri mUri;
120123
public int mPage;
121124
public int mNumPages;
@@ -264,10 +267,19 @@ public String getPassword() {
264267
}
265268
}
266269

270+
private void showWebViewCrashed() {
271+
binding.webviewAlertTitle.setText(getString(R.string.webview_crash_title));
272+
binding.webviewAlertMessage.setText(getString(R.string.webview_crash_message));
273+
binding.webviewAlertLayout.setVisibility(View.VISIBLE);
274+
binding.webviewAlertReload.setVisibility(View.VISIBLE);
275+
binding.webview.setVisibility(View.GONE);
276+
}
277+
267278
@Override
268279
@SuppressLint({"SetJavaScriptEnabled"})
269280
protected void onCreate(Bundle savedInstanceState) {
270281
super.onCreate(savedInstanceState);
282+
271283
binding = PdfviewerBinding.inflate(getLayoutInflater());
272284
setContentView(binding.getRoot());
273285
setSupportActionBar(binding.toolbar);
@@ -395,6 +407,17 @@ public void onPageFinished(WebView view, String url) {
395407
invalidateOptionsMenu();
396408
loadPdfWithPassword(mEncryptedDocumentPassword);
397409
}
410+
411+
@Override
412+
public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
413+
if (detail.didCrash()) {
414+
webViewCrashed = true;
415+
showWebViewCrashed();
416+
purgeWebView();
417+
return true;
418+
}
419+
return false;
420+
}
398421
});
399422

400423
GestureHelper.attach(PdfViewer.this, binding.webview,
@@ -455,6 +478,7 @@ public void onZoomEnd() {
455478
}
456479

457480
if (savedInstanceState != null) {
481+
webViewCrashed = savedInstanceState.getBoolean(STATE_WEBVIEW_CRASHED);
458482
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
459483
mUri = savedInstanceState.getParcelable(STATE_URI, Uri.class);
460484
} else {
@@ -468,7 +492,14 @@ public void onZoomEnd() {
468492
mEncryptedDocumentPassword = savedInstanceState.getString(STATE_ENCRYPTED_DOCUMENT_PASSWORD);
469493
}
470494

471-
if (mUri != null) {
495+
binding.webviewAlertReload.setOnClickListener(v -> {
496+
webViewCrashed = false;
497+
recreate();
498+
});
499+
500+
if (webViewCrashed) {
501+
showWebViewCrashed();
502+
} else if (mUri != null) {
472503
if ("file".equals(mUri.getScheme())) {
473504
snackbar.setText(R.string.legacy_file_uri).show();
474505
return;
@@ -478,14 +509,16 @@ public void onZoomEnd() {
478509
}
479510
}
480511

481-
512+
private void purgeWebView() {
513+
binding.webview.removeJavascriptInterface("channel");
514+
binding.getRoot().removeView(binding.webview);
515+
binding.webview.destroy();
516+
}
482517

483518
@Override
484519
protected void onDestroy() {
485520
super.onDestroy();
486-
binding.webview.removeJavascriptInterface("channel");
487-
binding.getRoot().removeView(binding.webview);
488-
binding.webview.destroy();
521+
purgeWebView();
489522
maybeCloseInputStream();
490523
}
491524

@@ -525,15 +558,18 @@ private void setToolbarTitleWithDocumentName() {
525558
protected void onResume() {
526559
super.onResume();
527560

528-
// The user could have left the activity to update the WebView
529-
invalidateOptionsMenu();
530-
if (getWebViewRelease() >= MIN_WEBVIEW_RELEASE) {
531-
binding.webviewOutOfDateLayout.setVisibility(View.GONE);
532-
binding.webview.setVisibility(View.VISIBLE);
533-
} else {
534-
binding.webview.setVisibility(View.GONE);
535-
binding.webviewOutOfDateMessage.setText(getString(R.string.webview_out_of_date_message, getWebViewRelease(), MIN_WEBVIEW_RELEASE));
536-
binding.webviewOutOfDateLayout.setVisibility(View.VISIBLE);
561+
if (!webViewCrashed) {
562+
// The user could have left the activity to update the WebView
563+
invalidateOptionsMenu();
564+
if (getWebViewRelease() >= MIN_WEBVIEW_RELEASE) {
565+
binding.webviewAlertLayout.setVisibility(View.GONE);
566+
binding.webview.setVisibility(View.VISIBLE);
567+
} else {
568+
binding.webview.setVisibility(View.GONE);
569+
binding.webviewAlertTitle.setText(getString(R.string.webview_out_of_date_title));
570+
binding.webviewAlertMessage.setText(getString(R.string.webview_out_of_date_message, getWebViewRelease(), MIN_WEBVIEW_RELEASE));
571+
binding.webviewAlertLayout.setVisibility(View.VISIBLE);
572+
}
537573
}
538574
}
539575

@@ -645,6 +681,7 @@ private void hideSystemUi() {
645681
@Override
646682
public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
647683
super.onSaveInstanceState(savedInstanceState);
684+
savedInstanceState.putBoolean(STATE_WEBVIEW_CRASHED, webViewCrashed);
648685
savedInstanceState.putParcelable(STATE_URI, mUri);
649686
savedInstanceState.putInt(STATE_PAGE, mPage);
650687
savedInstanceState.putFloat(STATE_ZOOM_RATIO, mZoomRatio);
@@ -703,14 +740,22 @@ public boolean onPrepareOptionsMenu(@NonNull Menu menu) {
703740
mDocumentState = STATE_END;
704741
}
705742

706-
enableDisableMenuItem(menu.findItem(R.id.action_open), getWebViewRelease() >= MIN_WEBVIEW_RELEASE);
743+
744+
enableDisableMenuItem(menu.findItem(R.id.action_open),
745+
!webViewCrashed && getWebViewRelease() >= MIN_WEBVIEW_RELEASE);
707746
enableDisableMenuItem(menu.findItem(R.id.action_share), mUri != null);
708747
enableDisableMenuItem(menu.findItem(R.id.action_next), mPage < mNumPages);
709748
enableDisableMenuItem(menu.findItem(R.id.action_previous), mPage > 1);
710749
enableDisableMenuItem(menu.findItem(R.id.action_save_as), mUri != null);
711750

712751
menu.findItem(R.id.action_outline).setVisible(viewModel.hasOutline());
713752

753+
if (webViewCrashed) {
754+
for (final int id : ids) {
755+
enableDisableMenuItem(menu.findItem(id), false);
756+
}
757+
}
758+
714759
return true;
715760
}
716761

app/src/main/res/layout/pdfviewer.xml

+25-10
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
2626

2727
<ScrollView
28-
android:id="@+id/webview_out_of_date_layout"
28+
android:id="@+id/webview_alert_layout"
2929
android:layout_width="match_parent"
3030
android:layout_height="match_parent"
3131
android:fillViewport="true"
@@ -43,15 +43,15 @@
4343
android:layout_marginTop="32dp"
4444
android:importantForAccessibility="no"
4545
android:src="@drawable/ic_error_outline_24dp"
46-
app:layout_constraintBottom_toTopOf="@id/webview_out_of_date_title"
46+
app:layout_constraintBottom_toTopOf="@id/webview_alert_title"
4747
app:layout_constraintEnd_toEndOf="parent"
4848
app:layout_constraintStart_toStartOf="parent"
4949
app:layout_constraintTop_toTopOf="parent"
5050
app:layout_constraintVertical_chainStyle="packed"
5151
app:tint="?attr/colorPrimary" />
5252

5353
<TextView
54-
android:id="@+id/webview_out_of_date_title"
54+
android:id="@+id/webview_alert_title"
5555
style="@style/TextAppearance.Material3.TitleLarge"
5656
android:layout_width="match_parent"
5757
android:layout_height="wrap_content"
@@ -60,15 +60,13 @@
6060
android:layout_marginEnd="32dp"
6161
android:elegantTextHeight="true"
6262
android:gravity="center"
63-
android:text="@string/webview_out_of_date_title"
64-
app:layout_constraintBottom_toTopOf="@id/webview_out_of_date_message"
63+
app:layout_constraintBottom_toTopOf="@id/webview_alert_message"
6564
app:layout_constraintEnd_toEndOf="parent"
6665
app:layout_constraintStart_toStartOf="parent"
6766
app:layout_constraintTop_toBottomOf="@id/error_image_view" />
6867

69-
7068
<TextView
71-
android:id="@+id/webview_out_of_date_message"
69+
android:id="@+id/webview_alert_message"
7270
style="@style/TextAppearance.Material3.BodyMedium"
7371
android:layout_width="match_parent"
7472
android:layout_height="wrap_content"
@@ -79,14 +77,31 @@
7977
android:elegantTextHeight="true"
8078
android:gravity="center"
8179
android:lineSpacingMultiplier="1.2"
82-
android:text="@string/webview_out_of_date_message"
80+
app:layout_constraintBottom_toBottomOf="@id/webview_alert_reload"
81+
app:layout_constraintEnd_toEndOf="parent"
82+
app:layout_constraintStart_toStartOf="parent"
83+
app:layout_constraintTop_toBottomOf="@id/webview_alert_title" />
84+
85+
<Button
86+
android:id="@+id/webview_alert_reload"
87+
android:layout_width="match_parent"
88+
android:layout_height="wrap_content"
89+
android:layout_marginStart="32dp"
90+
android:layout_marginTop="8dp"
91+
android:layout_marginEnd="32dp"
92+
android:layout_marginBottom="32dp"
93+
android:elegantTextHeight="true"
94+
android:gravity="center"
95+
android:lineSpacingMultiplier="1.2"
96+
android:text="@string/reload"
97+
android:visibility="gone"
8398
app:layout_constraintBottom_toBottomOf="parent"
8499
app:layout_constraintEnd_toEndOf="parent"
85100
app:layout_constraintStart_toStartOf="parent"
86-
app:layout_constraintTop_toBottomOf="@id/webview_out_of_date_title" />
101+
app:layout_constraintTop_toBottomOf="@id/webview_alert_message" />
87102

88103
</androidx.constraintlayout.widget.ConstraintLayout>
89104

90105
</ScrollView>
91106

92-
</androidx.coordinatorlayout.widget.CoordinatorLayout>
107+
</androidx.coordinatorlayout.widget.CoordinatorLayout>

app/src/main/res/values/strings.xml

+5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
<string name="webview_out_of_date_title">WebView out-of-date</string>
3434
<string name="webview_out_of_date_message" tools:ignore="PluralsCandidate">Your current WebView version is %1$d. The WebView should be at least version %2$d for the PDF Viewer to work.</string>
3535

36+
<string name="webview_crash_title">WebView crashed</string>
37+
<string name="webview_crash_message">Android WebView render process crashed.</string>
38+
39+
<string name="reload">Reload</string>
40+
3641
<string name="password_prompt_hint">Password</string>
3742
<string name="password_prompt_description">Enter the password to decrypt this PDF file</string>
3843
<string name="open">Open</string>

0 commit comments

Comments
 (0)