5656import android .app .AlertDialog ;
5757import android .content .DialogInterface ;
5858import android .content .Intent ;
59+ import android .content .pm .ApplicationInfo ;
5960import android .graphics .Bitmap ;
6061import android .media .MediaPlayer ;
6162import android .net .Uri ;
@@ -86,8 +87,45 @@ public class WebViewActivity extends FragmentActivity implements ViewerSettingsD
8687 private static final String TAG = "WebViewActivity" ;
8788 private static final String ASSET_PREFIX = "file:///android_asset/readium-shared-js/" ;
8889 private static final String READER_SKELETON = "file:///android_asset/readium-shared-js/reader.html" ;
89-
90- private WebView mWebview ;
90+
91+ // Installs "hook" function so that top-level window (application) can later inject the window.navigator.epubReadingSystem into this HTML document's iframe
92+ private static final String INJECT_EPUB_RSO_SCRIPT_1 = "" +
93+ "window.readium_set_epubReadingSystem = function (obj) {" +
94+ "\n window.navigator.epubReadingSystem = obj;" +
95+ "\n window.readium_set_epubReadingSystem = undefined;" +
96+ "\n var el1 = document.getElementById(\" readium_epubReadingSystem_inject1\" );" +
97+ "\n if (el1 && el1.parentNode) { el1.parentNode.removeChild(el1); }" +
98+ "\n var el2 = document.getElementById(\" readium_epubReadingSystem_inject2\" );" +
99+ "\n if (el2 && el2.parentNode) { el2.parentNode.removeChild(el2); }" +
100+ "\n };" ;
101+
102+ // Iterate top-level iframes, inject global window.navigator.epubReadingSystem if the expected hook function exists ( readium_set_epubReadingSystem() ).
103+ private static final String INJECT_EPUB_RSO_SCRIPT_2 = "" +
104+ "for (var i = 0; i < window.frames.length; i++) { \n " +
105+ "var iframe = window.frames[i]; \n " +
106+ "if (iframe.readium_set_epubReadingSystem) { \n " +
107+ "iframe.readium_set_epubReadingSystem(window.navigator.epubReadingSystem); \n " +
108+ "}\n " +
109+ "}\n " ;
110+ // Script tag to inject the "hook" function installer script, added to the head of every epub iframe document
111+ private static final String INJECT_HEAD_EPUB_RSO_1 = "" +
112+ "<script id=\" readium_epubReadingSystem_inject1\" type=\" text/javascript\" >\n " +
113+ "//<![CDATA[\n " +
114+ INJECT_EPUB_RSO_SCRIPT_1 + "\n " +
115+ "//]]>\n " +
116+ "</script>" ;
117+ // Script tag that generates an HTTP request to a fake script => triggers push of window.navigator.epubReadingSystem into this HTML document's iframe
118+ private static final String INJECT_HEAD_EPUB_RSO_2 = "" +
119+ "<script id=\" readium_epubReadingSystem_inject2\" type=\" text/javascript\" " +
120+ "src=\" /%d/readium_epubReadingSystem_inject.js\" > </script>" ;
121+ // Script tag to load the mathjax script payload, added to the head of epub iframe documents, only if <math> tags are detected
122+ private static final String INJECT_HEAD_MATHJAX = "<script type=\" text/javascript\" src=\" /readium_MathJax.js\" > </script>" ;
123+
124+ // Location of payloads in the asset folder
125+ private static final String PAYLOAD_MATHJAX_ASSET = "reader-payloads/MathJax.js" ;
126+ private static final String PAYLOAD_ANNOTATIONS_CSS_ASSET = "reader-payloads/annotations.css" ;
127+
128+ private WebView mWebview ;
91129 private Container mContainer ;
92130 private Package mPackage ;
93131 private OpenPageRequest mOpenPageRequestData ;
@@ -98,13 +136,19 @@ public class WebViewActivity extends FragmentActivity implements ViewerSettingsD
98136
99137 private boolean mIsMoAvailable ;
100138 private boolean mIsMoPlaying ;
139+ private int mEpubRsoInjectCounter = 0 ;
101140
102141 @ Override
103142 protected void onCreate (Bundle savedInstanceState ) {
104143 super .onCreate (savedInstanceState );
105144 setContentView (R .layout .activity_web_view );
106145
107146 mWebview = (WebView ) findViewById (R .id .webview );
147+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .KITKAT
148+ && 0 != (getApplicationInfo ().flags &= ApplicationInfo .FLAG_DEBUGGABLE )) {
149+ mWebview .setWebContentsDebuggingEnabled (true );
150+ }
151+
108152 mPageInfo = (TextView ) findViewById (R .id .page_info );
109153 initWebView ();
110154
@@ -301,13 +345,56 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) {
301345 return false ;
302346 }
303347
348+ private void evaluateJavascript (final String script ) {
349+ runOnUiThread (new Runnable () {
350+ @ Override
351+ public void run () {
352+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .KITKAT ) {
353+ mWebview .evaluateJavascript (script , null );
354+ } else {
355+ mWebview .loadUrl ("javascript:" + script );
356+ }
357+ }
358+ });
359+ }
360+
304361 @ Override
305362 public WebResourceResponse shouldInterceptRequest (WebView view , String url ) {
306363 Log .d (TAG , "shouldInterceptRequest: " + url );
307364 Uri uri = Uri .parse (url );
308365 if (uri .getScheme ().equals ("file" ) && url != "undefined" && url != null ) {
309366 String cleanedUrl = cleanResourceUrl (url );
310367 Log .d (TAG , url +" => " +cleanedUrl );
368+
369+ if (cleanedUrl .matches ("\\ /?\\ d*\\ /readium_epubReadingSystem_inject.js" )) {
370+ Log .d (TAG , "navigator.epubReadingSystem inject ..." );
371+
372+ // Fake script requested, this is immediately invoked after epubReadingSystem hook is in place,
373+ // => execute js on the reader.html context to push the global window.navigator.epubReadingSystem into the iframe(s)
374+ evaluateJavascript (INJECT_EPUB_RSO_SCRIPT_2 );
375+ return new WebResourceResponse ("text/javascript" , UTF_8
376+ , new ByteArrayInputStream ("(function(){})()" .getBytes ()));
377+
378+ }
379+ // Special handling for payload requests
380+ else if (cleanedUrl .matches ("\\ /?readium_MathJax.js" )) {
381+ Log .d (TAG , "MathJax.js inject ..." );
382+ try {
383+ return new WebResourceResponse ("text/javascript" , UTF_8
384+ , getAssets ().open (PAYLOAD_MATHJAX_ASSET ));
385+ } catch (IOException e ) {
386+ return super .shouldInterceptRequest (view , url );
387+ }
388+ } else if (cleanedUrl .matches ("\\ /?readium_Annotations.css" )) {
389+ Log .d (TAG , "annotations.css inject ..." );
390+ try {
391+ return new WebResourceResponse ("text/css" , UTF_8
392+ , getAssets ().open (PAYLOAD_ANNOTATIONS_CSS_ASSET ));
393+ } catch (IOException e ) {
394+ return super .shouldInterceptRequest (view , url );
395+ }
396+ }
397+
311398 InputStream data = mPackage .getInputStream (cleanedUrl );
312399 ManifestItem item = mPackage .getManifestItem (cleanedUrl );
313400 if (item != null && item .isHtml ()) {
@@ -316,8 +403,22 @@ public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
316403 binary = new byte [data .available ()];
317404 data .read (binary );
318405 data .close ();
319- data = new ByteArrayInputStream (HTMLUtil .htmlByReplacingMediaURLsInHTML (new String (binary ),
320- cleanedUrl , "PackageUUID" ).getBytes ());
406+ String htmlText = new String (binary );
407+ String newHtml = HTMLUtil .htmlByReplacingMediaURLsInHTML (htmlText , cleanedUrl , "PackageUUID" );
408+
409+ // Set up the script tags to add to the head
410+ String tagsToInjectToHead = INJECT_HEAD_EPUB_RSO_1
411+ // Slightly change fake script src url with an increasing count to prevent caching of the request
412+ + String .format (INJECT_HEAD_EPUB_RSO_2 , ++mEpubRsoInjectCounter );
413+ // Checks for the existance of MathML => request MathJax payload
414+ if (newHtml .contains ("<math" )) {
415+ tagsToInjectToHead += INJECT_HEAD_MATHJAX ;
416+ }
417+
418+ newHtml = HTMLUtil .htmlByInjectingIntoHead (newHtml , tagsToInjectToHead );
419+ //Log.d(TAG, "HTML head inject: " + newHtml);
420+
421+ data = new ByteArrayInputStream (newHtml .getBytes ());
321422 } catch (IOException e ) {
322423 Log .e (TAG , "" +e .getMessage (), e );
323424 }
0 commit comments