32
32
import androidx .core .view .ViewCompat ;
33
33
import androidx .core .view .WindowCompat ;
34
34
import androidx .core .view .WindowInsetsCompat ;
35
+ import androidx .fragment .app .Fragment ;
35
36
import androidx .loader .app .LoaderManager ;
36
37
import androidx .loader .content .Loader ;
37
38
38
39
import com .google .android .material .snackbar .Snackbar ;
39
40
40
41
import app .grapheneos .pdfviewer .databinding .PdfviewerBinding ;
41
42
import app .grapheneos .pdfviewer .fragment .DocumentPropertiesFragment ;
43
+ import app .grapheneos .pdfviewer .fragment .PasswordPromptFragment ;
42
44
import app .grapheneos .pdfviewer .fragment .JumpToPageFragment ;
43
45
import app .grapheneos .pdfviewer .loader .DocumentPropertiesLoader ;
44
46
45
47
import java .io .IOException ;
46
48
import java .io .InputStream ;
49
+ import java .io .FileNotFoundException ;
47
50
import java .util .HashMap ;
48
51
import java .util .List ;
49
52
@@ -54,6 +57,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
54
57
private static final String STATE_PAGE = "page" ;
55
58
private static final String STATE_ZOOM_RATIO = "zoomRatio" ;
56
59
private static final String STATE_DOCUMENT_ORIENTATION_DEGREES = "documentOrientationDegrees" ;
60
+ private static final String STATE_ENCRYPTED_DOCUMENT_PASSWORD = "encrypted_document_password" ;
57
61
private static final String KEY_PROPERTIES = "properties" ;
58
62
private static final int MIN_WEBVIEW_RELEASE = 89 ;
59
63
@@ -110,13 +114,15 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
110
114
private float mZoomRatio = 1f ;
111
115
private int mDocumentOrientationDegrees ;
112
116
private int mDocumentState ;
117
+ private String mEncryptedDocumentPassword ;
113
118
private List <CharSequence > mDocumentProperties ;
114
119
private InputStream mInputStream ;
115
120
116
121
private PdfviewerBinding binding ;
117
122
private TextView mTextView ;
118
123
private Toast mToast ;
119
124
private Snackbar snackbar ;
125
+ private PasswordPromptFragment mPasswordPromptFragment ;
120
126
121
127
private final ActivityResultLauncher <Intent > openDocumentLauncher = registerForActivityResult (
122
128
new ActivityResultContracts .StartActivityForResult (), result -> {
@@ -127,6 +133,7 @@ public class PdfViewer extends AppCompatActivity implements LoaderManager.Loader
127
133
mUri = result .getData ().getData ();
128
134
mPage = 1 ;
129
135
mDocumentProperties = null ;
136
+ mEncryptedDocumentPassword = "" ;
130
137
loadPdf ();
131
138
invalidateOptionsMenu ();
132
139
}
@@ -177,6 +184,29 @@ public void setDocumentProperties(final String properties) {
177
184
args .putString (KEY_PROPERTIES , properties );
178
185
runOnUiThread (() -> LoaderManager .getInstance (PdfViewer .this ).restartLoader (DocumentPropertiesLoader .ID , args , PdfViewer .this ));
179
186
}
187
+
188
+ @ JavascriptInterface
189
+ public void showPasswordPrompt () {
190
+ if (getPasswordPromptFragment ().isAdded ()) {
191
+ getPasswordPromptFragment ().dismiss ();
192
+ }
193
+ getPasswordPromptFragment ().show (getSupportFragmentManager (), PasswordPromptFragment .class .getName ());
194
+ }
195
+
196
+ @ JavascriptInterface
197
+ public void invalidPassword () {
198
+ runOnUiThread (PdfViewer .this ::notifyInvalidPassword );
199
+ showPasswordPrompt ();
200
+ }
201
+
202
+ @ JavascriptInterface
203
+ public String getPassword () {
204
+ return mEncryptedDocumentPassword != null ? mEncryptedDocumentPassword : "" ;
205
+ }
206
+ }
207
+
208
+ private void notifyInvalidPassword () {
209
+ snackbar .setText (R .string .password_prompt_invalid_password ).show ();
180
210
}
181
211
182
212
@ Override
@@ -241,6 +271,12 @@ public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceReque
241
271
Log .d (TAG , "path " + path );
242
272
243
273
if ("/placeholder.pdf" .equals (path )) {
274
+ maybeCloseInputStream ();
275
+ try {
276
+ mInputStream = getContentResolver ().openInputStream (mUri );
277
+ } catch (FileNotFoundException ignored ) {
278
+ snackbar .setText (R .string .io_error ).show ();
279
+ }
244
280
return new WebResourceResponse ("application/pdf" , null , mInputStream );
245
281
}
246
282
@@ -274,6 +310,7 @@ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request
274
310
public void onPageFinished (WebView view , String url ) {
275
311
mDocumentState = STATE_LOADED ;
276
312
invalidateOptionsMenu ();
313
+ loadPdfWithPassword (mEncryptedDocumentPassword );
277
314
}
278
315
});
279
316
@@ -341,6 +378,7 @@ public void onZoomEnd() {
341
378
mPage = savedInstanceState .getInt (STATE_PAGE );
342
379
mZoomRatio = savedInstanceState .getFloat (STATE_ZOOM_RATIO );
343
380
mDocumentOrientationDegrees = savedInstanceState .getInt (STATE_DOCUMENT_ORIENTATION_DEGREES );
381
+ mEncryptedDocumentPassword = savedInstanceState .getString (STATE_ENCRYPTED_DOCUMENT_PASSWORD );
344
382
}
345
383
346
384
if (mUri != null ) {
@@ -353,6 +391,38 @@ public void onZoomEnd() {
353
391
}
354
392
}
355
393
394
+ @ Override
395
+ protected void onDestroy () {
396
+ super .onDestroy ();
397
+ binding .webview .removeJavascriptInterface ("channel" );
398
+ binding .getRoot ().removeView (binding .webview );
399
+ binding .webview .destroy ();
400
+ maybeCloseInputStream ();
401
+ }
402
+
403
+ void maybeCloseInputStream () {
404
+ InputStream stream = mInputStream ;
405
+ if (stream == null ) {
406
+ return ;
407
+ }
408
+ mInputStream = null ;
409
+ try {
410
+ stream .close ();
411
+ } catch (IOException ignored ) {}
412
+ }
413
+
414
+ private PasswordPromptFragment getPasswordPromptFragment () {
415
+ if (mPasswordPromptFragment == null ) {
416
+ final Fragment fragment = getSupportFragmentManager ().findFragmentByTag (PasswordPromptFragment .class .getName ());
417
+ if (fragment != null ) {
418
+ mPasswordPromptFragment = (PasswordPromptFragment ) fragment ;
419
+ } else {
420
+ mPasswordPromptFragment = new PasswordPromptFragment ();
421
+ }
422
+ }
423
+ return mPasswordPromptFragment ;
424
+ }
425
+
356
426
@ Override
357
427
protected void onResume () {
358
428
super .onResume ();
@@ -403,10 +473,17 @@ private void loadPdf() {
403
473
return ;
404
474
}
405
475
476
+ mDocumentState = 0 ;
406
477
showSystemUi ();
478
+ invalidateOptionsMenu ();
407
479
binding .webview .loadUrl ("https://localhost/viewer.html" );
408
480
}
409
481
482
+ public void loadPdfWithPassword (final String password ) {
483
+ mEncryptedDocumentPassword = password ;
484
+ binding .webview .evaluateJavascript ("loadDocument()" , null );
485
+ }
486
+
410
487
private void renderPage (final int zoom ) {
411
488
binding .webview .evaluateJavascript ("onRenderPage(" + zoom + ")" , null );
412
489
}
@@ -503,6 +580,7 @@ public void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
503
580
savedInstanceState .putInt (STATE_PAGE , mPage );
504
581
savedInstanceState .putFloat (STATE_ZOOM_RATIO , mZoomRatio );
505
582
savedInstanceState .putInt (STATE_DOCUMENT_ORIENTATION_DEGREES , mDocumentOrientationDegrees );
583
+ savedInstanceState .putString (STATE_ENCRYPTED_DOCUMENT_PASSWORD , mEncryptedDocumentPassword );
506
584
}
507
585
508
586
private void showPageNumber () {
0 commit comments