diff --git a/.travis.yml b/.travis.yml index 675ec9572..97a89c460 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,13 +6,11 @@ before_install: android: components: - - build-tools-27.0.3 - - android-27 - - android-19 + - android-28 - extra-android-m2repository licenses: - android-sdk-license-.+ script: - ./gradlew checkstyle build \ No newline at end of file + ./gradlew build \ No newline at end of file diff --git a/FolioReader.iml b/FolioReader.iml deleted file mode 100644 index b07ef0401..000000000 --- a/FolioReader.iml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/README.md b/README.md index 7992389b4..f99023a76 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ FolioReader-Android is an ePub reader written in Java. - [x] Add Notes to a Highlight - [ ] Better Documentation - [x] Last Read Position Listener +- [x] Horizontal reading ## Demo ##### Custom Fonts @@ -35,12 +36,14 @@ FolioReader-Android is an ePub reader written in Java. ![Media Overlay](https://cloud.githubusercontent.com/assets/1277242/19012908/d61f3ce2-87df-11e6-8652-d72b6a1ad9a3.gif) ### Gradle -Add following dependency to your app build.gradle + +Add following dependency to your app build.gradle: + ``` java -compile 'com.folioreader:folioreader:0.3.11' +compile 'com.folioreader:folioreader:0.4.0' ``` -Add maven repository to your top level build.gradle +Add maven repository to your top level build.gradle: ```groovy allprojects { @@ -54,32 +57,50 @@ allprojects { ### Usage -First add activity tag for FolioActivity in your AndroidManifest.xml +First add permissions and activity tag for `FolioActivity` in your `AndroidManifest.xml`: ```xml - + + + + + + + + + ... + + + + ... + + + + ``` -To use FolioReader, get singleton object of **FolioReader**. +**Note: In case if you are upgrading to 0.4.0 and above don't forget to remove `android:configChanges="orientation|screenSize"` from `` tag of `FolioActivity`.** + +Get singleton object of `FolioReader`: ```java FolioReader folioReader = FolioReader.getInstance(getApplicationContext()); ``` -Call the function openBook(). +Call the function `openBook()`: -##### opening book from assets +##### opening book from assets - ```java -folioReader.openBook("file:///android_asset/adventures.epub"); +folioReader.openBook("file:///android_asset/TheSilverChair.epub"); ``` -##### opening book from raw +##### opening book from raw - ```java -folioReader.openBook(R.raw.barrett); +folioReader.openBook(R.raw.adventures); ``` ## WIKI diff --git a/build.gradle b/build.gradle index 4ea73c138..7c5f8f107 100644 --- a/build.gradle +++ b/build.gradle @@ -1,22 +1,22 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + buildscript { - ext.KOTLIN_VERSION= '1.2.41' + ext.KOTLIN_VERSION = '1.2.41' ext.ANDROID_LIB_VERSION = '27.1.1' ext.R2_STREAMER_VERSION = '0.1.7' def KOTLIN_VERSION = ext.KOTLIN_VERSION repositories { + google() jcenter() - maven { - url "http://dl.bintray.com/mobisystech/maven" - } - maven { - url 'https://maven.google.com/' - name 'Google' - } } dependencies { - classpath 'com.android.tools.build:gradle:3.1.2' + classpath 'com.android.tools.build:gradle:3.1.3' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION" @@ -26,13 +26,14 @@ buildscript { allprojects { repositories { + google() jcenter() maven { - url "http://dl.bintray.com/mobisystech/maven" - } - maven { - url 'https://maven.google.com/' - name 'Google' + url "http://dl.bintray.com/mobisystech/maven" } } } + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/folioreader/AndroidManifest.xml b/folioreader/AndroidManifest.xml index d62406cb3..12474418c 100644 --- a/folioreader/AndroidManifest.xml +++ b/folioreader/AndroidManifest.xml @@ -3,7 +3,9 @@ package="com.folioreader"> - + \ No newline at end of file diff --git a/folioreader/build.gradle b/folioreader/build.gradle index c96feb6e7..0d64acf77 100644 --- a/folioreader/build.gradle +++ b/folioreader/build.gradle @@ -17,7 +17,7 @@ ext { siteUrl = 'https://github.com/FolioReader/FolioReader-Android' gitUrl = 'https://github.com/FolioReader/FolioReader-Android.git' - libraryVersion = '0.3.11' + libraryVersion = '0.4.0' developerId = 'mobisystech' developerName = 'Folio Reader' @@ -30,14 +30,13 @@ ext { android { useLibrary 'org.apache.http.legacy' - compileSdkVersion 27 - buildToolsVersion "27.0.3" + compileSdkVersion Integer.parseInt(project.ANDROID_COMPILE_SDK_VERSION) defaultConfig { - versionCode 1 - versionName "1.0" - minSdkVersion 14 - targetSdkVersion 27 + minSdkVersion Integer.parseInt(project.ANDROID_MIN_SDK) + targetSdkVersion Integer.parseInt(project.ANDROID_TARGET_SDK_VERSION) + versionCode Integer.parseInt(project.VERSION_CODE) + versionName project.VERSION_NAME } sourceSets { @@ -86,8 +85,7 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation project(':webViewMarker') - //noinspection GradleDependency - implementation 'com.android.support.constraint:constraint-layout:1.1.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation "com.android.support:appcompat-v7:$ANDROID_LIB_VERSION" implementation "com.android.support:recyclerview-v7:$ANDROID_LIB_VERSION" implementation "com.android.support:support-v4:$ANDROID_LIB_VERSION" diff --git a/folioreader/res/drawable/blue_border_background.xml b/folioreader/res/drawable/blue_border_background.xml new file mode 100644 index 000000000..ed411a74c --- /dev/null +++ b/folioreader/res/drawable/blue_border_background.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/folioreader/res/drawable/green_border_background.xml b/folioreader/res/drawable/green_border_background.xml new file mode 100644 index 000000000..0abbd7131 --- /dev/null +++ b/folioreader/res/drawable/green_border_background.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/folioreader/res/drawable/red_border_background.xml b/folioreader/res/drawable/red_border_background.xml new file mode 100644 index 000000000..1c9e10274 --- /dev/null +++ b/folioreader/res/drawable/red_border_background.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/folioreader/res/layout/folio_page_fragment.xml b/folioreader/res/layout/folio_page_fragment.xml index 1ecc3d276..45e2e1e81 100644 --- a/folioreader/res/layout/folio_page_fragment.xml +++ b/folioreader/res/layout/folio_page_fragment.xml @@ -1,15 +1,35 @@ - + android:layout_above="@+id/indicatorLayout"> + + + + + + + + + + + android:paddingBottom="2dp" + android:paddingTop="2dp" + android:visibility="gone"> + + + android:layout_height="203dp"> @@ -21,10 +18,8 @@ android:id="@+id/view_config_ib_night_mode" android:layout_width="0dp" android:layout_height="50dp" - android:adjustViewBounds="true" android:background="@android:color/transparent" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/view_config_ib_day_mode" app:srcCompat="@drawable/icon_moon_sel" /> @@ -33,7 +28,6 @@ android:layout_width="0dp" android:layout_height="1dp" android:background="@color/grey_color" - android:visibility="visible" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/view_config_ib_night_mode" /> @@ -46,8 +40,6 @@ android:text="@string/andada" android:textSize="17sp" app:layout_constraintEnd_toStartOf="@+id/view_config_font_lato" - app:layout_constraintHorizontal_bias="0.5" - app:layout_constraintHorizontal_chainStyle="spread" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/view3" /> @@ -59,9 +51,7 @@ android:text="@string/lato" android:textSize="17sp" app:folio_font="@string/lato_font" - app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toStartOf="@+id/view_config_font_lora" - app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/view_config_font_andada" app:layout_constraintTop_toBottomOf="@+id/view3" /> @@ -74,7 +64,6 @@ android:textSize="17sp" app:folio_font="@string/lora_font" app:layout_constraintEnd_toStartOf="@+id/view_config_font_raleway" - app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/view_config_font_lato" app:layout_constraintTop_toBottomOf="@+id/view3" /> @@ -87,7 +76,6 @@ android:textSize="17sp" app:folio_font="@string/raleway_font" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toEndOf="@+id/view_config_font_lora" app:layout_constraintTop_toBottomOf="@+id/view3" /> @@ -96,9 +84,7 @@ android:layout_width="0dp" android:layout_height="1dp" android:background="@color/grey_color" - android:visibility="visible" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintHorizontal_bias="0.483" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/view_config_font_lato" /> @@ -106,36 +92,28 @@ android:id="@+id/view_config_iv_label_font_small" android:layout_width="36dp" android:layout_height="36dp" - android:layout_marginBottom="8dp" - android:layout_marginEnd="8dp" - android:layout_marginLeft="8dp" - android:layout_marginRight="8dp" - android:layout_marginStart="8dp" - android:layout_marginTop="8dp" + android:layout_margin="8dp" android:adjustViewBounds="false" android:scaleType="center" android:tint="@color/grey_color" + app:layout_constraintBottom_toTopOf="@id/view5" app:layout_constraintEnd_toStartOf="@+id/view_config_font_size_seek_bar" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/view_config_font_andada" + app:layout_constraintTop_toBottomOf="@+id/view4" app:srcCompat="@drawable/ic_format_font_black_24dp" /> + app:layout_constraintTop_toBottomOf="@+id/view4" /> + app:layout_constraintTop_toBottomOf="@+id/view_config_font_size_seek_bar" /> + app:layout_constraintTop_toBottomOf="@+id/view5" /> + app:layout_constraintStart_toEndOf="@+id/buttonVertical" + app:layout_constraintTop_toBottomOf="@+id/view5" /> - \ No newline at end of file + diff --git a/folioreader/res/layout/view_loading.xml b/folioreader/res/layout/view_loading.xml new file mode 100644 index 000000000..d6842d3a8 --- /dev/null +++ b/folioreader/res/layout/view_loading.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/folioreader/res/layout/view_webview_pager.xml b/folioreader/res/layout/view_webview_pager.xml new file mode 100644 index 000000000..e94ed64b1 --- /dev/null +++ b/folioreader/res/layout/view_webview_pager.xml @@ -0,0 +1,20 @@ + + + + + + \ No newline at end of file diff --git a/folioreader/res/values/colors.xml b/folioreader/res/values/colors.xml index 60533744e..e1e86d5fc 100644 --- a/folioreader/res/values/colors.xml +++ b/folioreader/res/values/colors.xml @@ -17,4 +17,5 @@ #FFFFFF #F02814 #a8a8a8 + #131313 \ No newline at end of file diff --git a/folioreader/res/values/strings.xml b/folioreader/res/values/strings.xml index 0ae3da5f8..182fa14f2 100644 --- a/folioreader/res/values/strings.xml +++ b/folioreader/res/values/strings.xml @@ -66,10 +66,11 @@ please wait till audio is been parsed, Retry after some time javascript:alert(audioMarkID(\'epub-media-overlay-playing\',\'%s\')) javascript:setMediaOverlayStyle(\'%s\') - javascript:gotoHighlight(\'%s\') + javascript:goToAnchor(\'%s\') + javascript:goToHighlight(\'%s\') javascript:getHighlightString(\'%s\') javascript:setHighlightStyle(\'%s\'); - ]]> + ]]> ]]> %s]]> %s]]> @@ -91,6 +92,10 @@ Dictionary Wikipedia Cannot open epub it needs storage access ! - horizontal - vertical + Horizontal + Vertical + + application/xhtml+xml + text/html + BackCompat diff --git a/folioreader/res/xml/network_security_config.xml b/folioreader/res/xml/network_security_config.xml new file mode 100644 index 000000000..85285232d --- /dev/null +++ b/folioreader/res/xml/network_security_config.xml @@ -0,0 +1,6 @@ + + + + 127.0.0.1 + + \ No newline at end of file diff --git a/folioreader/src/main/assets/css/Style.css b/folioreader/src/main/assets/css/Style.css index 652c51aa6..400acc4b3 100755 --- a/folioreader/src/main/assets/css/Style.css +++ b/folioreader/src/main/assets/css/Style.css @@ -33,20 +33,24 @@ footer, header, hgroup, menu, nav, section { /* ePUB */ html { -webkit-text-size-adjust: none; /* Never autoresize text */ + margin: 0 !important; padding: 0 0 !important; } body { - padding: 40px 20px !important; + margin: 0 !important; + padding: 20px 20px !important; overflow: !important; } /* Custom padding for tablets */ +/* @media only screen and (min-device-width: 768px){ body { padding: 60px 80px !important; } } +*/ /* Table */ table { @@ -192,7 +196,6 @@ html .highlight_yellow, html .highlight_green, html .highlight_blue, html .highl */ html { - -webkit-transition: all 0.6s ease; background-color: #FFFFFF !important; } diff --git a/folioreader/src/main/assets/js/Bridge.js b/folioreader/src/main/assets/js/Bridge.js index b2b3b0011..07229dd90 100755 --- a/folioreader/src/main/assets/js/Bridge.js +++ b/folioreader/src/main/assets/js/Bridge.js @@ -120,8 +120,8 @@ var getRectForSelectedText = function(elm) { // Method that call that a hightlight was clicked // with URL scheme and rect informations var callHighlightURL = function(elm) { - event.stopPropagation(); - var URLBase = "highlight://"; + event.stopPropagation(); + var URLBase = "highlight://"; var currentHighlightRect = getRectForSelectedText(elm); thisHighlight = elm; @@ -233,32 +233,52 @@ function playAudioFragmentID(fragmentID) { window.location = URLBase + (fragmentID?encodeURIComponent(fragmentID):"") } +function bodyOrHtml() { + if ('scrollingElement' in document) { + return document.scrollingElement; + } + // Fallback for legacy browsers + if (navigator.userAgent.indexOf('WebKit') != -1) { + return document.body; + } + return document.documentElement; +} + /** Go To Element - scrolls the webview to the requested element */ -function goToEl(el) { - var top = document.body.scrollTop; - var elTop = el.offsetTop - 20; - var bottom = window.innerHeight + document.body.scrollTop; - var elBottom = el.offsetHeight + el.offsetTop + 60 - - if(elBottom > bottom || elTop < top) { - document.body.scrollTop = el.offsetTop - 20 +function goToElement(element) { + + var scrollingElement = bodyOrHtml(); + var top = scrollingElement.scrollTop; + var elementTop = element.offsetTop - 20; + var bottom = window.innerHeight + top; + var elementBottom = element.offsetHeight + element.offsetTop + 60; + + //console.log(window); + //console.log("-> top = " + top); + //console.log("-> elementTop = " + elementTop); + //console.log("-> bottom = " + bottom); + //console.log("-> elementBottom = " + elementBottom); + + if (FolioPageFragment.getDirection() == "VERTICAL" && + (elementBottom > bottom || elementTop < top)) { + + var newScrollTop = elementTop; + //console.log("-> newScrollTop = " + newScrollTop); + scrollingElement.scrollTop = newScrollTop; + + } else if (FolioPageFragment.getDirection() == "HORIZONTAL" && top == 0) { + + var clientWidth = document.documentElement.clientWidth; + var pageIndex = Math.floor(element.offsetLeft / clientWidth); + var newScrollLeft = clientWidth * pageIndex; + //console.log("-> newScrollLeft = " + newScrollLeft); + scrollingElement.scrollLeft = newScrollLeft; + WebViewPager.setCurrentPage(pageIndex); } - /* Set scroll left in case horz scroll is activated. - - The following works because el.offsetTop accounts for each page turned - as if the document was scrolling vertical. We then divide by the window - height to figure out what page the element should appear on and set scroll left - to scroll to that page. - */ - if( document.body.scrollTop == 0 ){ - var elLeft = document.body.clientWidth * Math.floor(el.offsetTop / window.innerHeight); - document.body.scrollLeft = elLeft; - } - - return el; + return element; } /** @@ -272,6 +292,236 @@ function removeAllClasses(className) { } } +//For testing purpose only +function sleep(seconds) +{ + var e = new Date().getTime() + (seconds * 1000); + while (new Date().getTime() <= e) {} +} + +// Mock objects for testing purpose +/*var FolioPageFragment = { + + setHorizontalPageCount : function(pageCount) { + console.warn("-> Mock call to FolioPageFragment.setHorizontalPageCount(" + pageCount + ")"); + }, + + storeFirstVisibleSpan : function(usingId, value) { + console.warn("-> Mock call to FolioPageFragment.storeFirstVisibleSpan(" + usingId + ", " + value + ")"); + }, + + getDirection : function() { + //var direction = "VERTICAL"; + var direction = "HORIZONTAL"; + console.warn("-> Mock call to FolioPageFragment.getDirection(), return " + direction); + return direction; + } +}; + +var FolioWebView = { + + setCompatMode : function(compatMode) { + console.warn("-> Mock call to FolioWebView.setCompatMode(" + compatMode + ")"); + } +}; + +var WebViewPager = { + + setCurrentPage : function(pageIndex) { + console.warn("-> Mock call to WebViewPager.setCurrentPage(" + pageIndex + ")"); + }, + + setPageToLast : function() { + console.warn("-> Mock call to WebViewPager.setPageToLast()"); + }, + + setPageToFirst : function() { + console.warn("-> Mock call to WebViewPager.setPageToFirst()"); + } +}; + +var LoadingView = { + + show : function() { + console.warn("-> Mock call to LoadingView.show()"); + }, + + hide : function() { + console.warn("-> Mock call to LoadingView.hide()"); + }, + + visible : function() { + console.warn("-> Mock call to LoadingView.visible()"); + }, + + invisible : function() { + console.warn("-> Mock call to LoadingView.invisible()"); + } +};*/ + +// Testing purpose calls +function test() { + + getCompatMode(); + wrappingSentencesWithinPTags(); + + if (FolioPageFragment.getDirection() == "HORIZONTAL") + initHorizontalDirection(); +} + +function scrollToLast() { + console.log("-> scrollToLast"); + + var direction = FolioPageFragment.getDirection(); + var scrollingElement = bodyOrHtml(); + + if (direction == "VERTICAL") { + scrollingElement.scrollTop = + scrollingElement.scrollHeight - document.documentElement.clientHeight; + + } else if (direction == "HORIZONTAL") { + scrollingElement.scrollLeft = + scrollingElement.scrollWidth - document.documentElement.clientWidth; + WebViewPager.setPageToLast(); + } + + LoadingView.hide(); +} + +function scrollToFirst() { + console.log("-> scrollToFirst"); + + var direction = FolioPageFragment.getDirection(); + var scrollingElement = bodyOrHtml(); + + if (direction == "VERTICAL") { + scrollingElement.scrollTop = 0; + + } else if (direction == "HORIZONTAL") { + scrollingElement.scrollLeft = 0; + WebViewPager.setPageToFirst(); + } + + LoadingView.hide(); +} + +function getCompatMode() { + FolioWebView.setCompatMode(document.compatMode); +} + +var scrollWidth; +var horizontalInterval; +var horizontalIntervalPeriod = 1000; +var horizontalIntervalCounter = 0; +var horizontalIntervalLimit = 3000; + +function horizontalRecheck() { + + horizontalIntervalCounter += horizontalIntervalPeriod; + + if (window.scrollWidth != document.documentElement.scrollWidth) { + // Rare condition + // This might happen when document.documentElement.scrollWidth gives incorrect value + // when the webview is busy re-drawing contents. + //console.log("-> horizontalIntervalCounter = " + horizontalIntervalCounter); + console.warn("-> scrollWidth changed from " + window.scrollWidth + " to " + + document.documentElement.scrollWidth); + postInitHorizontalDirection(); + } + + if (horizontalIntervalCounter >= horizontalIntervalLimit) + clearInterval(horizontalInterval); +} + +function initHorizontalDirection() { + + preInitHorizontalDirection(); + postInitHorizontalDirection(); + + horizontalInterval = setInterval(horizontalRecheck, horizontalIntervalPeriod); +} + +function preInitHorizontalDirection() { + + //console.log(window); + //console.log("-> " + document.getElementsByTagName('title')[0].innerText); + var htmlElement = document.getElementsByTagName('html')[0]; + var bodyElement = document.getElementsByTagName('body')[0]; + + // Required when initHorizontalDirection() is called multiple times. + // Currently it is called only once per page. + htmlElement.style.width = null; + bodyElement.style.width = null; + htmlElement.style.height = null; + bodyElement.style.height = null; + + var bodyStyle = bodyElement.currentStyle || window.getComputedStyle(bodyElement); + var paddingTop = parseInt(bodyStyle.paddingTop, 10); + var paddingRight = parseInt(bodyStyle.paddingRight, 10); + var paddingBottom = parseInt(bodyStyle.paddingBottom, 10); + var paddingLeft = parseInt(bodyStyle.paddingLeft, 10); + //console.log("-> padding = " + paddingTop + ", " + paddingRight + ", " + paddingBottom + ", " + paddingLeft); + + //document.documentElement.clientWidth is window.innerWidth excluding x scrollbar width + var pageWidth = document.documentElement.clientWidth - (paddingLeft + paddingRight); + //document.documentElement.clientHeight is window.innerHeight excluding y scrollbar height + var pageHeight = document.documentElement.clientHeight - (paddingTop + paddingBottom); + + bodyElement.style.webkitColumnGap = (paddingLeft + paddingRight) + 'px'; + bodyElement.style.webkitColumnWidth = pageWidth + 'px'; + + //console.log("-> window.innerWidth = " + window.innerWidth); + //console.log("-> window.innerHeight = " + window.innerHeight); + //console.log("-> clientWidth = " + document.documentElement.clientWidth); + //console.log("-> clientHeight = " + document.documentElement.clientHeight); + //console.log("-> bodyElement.offsetWidth = " + bodyElement.offsetWidth); + //console.log("-> bodyElement.offsetHeight = " + bodyElement.offsetHeight); + //console.log("-> pageWidth = " + pageWidth); + //console.log("-> pageHeight = " + pageHeight); + + htmlElement.style.height = (pageHeight + (paddingTop + paddingBottom)) + 'px'; + bodyElement.style.height = pageHeight + 'px'; +} + +function postInitHorizontalDirection() { + + var htmlElement = document.getElementsByTagName('html')[0]; + var bodyElement = document.getElementsByTagName('body')[0]; + var bodyStyle = bodyElement.currentStyle || window.getComputedStyle(bodyElement); + var paddingTop = parseInt(bodyStyle.paddingTop, 10); + var paddingRight = parseInt(bodyStyle.paddingRight, 10); + var paddingBottom = parseInt(bodyStyle.paddingBottom, 10); + var paddingLeft = parseInt(bodyStyle.paddingLeft, 10); + var clientWidth = document.documentElement.clientWidth; + + var scrollWidth = document.documentElement.scrollWidth; + //console.log("-> document.documentElement.offsetWidth = " + document.documentElement.offsetWidth); + if (scrollWidth > clientWidth + && scrollWidth > document.documentElement.offsetWidth) { + scrollWidth += paddingRight; + } + var newBodyWidth = scrollWidth - (paddingLeft + paddingRight); + window.scrollWidth = scrollWidth; + + htmlElement.style.width = scrollWidth + 'px'; + bodyElement.style.width = newBodyWidth + 'px'; + + // pageCount deliberately rounded instead of ceiling to avoid any unexpected error + var pageCount = Math.round(scrollWidth / clientWidth); + var pageCountFloat = scrollWidth / clientWidth; + + if (pageCount != pageCountFloat) { + console.warn("-> pageCount = " + pageCount + ", pageCountFloat = " + pageCountFloat + + ", Something wrong in pageCount calculation"); + } + + //console.log("-> scrollWidth = " + scrollWidth); + //console.log("-> newBodyWidth = " + newBodyWidth); + //console.log("-> pageCount = " + pageCount); + + FolioPageFragment.setHorizontalPageCount(pageCount); +} + /** Audio Mark ID - marks an element with an ID with the given class and scrolls to it */ @@ -282,7 +532,7 @@ function audioMarkID(className, id) { audioMarkClass = className var el = document.getElementById(id); - goToEl(el); + goToElement(el); el.classList.add(className) } @@ -293,9 +543,9 @@ function setMediaOverlayStyle(style){ function setMediaOverlayStyleColors(color, colorHighlight) { var stylesheet = document.styleSheets[document.styleSheets.length-1]; - stylesheet.insertRule(".mediaOverlayStyle0 span.epub-media-overlay-playing { background: "+colorHighlight+" !important }") - stylesheet.insertRule(".mediaOverlayStyle1 span.epub-media-overlay-playing { border-color: "+color+" !important }") - stylesheet.insertRule(".mediaOverlayStyle2 span.epub-media-overlay-playing { color: "+color+" !important }") +// stylesheet.insertRule(".mediaOverlayStyle0 span.epub-media-overlay-playing { background: "+colorHighlight+" !important }") +// stylesheet.insertRule(".mediaOverlayStyle1 span.epub-media-overlay-playing { border-color: "+color+" !important }") +// stylesheet.insertRule(".mediaOverlayStyle2 span.epub-media-overlay-playing { color: "+color+" !important }") } var currentIndex = -1; @@ -374,7 +624,7 @@ function getSentenceWithIndex(className) { var text = sentence.innerText || sentence.textContent; - goToEl(sentence); + goToElement(sentence); if (audioMarkClass){ removeAllClasses(audioMarkClass); @@ -617,49 +867,53 @@ function scrollToSpan(usingId, value) { if (usingId) { var spanElement = document.getElementById(value); if (spanElement) - goToEl(spanElement); + goToElement(spanElement); } else { var spanCollection = document.getElementsByTagName("span"); if (spanCollection.length == 0 || value < 0 || value >= spanCollection.length - || value == null) + || value == null) { + LoadingView.hide(); return; - goToEl(spanCollection[value]); + } + goToElement(spanCollection[value]); } + + LoadingView.hide(); } // Class based onClick listener function addClassBasedOnClickListener(schemeName, querySelector, attributeName, selectAll) { - if (selectAll) { - // Get all elements with the given query selector - var elements = document.querySelectorAll(querySelector); - for (elementIndex = 0; elementIndex < elements.length; elementIndex++) { - var element = elements[elementIndex]; - addClassBasedOnClickListenerToElement(element, schemeName, attributeName); - } - } else { - // Get the first element with the given query selector - var element = document.querySelector(querySelector); - addClassBasedOnClickListenerToElement(element, schemeName, attributeName); - } + if (selectAll) { + // Get all elements with the given query selector + var elements = document.querySelectorAll(querySelector); + for (elementIndex = 0; elementIndex < elements.length; elementIndex++) { + var element = elements[elementIndex]; + addClassBasedOnClickListenerToElement(element, schemeName, attributeName); + } + } else { + // Get the first element with the given query selector + var element = document.querySelector(querySelector); + addClassBasedOnClickListenerToElement(element, schemeName, attributeName); + } } function addClassBasedOnClickListenerToElement(element, schemeName, attributeName) { - // Get the content from the given attribute name - var attributeContent = element.getAttribute(attributeName); - // Add the on click logic - element.setAttribute("onclick", "onClassBasedListenerClick(\"" + schemeName + "\", \"" + encodeURIComponent(attributeContent) + "\");"); + // Get the content from the given attribute name + var attributeContent = element.getAttribute(attributeName); + // Add the on click logic + element.setAttribute("onclick", "onClassBasedListenerClick(\"" + schemeName + "\", \"" + encodeURIComponent(attributeContent) + "\");"); } var onClassBasedListenerClick = function(schemeName, attributeContent) { - // Prevent the browser from performing the default on click behavior - event.preventDefault(); - // Don't pass the click event to other elemtents - event.stopPropagation(); - // Create parameters containing the click position inside the web view. - var positionParameterString = "/clientX=" + event.clientX + "&clientY=" + event.clientY; - // Set the custom link URL to the event - window.location = schemeName + "://" + attributeContent + positionParameterString; + // Prevent the browser from performing the default on click behavior + event.preventDefault(); + // Don't pass the click event to other elemtents + event.stopPropagation(); + // Create parameters containing the click position inside the web view. + var positionParameterString = "/clientX=" + event.clientX + "&clientY=" + event.clientY; + // Set the custom link URL to the event + window.location = schemeName + "://" + attributeContent + positionParameterString; } function getHighlightString(style) { @@ -681,11 +935,20 @@ function getHighlightString(style) { Highlight.getHighlightJson(JSON.stringify(params)); } -function gotoHighlight(highlightId){ - var element = document.getElementById(highlightId.toString()); - if(element != null) { - goToEl(element); - } +function goToHighlight(highlightId){ + var element = document.getElementById(highlightId.toString()); + if (element) + goToElement(element); + + LoadingView.hide(); +} + +function goToAnchor(anchorId) { + var element = document.getElementById(anchorId); + if (element) + goToElement(element); + + LoadingView.hide(); } $(function(){ diff --git a/folioreader/src/main/java/com/folioreader/Config.java b/folioreader/src/main/java/com/folioreader/Config.java index b7e7a1d49..f0046f065 100644 --- a/folioreader/src/main/java/com/folioreader/Config.java +++ b/folioreader/src/main/java/com/folioreader/Config.java @@ -2,205 +2,274 @@ import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; import org.json.JSONObject; /** - * Created by mahavir on 4/12/16. + * Configuration class for FolioReader. */ +@SuppressWarnings("PMD.AvoidDuplicateLiterals") public class Config implements Parcelable { + + private static final String LOG_TAG = Config.class.getSimpleName(); public static final String INTENT_CONFIG = "config"; + public static final String EXTRA_OVERRIDE_CONFIG = "com.folioreader.extra.OVERRIDE_CONFIG"; public static final String CONFIG_FONT = "font"; public static final String CONFIG_FONT_SIZE = "font_size"; - public static final String CONFIG_IS_NIGHTMODE = "is_night_mode"; - public static final String CONFIG_IS_THEMECOLOR = "theme_color"; + public static final String CONFIG_IS_NIGHT_MODE = "is_night_mode"; + public static final String CONFIG_IS_THEME_COLOR = "theme_color"; public static final String CONFIG_IS_TTS = "is_tts"; + public static final String CONFIG_ALLOWED_DIRECTION = "allowed_direction"; + public static final String CONFIG_DIRECTION = "direction"; public static final String INTENT_PORT = "port"; - private int font; - private int fontSize; + private static final AllowedDirection DEFAULT_ALLOWED_DIRECTION = AllowedDirection.ONLY_VERTICAL; + private static final Direction DEFAULT_DIRECTION = Direction.VERTICAL; + + private int font = 3; + private int fontSize = 2; private boolean nightMode; - private int themeColor; - private boolean showTts; + private int themeColor = R.color.app_green; + private boolean showTts = true; + private AllowedDirection allowedDirection = DEFAULT_ALLOWED_DIRECTION; + private Direction direction = DEFAULT_DIRECTION; + + /** + * Reading modes available + */ + public enum AllowedDirection { + ONLY_VERTICAL, ONLY_HORIZONTAL, VERTICAL_AND_HORIZONTAL + } + + /** + * Reading directions + */ + public enum Direction { + VERTICAL, HORIZONTAL + } + + public static final Creator CREATOR = new Creator() { + @Override + public Config createFromParcel(Parcel in) { + return new Config(in); + } + + @Override + public Config[] newArray(int size) { + return new Config[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(font); + dest.writeInt(fontSize); + dest.writeByte((byte) (nightMode ? 1 : 0)); + dest.writeInt(themeColor); + dest.writeByte((byte) (showTts ? 1 : 0)); + dest.writeString(allowedDirection.toString()); + dest.writeString(direction.toString()); + } - public Config(int font, int fontSize, boolean nightMode, int iconcolor, boolean showTts) { + protected Config(Parcel in) { + font = in.readInt(); + fontSize = in.readInt(); + nightMode = in.readByte() != 0; + themeColor = in.readInt(); + showTts = in.readByte() != 0; + allowedDirection = getAllowedDirectionFromString(LOG_TAG, in.readString()); + direction = getDirectionFromString(LOG_TAG, in.readString()); + } + + public Config() { + } + + public Config(int font, int fontSize, boolean nightMode, int themeColor, boolean showTts, + AllowedDirection allowedDirection, Direction direction) { this.font = font; this.fontSize = fontSize; this.nightMode = nightMode; - this.themeColor = iconcolor; + this.themeColor = themeColor; this.showTts = showTts; - } - - private Config(ConfigBuilder configBuilder) { - font = configBuilder.mFont; - fontSize = configBuilder.mFontSize; - nightMode = configBuilder.mNightMode; - themeColor = configBuilder.mThemeColor; - showTts = configBuilder.mShowTts; + setAllowedDirection(allowedDirection); + setDirection(direction); } public Config(JSONObject jsonObject) { font = jsonObject.optInt(CONFIG_FONT); fontSize = jsonObject.optInt(CONFIG_FONT_SIZE); - nightMode = jsonObject.optBoolean(CONFIG_IS_NIGHTMODE); - themeColor = jsonObject.optInt(CONFIG_IS_THEMECOLOR); + nightMode = jsonObject.optBoolean(CONFIG_IS_NIGHT_MODE); + themeColor = jsonObject.optInt(CONFIG_IS_THEME_COLOR); showTts = jsonObject.optBoolean(CONFIG_IS_TTS); + allowedDirection = getAllowedDirectionFromString(LOG_TAG, + jsonObject.optString(CONFIG_ALLOWED_DIRECTION)); + direction = getDirectionFromString(LOG_TAG, jsonObject.optString(CONFIG_DIRECTION)); } - private Config() { - fontSize = 2; - font = 3; - nightMode = false; - themeColor = R.color.app_green; - showTts = true; + public static Direction getDirectionFromString(String LOG_TAG, String directionString) { + + switch (directionString) { + case "VERTICAL": + return Direction.VERTICAL; + case "HORIZONTAL": + return Direction.HORIZONTAL; + default: + Log.w(LOG_TAG, "-> Illegal argument directionString = `" + directionString + + "`, defaulting direction to " + DEFAULT_DIRECTION); + return DEFAULT_DIRECTION; + } } - private Config(Parcel in) { - readFromParcel(in); + public static AllowedDirection getAllowedDirectionFromString(String LOG_TAG, + String allowedDirectionString) { + + switch (allowedDirectionString) { + case "ONLY_VERTICAL": + return AllowedDirection.ONLY_VERTICAL; + case "ONLY_HORIZONTAL": + return AllowedDirection.ONLY_HORIZONTAL; + case "VERTICAL_AND_HORIZONTAL": + return AllowedDirection.VERTICAL_AND_HORIZONTAL; + default: + Log.w(LOG_TAG, "-> Illegal argument allowedDirectionString = `" + + allowedDirectionString + "`, defaulting allowedDirection to " + + DEFAULT_ALLOWED_DIRECTION); + return DEFAULT_ALLOWED_DIRECTION; + } } - public int getFont() { return font; } - public void setFont(int font) { + public Config setFont(int font) { this.font = font; + return this; } public int getFontSize() { return fontSize; } - public void setFontSize(int fontSize) { + public Config setFontSize(int fontSize) { this.fontSize = fontSize; + return this; } public boolean isNightMode() { return nightMode; } - public void setNightMode(boolean nightMode) { + public Config setNightMode(boolean nightMode) { this.nightMode = nightMode; + return this; } - public int getThemeColor() { return themeColor; } - public void setThemeColor(int themeColor) { + public Config setThemeColor(int themeColor) { this.themeColor = themeColor; + return this; } public boolean isShowTts() { return showTts; } - public void setShowTts(boolean showTts) { + public Config setShowTts(boolean showTts) { this.showTts = showTts; + return this; } - @Override - - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Config)) return false; - - Config config = (Config) o; - - return font == config.font && fontSize == config.fontSize && nightMode == config.nightMode; - } - - @Override - public int hashCode() { - int result = font; - result = 31 * result - + fontSize; - result = 31 * result - + (nightMode ? 1 : 0); - return result; - } - - @Override - public String toString() { - return "Config{" - + "font=" - + font - + ", fontSize=" + fontSize - + ", nightMode=" + nightMode - + '}'; + public AllowedDirection getAllowedDirection() { + return allowedDirection; } - @Override - public int describeContents() { - return 0; - } + /** + * Set reading direction mode options for users. This method should be called before + * {@link #setDirection(Direction)} as it has higher preference. + * + * @param allowedDirection reading direction mode options for users. Setting to + * {@link AllowedDirection#VERTICAL_AND_HORIZONTAL} users will have + * choice to select the reading direction at runtime. + */ + public Config setAllowedDirection(AllowedDirection allowedDirection) { + + this.allowedDirection = allowedDirection; + + if (allowedDirection == null) { + this.allowedDirection = DEFAULT_ALLOWED_DIRECTION; + direction = DEFAULT_DIRECTION; + Log.w(LOG_TAG, "-> allowedDirection cannot be null, defaulting " + + "allowedDirection to " + DEFAULT_ALLOWED_DIRECTION + " and direction to " + + DEFAULT_DIRECTION); + + } else if (allowedDirection == AllowedDirection.ONLY_VERTICAL && direction != Direction.VERTICAL) { + direction = Direction.VERTICAL; + Log.w(LOG_TAG, "-> allowedDirection is " + allowedDirection + + ", defaulting direction to " + direction); + + } else if (allowedDirection == AllowedDirection.ONLY_HORIZONTAL && direction != Direction.HORIZONTAL) { + direction = Direction.HORIZONTAL; + Log.w(LOG_TAG, "-> allowedDirection is " + allowedDirection + + ", defaulting direction to " + direction); + } - @Override - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(font); - dest.writeInt(fontSize); - dest.writeInt(nightMode ? 1 : 0); - dest.writeInt(themeColor); - dest.writeInt(showTts ? 1 : 0); + return this; } - private void readFromParcel(Parcel in) { - font = in.readInt(); - fontSize = in.readInt(); - nightMode = in.readInt() == 1; - themeColor = in.readInt(); - showTts = in.readInt() == 1; + public Direction getDirection() { + return direction; } - public static final Creator CREATOR = new Creator() { - @Override - public Config createFromParcel(Parcel in) { - return new Config(in); - } - - @Override - public Config[] newArray(int size) { - return new Config[size]; - } - }; - - public static class ConfigBuilder { - private int mFont = 3; - private int mFontSize = 2; - private boolean mNightMode = false; - private int mThemeColor = R.color.app_green; - private boolean mShowTts = true; - - public ConfigBuilder font(int font) { - mFont = font; - return this; - } - - public ConfigBuilder fontSize(int fontSize) { - mFontSize = fontSize; - return this; - } - - public ConfigBuilder nightmode(boolean nightMode) { - mNightMode = nightMode; - return this; - } - - public ConfigBuilder themeColor(int themeColor) { - mThemeColor = themeColor; - return this; - } - - public ConfigBuilder setShowTts(boolean showTts) { - mShowTts = showTts; - return this; + /** + * Set reading direction. This method should be called after + * {@link #setAllowedDirection(AllowedDirection)} as it has lower preference. + * + * @param direction reading direction. + */ + public Config setDirection(Direction direction) { + + if (allowedDirection == AllowedDirection.VERTICAL_AND_HORIZONTAL && direction == null) { + this.direction = DEFAULT_DIRECTION; + Log.w(LOG_TAG, "-> direction cannot be `null` when allowedDirection is " + + allowedDirection + ", defaulting direction to " + this.direction); + + } else if (allowedDirection == AllowedDirection.ONLY_VERTICAL && direction != Direction.VERTICAL) { + this.direction = Direction.VERTICAL; + Log.w(LOG_TAG, "-> direction cannot be `" + direction + "` when allowedDirection is " + + allowedDirection + ", defaulting direction to " + this.direction); + + } else if (allowedDirection == AllowedDirection.ONLY_HORIZONTAL && direction != Direction.HORIZONTAL) { + this.direction = Direction.HORIZONTAL; + Log.w(LOG_TAG, "-> direction cannot be `" + direction + "` when allowedDirection is " + + allowedDirection + ", defaulting direction to " + this.direction); + + } else { + this.direction = direction; } + return this; + } - public Config build() { - return new Config(this); - } + @Override + public String toString() { + return "Config{" + + "font=" + font + + ", fontSize=" + fontSize + + ", nightMode=" + nightMode + + ", themeColor=" + themeColor + + ", showTts=" + showTts + + ", allowedDirection=" + allowedDirection + + ", direction=" + direction + + '}'; } } diff --git a/folioreader/src/main/java/com/folioreader/FolioReader.java b/folioreader/src/main/java/com/folioreader/FolioReader.java index 54c27a9d3..b24159f94 100644 --- a/folioreader/src/main/java/com/folioreader/FolioReader.java +++ b/folioreader/src/main/java/com/folioreader/FolioReader.java @@ -5,8 +5,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.os.Build; -import android.os.Parcelable; import android.support.v4.content.LocalBroadcastManager; import com.folioreader.model.HighLight; @@ -31,6 +29,8 @@ public class FolioReader { private static FolioReader singleton = null; public static final String INTENT_BOOK_ID = "book_id"; private Context context; + private Config config; + private boolean overrideConfig; private OnHighlightListener onHighlightListener; private ReadPositionListener readPositionListener; private ReadPosition readPosition; @@ -99,57 +99,38 @@ public FolioReader openBook(int rawId) { return singleton; } - public FolioReader openBook(String assetOrSdcardPath, Config config) { + public FolioReader openBook(String assetOrSdcardPath, int port) { Intent intent = getIntentFromUrl(assetOrSdcardPath, 0); - intent.putExtra(Config.INTENT_CONFIG, config); - context.startActivity(intent); - return singleton; - } - - public FolioReader openBook(int rawId, Config config) { - Intent intent = getIntentFromUrl(null, rawId); - intent.putExtra(Config.INTENT_CONFIG, config); - context.startActivity(intent); - return singleton; - } - - public FolioReader openBook(String assetOrSdcardPath, Config config, int port) { - Intent intent = getIntentFromUrl(assetOrSdcardPath, 0); - intent.putExtra(Config.INTENT_CONFIG, config); intent.putExtra(Config.INTENT_PORT, port); context.startActivity(intent); return singleton; } - public FolioReader openBook(int rawId, Config config, int port) { + public FolioReader openBook(int rawId, int port) { Intent intent = getIntentFromUrl(null, rawId); - intent.putExtra(Config.INTENT_CONFIG, config); intent.putExtra(Config.INTENT_PORT, port); context.startActivity(intent); return singleton; } - public FolioReader openBook(String assetOrSdcardPath, Config config, int port, String bookId) { + public FolioReader openBook(String assetOrSdcardPath, int port, String bookId) { Intent intent = getIntentFromUrl(assetOrSdcardPath, 0); - intent.putExtra(Config.INTENT_CONFIG, config); intent.putExtra(Config.INTENT_PORT, port); intent.putExtra(INTENT_BOOK_ID, bookId); context.startActivity(intent); return singleton; } - public FolioReader openBook(int rawId, Config config, int port, String bookId) { + public FolioReader openBook(int rawId, int port, String bookId) { Intent intent = getIntentFromUrl(null, rawId); - intent.putExtra(Config.INTENT_CONFIG, config); intent.putExtra(Config.INTENT_PORT, port); intent.putExtra(INTENT_BOOK_ID, bookId); context.startActivity(intent); return singleton; } - public FolioReader openBook(String assetOrSdcardPath, Config config, String bookId) { + public FolioReader openBook(String assetOrSdcardPath, String bookId) { Intent intent = getIntentFromUrl(assetOrSdcardPath, 0); - intent.putExtra(Config.INTENT_CONFIG, config); intent.putExtra(INTENT_BOOK_ID, bookId); context.startActivity(intent); return singleton; @@ -158,9 +139,10 @@ public FolioReader openBook(String assetOrSdcardPath, Config config, String book private Intent getIntentFromUrl(String assetOrSdcardPath, int rawId) { Intent intent = new Intent(context, FolioActivity.class); - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(FolioActivity.EXTRA_READ_POSITION, (Parcelable) readPosition); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(Config.INTENT_CONFIG, config); + intent.putExtra(Config.EXTRA_OVERRIDE_CONFIG, overrideConfig); + intent.putExtra(FolioActivity.EXTRA_READ_POSITION, readPosition); if (rawId != 0) { intent.putExtra(FolioActivity.INTENT_EPUB_SOURCE_PATH, rawId); @@ -176,6 +158,19 @@ private Intent getIntentFromUrl(String assetOrSdcardPath, int rawId) { return intent; } + /** + * Pass your configuration and choose to override it every time or just for first execution. + * @param config custom configuration. + * @param overrideConfig true will override the config, false will use either this + * config if it is null in application context or will fetch previously + * saved one while execution. + */ + public FolioReader setConfig(Config config, boolean overrideConfig) { + this.config = config; + this.overrideConfig = overrideConfig; + return singleton; + } + public FolioReader setOnHighlightListener(OnHighlightListener onHighlightListener) { this.onHighlightListener = onHighlightListener; return singleton; diff --git a/folioreader/src/main/java/com/folioreader/model/ReadPosition.java b/folioreader/src/main/java/com/folioreader/model/ReadPosition.java index f7941ecc5..d0fb1711c 100644 --- a/folioreader/src/main/java/com/folioreader/model/ReadPosition.java +++ b/folioreader/src/main/java/com/folioreader/model/ReadPosition.java @@ -1,5 +1,7 @@ package com.folioreader.model; +import android.os.Parcelable; + import com.folioreader.FolioReader; import com.folioreader.ui.folio.activity.FolioActivity; @@ -10,7 +12,7 @@ * * @author Hrishikesh Kadam on 20/04/2018. */ -public interface ReadPosition { +public interface ReadPosition extends Parcelable { /** * Returns the bookId if sent in {@link FolioReader}'s openBook() else logic defined in diff --git a/folioreader/src/main/java/com/folioreader/model/ReadPositionImpl.java b/folioreader/src/main/java/com/folioreader/model/ReadPositionImpl.java index 601eeae5d..9251a4912 100644 --- a/folioreader/src/main/java/com/folioreader/model/ReadPositionImpl.java +++ b/folioreader/src/main/java/com/folioreader/model/ReadPositionImpl.java @@ -9,6 +9,8 @@ import com.fasterxml.jackson.databind.ObjectWriter; import com.folioreader.util.ObjectMapperSingleton; +import java.io.IOException; + /** * Created by Hrishikesh Kadam on 20/04/2018. */ @@ -48,6 +50,20 @@ public ReadPositionImpl(String bookId, String chapterId, String chapterHref, int this.value = value; } + public static ReadPosition createInstance(String jsonString) { + + ReadPositionImpl readPosition = null; + try { + readPosition = ObjectMapperSingleton.getObjectMapper() + .reader() + .forType(ReadPositionImpl.class) + .readValue(jsonString); + } catch (IOException e) { + Log.e(LOG_TAG, "-> " + e); + } + return readPosition; + } + protected ReadPositionImpl(Parcel in) { bookId = in.readString(); chapterId = in.readString(); diff --git a/folioreader/src/main/java/com/folioreader/ui/base/HtmlUtil.java b/folioreader/src/main/java/com/folioreader/ui/base/HtmlUtil.java index 6a8027bc8..641ddbc78 100644 --- a/folioreader/src/main/java/com/folioreader/ui/base/HtmlUtil.java +++ b/folioreader/src/main/java/com/folioreader/ui/base/HtmlUtil.java @@ -20,41 +20,39 @@ public final class HtmlUtil { * @return modified raw html string */ public static String getHtmlContent(Context context, String htmlContent, Config config) { + String cssPath = String.format(context.getString(R.string.css_tag), "file:///android_asset/css/Style.css"); - String jsPath = String.format(context.getString(R.string.script_tag), - "file:///android_asset/js/jsface.min.js"); - jsPath = - jsPath + String.format(context.getString(R.string.script_tag), - "file:///android_asset/js/jquery-3.1.1.min.js"); - - jsPath = - jsPath + String.format(context.getString(R.string.script_tag), - "file:///android_asset/js/rangy-core.js"); - jsPath = - jsPath + String.format(context.getString(R.string.script_tag), - "file:///android_asset/js/rangy-highlighter.js"); - jsPath = - jsPath + String.format(context.getString(R.string.script_tag), - "file:///android_asset/js/rangy-classapplier.js"); - jsPath = - jsPath + String.format(context.getString(R.string.script_tag), - "file:///android_asset/js/rangy-serializer.js"); - jsPath = - jsPath + String.format(context.getString(R.string.script_tag), - "file:///android_asset/js/rangy-serializer.js"); - jsPath = - jsPath + String.format(context.getString(R.string.script_tag), - "file:///android_asset/js/Bridge.js"); - - jsPath = - jsPath + String.format(context.getString(R.string.script_tag), - "file:///android_asset/android.selection.js"); - jsPath = - jsPath + String.format(context.getString(R.string.script_tag_method_call), - "setMediaOverlayStyleColors('#C0ED72','#C0ED72')"); + "file:///android_asset/js/jsface.min.js") + "\n"; + + jsPath = jsPath + String.format(context.getString(R.string.script_tag), + "file:///android_asset/js/jquery-3.1.1.min.js") + "\n"; + + jsPath = jsPath + String.format(context.getString(R.string.script_tag), + "file:///android_asset/js/rangy-core.js") + "\n"; + + jsPath = jsPath + String.format(context.getString(R.string.script_tag), + "file:///android_asset/js/rangy-highlighter.js") + "\n"; + + jsPath = jsPath + String.format(context.getString(R.string.script_tag), + "file:///android_asset/js/rangy-classapplier.js") + "\n"; + + jsPath = jsPath + String.format(context.getString(R.string.script_tag), + "file:///android_asset/js/rangy-serializer.js") + "\n"; + + jsPath = jsPath + String.format(context.getString(R.string.script_tag), + "file:///android_asset/js/Bridge.js") + "\n"; + + jsPath = jsPath + String.format(context.getString(R.string.script_tag), + "file:///android_asset/android.selection.js") + "\n"; + + jsPath = jsPath + String.format(context.getString(R.string.script_tag_method_call), + "setMediaOverlayStyleColors('#C0ED72','#C0ED72')") + "\n"; + + jsPath = jsPath + + ""; String toInject = "\n" + cssPath + "\n" + jsPath + "\n"; htmlContent = htmlContent.replace("", toInject); diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/activity/ContentHighlightActivity.java b/folioreader/src/main/java/com/folioreader/ui/folio/activity/ContentHighlightActivity.java index 697437069..32735b249 100644 --- a/folioreader/src/main/java/com/folioreader/ui/folio/activity/ContentHighlightActivity.java +++ b/folioreader/src/main/java/com/folioreader/ui/folio/activity/ContentHighlightActivity.java @@ -1,8 +1,11 @@ package com.folioreader.ui.folio.activity; +import android.content.res.TypedArray; import android.graphics.Color; +import android.os.Build; import android.os.Bundle; import android.support.v4.app.FragmentTransaction; +import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.ImageView; @@ -10,11 +13,11 @@ import com.folioreader.Config; import com.folioreader.Constants; +import com.folioreader.FolioReader; import com.folioreader.R; import com.folioreader.ui.folio.fragment.HighlightFragment; import com.folioreader.ui.tableofcontents.view.TableOfContentFragment; import com.folioreader.util.AppUtil; -import com.folioreader.FolioReader; import com.folioreader.util.UiUtil; public class ContentHighlightActivity extends AppCompatActivity { @@ -34,8 +37,10 @@ protected void onCreate(Bundle savedInstanceState) { } private void initViews() { + UiUtil.setColorToImage(this, mConfig.getThemeColor(), ((ImageView) findViewById(R.id.btn_close)).getDrawable()); findViewById(R.id.layout_content_highlights).setBackgroundDrawable(UiUtil.getShapeDrawable(this, mConfig.getThemeColor())); + if (mIsNightMode) { findViewById(R.id.toolbar).setBackgroundColor(Color.BLACK); findViewById(R.id.btn_contents).setBackgroundDrawable(UiUtil.convertColorIntoStateDrawable(this, mConfig.getThemeColor(), R.color.black)); @@ -50,6 +55,17 @@ private void initViews() { findViewById(R.id.btn_highlights).setBackgroundDrawable(UiUtil.convertColorIntoStateDrawable(this, mConfig.getThemeColor(), R.color.white)); } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + int color; + if (mIsNightMode) { + color = ContextCompat.getColor(this, R.color.black); + } else { + int[] attrs = {android.R.attr.navigationBarColor}; + TypedArray typedArray = getTheme().obtainStyledAttributes(attrs); + color = typedArray.getColor(0, ContextCompat.getColor(this, R.color.white)); + } + getWindow().setNavigationBarColor(color); + } loadContentFragment(); findViewById(R.id.btn_close).setOnClickListener(new View.OnClickListener() { diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/activity/FolioActivity.java b/folioreader/src/main/java/com/folioreader/ui/folio/activity/FolioActivity.java index 07d57f19d..98486af95 100644 --- a/folioreader/src/main/java/com/folioreader/ui/folio/activity/FolioActivity.java +++ b/folioreader/src/main/java/com/folioreader/ui/folio/activity/FolioActivity.java @@ -16,8 +16,11 @@ package com.folioreader.ui.folio.activity; import android.Manifest; +import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.TypedArray; +import android.os.Build; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.app.ActivityCompat; @@ -33,9 +36,7 @@ import com.folioreader.R; import com.folioreader.model.HighlightImpl; import com.folioreader.model.ReadPosition; -import com.folioreader.model.event.AnchorIdEvent; import com.folioreader.model.event.MediaOverlayPlayPauseEvent; -import com.folioreader.model.event.WebViewPosition; import com.folioreader.ui.folio.adapter.FolioPageFragmentAdapter; import com.folioreader.ui.folio.fragment.FolioPageFragment; import com.folioreader.ui.folio.presenter.MainMvpView; @@ -46,9 +47,9 @@ import com.folioreader.view.DirectionalViewpager; import com.folioreader.view.FolioToolbar; import com.folioreader.view.FolioToolbarCallback; +import com.folioreader.view.FolioWebView; import com.folioreader.view.MediaControllerCallback; import com.folioreader.view.MediaControllerView; -import com.folioreader.view.ObservableWebView; import org.greenrobot.eventbus.EventBus; import org.readium.r2_streamer.model.container.Container; @@ -69,19 +70,20 @@ public class FolioActivity extends AppCompatActivity - implements FolioPageFragment.FolioPageFragmentCallback, - ObservableWebView.ToolBarListener, - ConfigBottomSheetDialogFragment.ConfigDialogCallback, + implements FolioActivityCallback, + FolioWebView.ToolBarListener, MainMvpView, MediaControllerCallback, FolioToolbarCallback { - private static final String TAG = "FolioActivity"; + private static final String LOG_TAG = "FolioActivity"; public static final String INTENT_EPUB_SOURCE_PATH = "com.folioreader.epub_asset_path"; public static final String INTENT_EPUB_SOURCE_TYPE = "epub_source_type"; public static final String INTENT_HIGHLIGHTS_LIST = "highlight_list"; public static final String EXTRA_READ_POSITION = "com.folioreader.extra.READ_POSITION"; + private static final String BUNDLE_READ_POSITION_CONFIG_CHANGE = "BUNDLE_READ_POSITION_CONFIG_CHANGE"; + private static final String BUNDLE_TOOLBAR_IS_VISIBLE = "BUNDLE_TOOLBAR_IS_VISIBLE"; public enum EpubSourceType { RAW, @@ -99,22 +101,27 @@ public enum EpubSourceType { private int mChapterPosition; private FolioPageFragmentAdapter mFolioPageFragmentAdapter; private ReadPosition entryReadPosition; + private ReadPosition lastReadPosition; + private Bundle outState; + private Bundle savedInstanceState; private List mSpineReferenceList = new ArrayList<>(); private EpubServer mEpubServer; - private Config mConfig; private String mBookId; private String mEpubFilePath; private EpubSourceType mEpubSourceType; int mEpubRawId = 0; private MediaControllerView mediaControllerView; + private Config.Direction direction = Config.Direction.VERTICAL; @Override protected void onCreate(Bundle savedInstanceState) { - setConfig(); super.onCreate(savedInstanceState); + setConfig(savedInstanceState); + setContentView(R.layout.folio_activity); + this.savedInstanceState = savedInstanceState; mBookId = getIntent().getStringExtra(FolioReader.INTENT_BOOK_ID); mEpubSourceType = (EpubSourceType) @@ -134,8 +141,34 @@ protected void onCreate(Bundle savedInstanceState) { setupBook(); } + initToolbar(savedInstanceState); + } + + private void initToolbar(Bundle savedInstanceState) { + toolbar = findViewById(R.id.toolbar); toolbar.setListeners(this); + if (savedInstanceState != null) { + toolbar.setVisible(savedInstanceState.getBoolean(BUNDLE_TOOLBAR_IS_VISIBLE)); + if (toolbar.getVisible()) { + toolbar.show(); + } else { + toolbar.hide(); + } + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Config config = AppUtil.getSavedConfig(getApplicationContext()); + int color; + if (config.isNightMode()) { + color = ContextCompat.getColor(this, R.color.black); + } else { + int[] attrs = {android.R.attr.navigationBarColor}; + TypedArray typedArray = getTheme().obtainStyledAttributes(attrs); + color = typedArray.getColor(0, ContextCompat.getColor(this, R.color.white)); + } + getWindow().setNavigationBarColor(color); + } } @Override @@ -166,7 +199,7 @@ private void initBook(String mEpubFileName, int mEpubRawId, String mEpubFilePath new MainPresenter(this).parseManifest(urlString); } catch (IOException e) { - Log.e(TAG, "initBook failed", e); + Log.e(LOG_TAG, "initBook failed", e); } } @@ -180,101 +213,26 @@ private void getEpubResource() { } @Override - public void onOrientationChange(int orientation) { - if (orientation == 0) { - mFolioPageViewPager.setDirection(DirectionalViewpager.Direction.VERTICAL); - mFolioPageFragmentAdapter = - new FolioPageFragmentAdapter(getSupportFragmentManager(), - mSpineReferenceList, bookFileName, mBookId); - mFolioPageViewPager.setAdapter(mFolioPageFragmentAdapter); - mFolioPageViewPager.setOffscreenPageLimit(1); - mFolioPageViewPager.setCurrentItem(mChapterPosition); - - } else { - mFolioPageViewPager.setDirection(DirectionalViewpager.Direction.HORIZONTAL); - mFolioPageFragmentAdapter = - new FolioPageFragmentAdapter(getSupportFragmentManager(), - mSpineReferenceList, bookFileName, mBookId); - mFolioPageViewPager.setAdapter(mFolioPageFragmentAdapter); - mFolioPageViewPager.setCurrentItem(mChapterPosition); - } - } - - private void configFolio() { - mFolioPageViewPager = findViewById(R.id.folioPageViewPager); - mFolioPageViewPager.setOnPageChangeListener(new DirectionalViewpager.OnPageChangeListener() { - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - } - - @Override - public void onPageSelected(int position) { - EventBus.getDefault().post(new MediaOverlayPlayPauseEvent(mSpineReferenceList.get(mChapterPosition).href, false, true)); - mediaControllerView.setPlayButtonDrawable(); - mChapterPosition = position; - } - - @Override - public void onPageScrollStateChanged(int state) { - if (state == DirectionalViewpager.SCROLL_STATE_IDLE) { - toolbar.setTitle(mSpineReferenceList.get(mChapterPosition).bookTitle); - } - } - }); - - if (mSpineReferenceList != null) { - mFolioPageFragmentAdapter = new FolioPageFragmentAdapter(getSupportFragmentManager(), mSpineReferenceList, bookFileName, mBookId); - mFolioPageViewPager.setAdapter(mFolioPageFragmentAdapter); - - entryReadPosition = getIntent().getParcelableExtra(FolioActivity.EXTRA_READ_POSITION); - mFolioPageViewPager.setCurrentItem(getChapterIndex(entryReadPosition)); - } - } - - /** - * Returns the index of the chapter by following priority - - * 1. id - * 2. href - * 3. index - * - * @param readPosition Last read position - * @return index of the chapter - */ - private int getChapterIndex(ReadPosition readPosition) { - if (readPosition == null) { - return 0; + public void onDirectionChange(@NonNull Config.Direction newDirection) { + Log.v(LOG_TAG, "-> onDirectionChange"); - } else if (!TextUtils.isEmpty(readPosition.getChapterId())) { - return getChapterIndex("id", readPosition.getChapterId()); + FolioPageFragment folioPageFragment = (FolioPageFragment) + mFolioPageFragmentAdapter.getItem(mFolioPageViewPager.getCurrentItem()); + entryReadPosition = folioPageFragment.getLastReadPosition(); - } else if (!TextUtils.isEmpty(readPosition.getChapterHref())) { - return getChapterIndex("href", readPosition.getChapterHref()); + direction = newDirection; - } else if (readPosition.getChapterIndex() > -1 - && readPosition.getChapterIndex() < mSpineReferenceList.size()) { - return readPosition.getChapterIndex(); - } - - return 0; - } - - private int getChapterIndex(String caseString, String value) { - for (int i = 0; i < mSpineReferenceList.size(); i++) { - switch (caseString) { - case "id": - if (mSpineReferenceList.get(i).getId().equals(value)) - return i; - case "href": - if (mSpineReferenceList.get(i).getOriginalHref().equals(value)) - return i; - } - } - return 0; + mFolioPageViewPager.setDirection(newDirection); + mFolioPageFragmentAdapter = new FolioPageFragmentAdapter(getSupportFragmentManager(), + mSpineReferenceList, bookFileName, mBookId); + mFolioPageViewPager.setAdapter(mFolioPageFragmentAdapter); + mFolioPageViewPager.setCurrentItem(mChapterPosition); } @Override public void showConfigBottomSheetDialogFragment() { - new ConfigBottomSheetDialogFragment().show(getSupportFragmentManager(), ConfigBottomSheetDialogFragment.class.getSimpleName()); + new ConfigBottomSheetDialogFragment().show(getSupportFragmentManager(), + ConfigBottomSheetDialogFragment.class.getSimpleName()); } @Override @@ -282,6 +240,11 @@ public void hideOrShowToolBar() { toolbar.showOrHideIfVisible(); } + @Override + public void hideToolBarIfVisible() { + + } + @Override public void setPagerToPosition(String href) { } @@ -314,22 +277,26 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == ACTION_CONTENT_HIGHLIGHT && resultCode == RESULT_OK && data.hasExtra(TYPE)) { String type = data.getStringExtra(TYPE); + if (type.equals(CHAPTER_SELECTED)) { String selectedChapterHref = data.getStringExtra(SELECTED_CHAPTER_POSITION); for (Link spine : mSpineReferenceList) { if (selectedChapterHref.contains(spine.href)) { mChapterPosition = mSpineReferenceList.indexOf(spine); mFolioPageViewPager.setCurrentItem(mChapterPosition); - toolbar.setTitle(data.getStringExtra(Constants.BOOK_TITLE)); - EventBus.getDefault().post(new AnchorIdEvent(selectedChapterHref)); + FolioPageFragment folioPageFragment = (FolioPageFragment) + mFolioPageFragmentAdapter.getItem(mChapterPosition); + folioPageFragment.scrollToFirst(); + folioPageFragment.scrollToAnchorId(selectedChapterHref); break; } } } else if (type.equals(HIGHLIGHT_SELECTED)) { HighlightImpl highlightImpl = data.getParcelableExtra(HIGHLIGHT_ITEM); - int position = highlightImpl.getPageNumber(); - mFolioPageViewPager.setCurrentItem(position); - EventBus.getDefault().post(new WebViewPosition(mSpineReferenceList.get(mChapterPosition).href, highlightImpl.getRangy())); + mFolioPageViewPager.setCurrentItem(highlightImpl.getPageNumber()); + FolioPageFragment folioPageFragment = (FolioPageFragment) + mFolioPageFragmentAdapter.getItem(highlightImpl.getPageNumber()); + folioPageFragment.scrollToHighlightId(highlightImpl.getRangy()); } } } @@ -337,6 +304,10 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { @Override protected void onDestroy() { super.onDestroy(); + + if (outState != null) + outState.putParcelable(BUNDLE_READ_POSITION_CONFIG_CHANGE, lastReadPosition); + if (mEpubServer != null) { mEpubServer.stop(); } @@ -368,16 +339,162 @@ public void onLoadPublication(EpubPublication publication) { configFolio(); } - private void setConfig() { - if (AppUtil.getSavedConfig(this) != null) { - mConfig = AppUtil.getSavedConfig(this); - } else if (getIntent().getParcelableExtra(Config.INTENT_CONFIG) != null) { - mConfig = getIntent().getParcelableExtra(Config.INTENT_CONFIG); - AppUtil.saveConfig(this, mConfig); + private void configFolio() { + + mFolioPageViewPager = findViewById(R.id.folioPageViewPager); + // Replacing with addOnPageChangeListener(), onPageSelected() is not invoked + mFolioPageViewPager.setOnPageChangeListener(new DirectionalViewpager.OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { + } + + @Override + public void onPageSelected(int position) { + Log.v(LOG_TAG, "-> onPageSelected -> DirectionalViewpager -> position = " + position); + + EventBus.getDefault().post(new MediaOverlayPlayPauseEvent( + mSpineReferenceList.get(mChapterPosition).href, false, true)); + mediaControllerView.setPlayButtonDrawable(); + mChapterPosition = position; + toolbar.setTitle(mSpineReferenceList.get(mChapterPosition).bookTitle); + } + + @Override + public void onPageScrollStateChanged(int state) { + + if (state == DirectionalViewpager.SCROLL_STATE_IDLE) { + int position = mFolioPageViewPager.getCurrentItem(); + Log.v(LOG_TAG, "-> onPageScrollStateChanged -> DirectionalViewpager -> " + + "position = " + position); + + FolioPageFragment folioPageFragment = + (FolioPageFragment) mFolioPageFragmentAdapter.getItem(position - 1); + if (folioPageFragment != null) + folioPageFragment.scrollToLast(); + + folioPageFragment = + (FolioPageFragment) mFolioPageFragmentAdapter.getItem(position + 1); + if (folioPageFragment != null) + folioPageFragment.scrollToFirst(); + } + } + }); + + if (mSpineReferenceList != null) { + + mFolioPageViewPager.setDirection(direction); + mFolioPageFragmentAdapter = new FolioPageFragmentAdapter(getSupportFragmentManager(), + mSpineReferenceList, bookFileName, mBookId); + mFolioPageViewPager.setAdapter(mFolioPageFragmentAdapter); + + ReadPosition readPosition; + if (savedInstanceState == null) { + readPosition = getIntent().getParcelableExtra(FolioActivity.EXTRA_READ_POSITION); + entryReadPosition = readPosition; + } else { + readPosition = savedInstanceState.getParcelable(BUNDLE_READ_POSITION_CONFIG_CHANGE); + lastReadPosition = readPosition; + } + mFolioPageViewPager.setCurrentItem(getChapterIndex(readPosition)); + } + } + + /** + * Returns the index of the chapter by following priority - + * 1. id + * 2. href + * 3. index + * + * @param readPosition Last read position + * @return index of the chapter + */ + private int getChapterIndex(ReadPosition readPosition) { + if (readPosition == null) { + return 0; + + } else if (!TextUtils.isEmpty(readPosition.getChapterId())) { + return getChapterIndex("id", readPosition.getChapterId()); + + } else if (!TextUtils.isEmpty(readPosition.getChapterHref())) { + return getChapterIndex("href", readPosition.getChapterHref()); + + } else if (readPosition.getChapterIndex() > -1 + && readPosition.getChapterIndex() < mSpineReferenceList.size()) { + return readPosition.getChapterIndex(); + } + + return 0; + } + + private int getChapterIndex(String caseString, String value) { + for (int i = 0; i < mSpineReferenceList.size(); i++) { + switch (caseString) { + case "id": + if (mSpineReferenceList.get(i).getId().equals(value)) + return i; + case "href": + if (mSpineReferenceList.get(i).getOriginalHref().equals(value)) + return i; + } + } + return 0; + } + + /** + * If called, this method will occur after onStop() for applications targeting platforms + * starting with Build.VERSION_CODES.P. For applications targeting earlier platform versions + * this method will occur before onStop() and there are no guarantees about whether it will + * occur before or after onPause() + * + * @see Activity#onSaveInstanceState(Bundle) of Build.VERSION_CODES.P + */ + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + Log.v(LOG_TAG, "-> onSaveInstanceState"); + this.outState = outState; + + outState.putBoolean(BUNDLE_TOOLBAR_IS_VISIBLE, toolbar.getVisible()); + } + + @Override + public void storeLastReadPosition(ReadPosition lastReadPosition) { + Log.v(LOG_TAG, "-> storeLastReadPosition"); + this.lastReadPosition = lastReadPosition; + } + + private void setConfig(Bundle savedInstanceState) { + + Config config; + Config intentConfig = getIntent().getParcelableExtra(Config.INTENT_CONFIG); + boolean overrideConfig = getIntent().getBooleanExtra(Config.EXTRA_OVERRIDE_CONFIG, false); + Config savedConfig = AppUtil.getSavedConfig(this); + + if (savedInstanceState != null) { + config = savedConfig; + + } else if (savedConfig == null) { + if (intentConfig == null) { + config = new Config(); + } else { + config = intentConfig; + } + } else { - mConfig = new Config.ConfigBuilder().build(); - AppUtil.saveConfig(this, mConfig); + if (intentConfig != null && overrideConfig) { + config = intentConfig; + } else { + config = savedConfig; + } } + + // Code would never enter this if, just added for any unexpected error + // and to avoid lint warning + if (config == null) + config = new Config(); + + AppUtil.saveConfig(this, config); + direction = config.getDirection(); } @Override @@ -412,4 +529,9 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis break; } } + + @Override + public Config.Direction getDirection() { + return direction; + } } \ No newline at end of file diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/activity/FolioActivityCallback.java b/folioreader/src/main/java/com/folioreader/ui/folio/activity/FolioActivityCallback.java new file mode 100644 index 000000000..61acd51e0 --- /dev/null +++ b/folioreader/src/main/java/com/folioreader/ui/folio/activity/FolioActivityCallback.java @@ -0,0 +1,21 @@ +package com.folioreader.ui.folio.activity; + +import com.folioreader.Config; +import com.folioreader.model.ReadPosition; + +public interface FolioActivityCallback { + + int getChapterPosition(); + + void setPagerToPosition(String href); + + ReadPosition getEntryReadPosition(); + + void goToChapter(String href); + + Config.Direction getDirection(); + + void onDirectionChange(Config.Direction newDirection); + + void storeLastReadPosition(ReadPosition lastReadPosition); +} diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/adapter/FolioPageFragmentAdapter.java b/folioreader/src/main/java/com/folioreader/ui/folio/adapter/FolioPageFragmentAdapter.java index 7dce8b238..eaa450d74 100644 --- a/folioreader/src/main/java/com/folioreader/ui/folio/adapter/FolioPageFragmentAdapter.java +++ b/folioreader/src/main/java/com/folioreader/ui/folio/adapter/FolioPageFragmentAdapter.java @@ -3,33 +3,63 @@ import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; +import android.view.ViewGroup; import com.folioreader.ui.folio.fragment.FolioPageFragment; import org.readium.r2_streamer.model.publication.link.Link; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** * @author mahavir on 4/2/16. */ public class FolioPageFragmentAdapter extends FragmentStatePagerAdapter { + + private static final String LOG_TAG = FolioPageFragmentAdapter.class.getSimpleName(); private List mSpineReferences; private String mEpubFileName; private String mBookId; + private ArrayList fragments; - public FolioPageFragmentAdapter(FragmentManager fm, List spineReferences, String epubFileName, String bookId) { - super(fm); + public FolioPageFragmentAdapter(FragmentManager fragmentManager, List spineReferences, + String epubFileName, String bookId) { + super(fragmentManager); this.mSpineReferences = spineReferences; this.mEpubFileName = epubFileName; this.mBookId = bookId; + fragments = new ArrayList<>(Arrays.asList(new Fragment[mSpineReferences.size()])); + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + super.destroyItem(container, position, object); + fragments.set(position, null); + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + + Fragment fragment = (Fragment) super.instantiateItem(container, position); + fragments.set(position, fragment); + return fragment; } @Override public Fragment getItem(int position) { - FolioPageFragment mFolioPageFragment = FolioPageFragment.newInstance(position, mEpubFileName, mSpineReferences.get(position),mBookId); - mFolioPageFragment.setFragmentPos(position); - return mFolioPageFragment; + + if (mSpineReferences.size() == 0 || position < 0 || position >= mSpineReferences.size()) + return null; + + Fragment fragment = fragments.get(position); + if (fragment == null) { + fragment = FolioPageFragment.newInstance(position, + mEpubFileName, mSpineReferences.get(position), mBookId); + fragments.set(position, fragment); + } + return fragment; } @Override diff --git a/folioreader/src/main/java/com/folioreader/ui/folio/fragment/FolioPageFragment.java b/folioreader/src/main/java/com/folioreader/ui/folio/fragment/FolioPageFragment.java index a02fe77ae..2024e2e7c 100644 --- a/folioreader/src/main/java/com/folioreader/ui/folio/fragment/FolioPageFragment.java +++ b/folioreader/src/main/java/com/folioreader/ui/folio/fragment/FolioPageFragment.java @@ -3,7 +3,6 @@ import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; -import android.content.res.Configuration; import android.graphics.Color; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; @@ -27,42 +26,43 @@ import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; +import android.widget.FrameLayout; import android.widget.TextView; import android.widget.Toast; import com.bossturban.webviewmarker.TextSelectionSupport; import com.folioreader.Config; import com.folioreader.Constants; +import com.folioreader.FolioReader; import com.folioreader.R; import com.folioreader.model.HighLight; import com.folioreader.model.HighlightImpl; import com.folioreader.model.ReadPosition; import com.folioreader.model.ReadPositionImpl; -import com.folioreader.model.event.AnchorIdEvent; import com.folioreader.model.event.MediaOverlayHighlightStyleEvent; import com.folioreader.model.event.MediaOverlayPlayPauseEvent; import com.folioreader.model.event.MediaOverlaySpeedEvent; import com.folioreader.model.event.ReloadDataEvent; import com.folioreader.model.event.RewindIndexEvent; import com.folioreader.model.event.UpdateHighlightEvent; -import com.folioreader.model.event.WebViewPosition; import com.folioreader.model.quickaction.ActionItem; import com.folioreader.model.quickaction.QuickAction; import com.folioreader.model.sqlite.HighLightTable; import com.folioreader.ui.base.HtmlTask; import com.folioreader.ui.base.HtmlTaskCallback; import com.folioreader.ui.base.HtmlUtil; -import com.folioreader.ui.folio.activity.FolioActivity; +import com.folioreader.ui.folio.activity.FolioActivityCallback; import com.folioreader.ui.folio.mediaoverlay.MediaController; import com.folioreader.ui.folio.mediaoverlay.MediaControllerCallbacks; import com.folioreader.util.AppUtil; -import com.folioreader.FolioReader; import com.folioreader.util.HighlightUtil; import com.folioreader.util.SMILParser; import com.folioreader.util.UiUtil; +import com.folioreader.view.FolioWebView; +import com.folioreader.view.LoadingView; import com.folioreader.view.MediaControllerView; -import com.folioreader.view.ObservableWebView; import com.folioreader.view.VerticalSeekbar; +import com.folioreader.view.WebViewPager; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -79,13 +79,16 @@ * Created by mahavir on 4/2/16. */ @SuppressWarnings("PMD.AvoidDuplicateLiterals") -public class FolioPageFragment extends Fragment implements HtmlTaskCallback, MediaControllerCallbacks, ObservableWebView.SeekBarListener { +public class FolioPageFragment + extends Fragment + implements HtmlTaskCallback, MediaControllerCallbacks, FolioWebView.SeekBarListener { + public static final String LOG_TAG = FolioPageFragment.class.getSimpleName(); public static final String KEY_FRAGMENT_FOLIO_POSITION = "com.folioreader.ui.folio.fragment.FolioPageFragment.POSITION"; public static final String KEY_FRAGMENT_FOLIO_BOOK_TITLE = "com.folioreader.ui.folio.fragment.FolioPageFragment.BOOK_TITLE"; public static final String KEY_FRAGMENT_EPUB_FILE_NAME = "com.folioreader.ui.folio.fragment.FolioPageFragment.EPUB_FILE_NAME"; private static final String KEY_IS_SMIL_AVAILABLE = "com.folioreader.ui.folio.fragment.FolioPageFragment.IS_SMIL_AVAILABLE"; - public static final String TAG = FolioPageFragment.class.getSimpleName(); + private static final String BUNDLE_READ_POSITION_CONFIG_CHANGE = "BUNDLE_READ_POSITION_CONFIG_CHANGE"; private static final int ACTION_ID_COPY = 1001; private static final int ACTION_ID_SHARE = 1002; @@ -109,26 +112,20 @@ public class FolioPageFragment extends Fragment implements HtmlTaskCallback, Med private String rangy = ""; private String highlightId; - public interface FolioPageFragmentCallback { - - int getChapterPosition(); - - void setPagerToPosition(String href); - - ReadPosition getEntryReadPosition(); - - void goToChapter(String href); - } + private ReadPosition lastReadPosition; + private Bundle outState; + private Bundle savedInstanceState; private View mRootView; + private LoadingView loadingView; private VerticalSeekbar mScrollSeekbar; - private ObservableWebView mWebview; + private FolioWebView mWebview; + private WebViewPager webViewPager; private TextSelectionSupport mTextSelectionSupport; private TextView mPagesLeftTextView, mMinutesLeftTextView; - private FolioPageFragmentCallback mActivityCallback; + private FolioActivityCallback mActivityCallback; - private int mScrollY; private int mTotalMinutes; private String mSelectedText; private Animation mFadeInAnimation, mFadeOutAnimation; @@ -137,9 +134,7 @@ public interface FolioPageFragmentCallback { private int mPosition = -1; private String mBookTitle; private String mEpubFileName = null; - private int mPos; private boolean mIsPageReloaded; - private int mLastWebviewScrollpos; private String highlightStyle; @@ -162,8 +157,10 @@ public static FolioPageFragment newInstance(int position, String bookTitle, Link public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - if (getActivity() instanceof FolioPageFragmentCallback) - mActivityCallback = (FolioPageFragmentCallback) getActivity(); + this.savedInstanceState = savedInstanceState; + + if (getActivity() instanceof FolioActivityCallback) + mActivityCallback = (FolioActivityCallback) getActivity(); EventBus.getDefault().register(this); if ((savedInstanceState != null) @@ -181,6 +178,7 @@ public View onCreateView(LayoutInflater inflater, spineItem = (Link) getArguments().getSerializable(SPINE_ITEM); mBookId = getArguments().getString(FolioReader.INTENT_BOOK_ID); } + if (spineItem != null) { if (spineItem.properties.contains("media-overlay")) { mediaController = new MediaController(getActivity(), MediaController.MediaType.SMIL, this); @@ -191,14 +189,13 @@ public View onCreateView(LayoutInflater inflater, } } highlightStyle = HighlightImpl.HighlightStyle.classForStyle(HighlightImpl.HighlightStyle.Normal); - mRootView = View.inflate(getActivity(), R.layout.folio_page_fragment, null); + mRootView = inflater.inflate(R.layout.folio_page_fragment, container, false); mPagesLeftTextView = (TextView) mRootView.findViewById(R.id.pagesLeft); mMinutesLeftTextView = (TextView) mRootView.findViewById(R.id.minutesLeft); - Activity activity = getActivity(); - - mConfig = AppUtil.getSavedConfig(activity); + mConfig = AppUtil.getSavedConfig(getContext()); + loadingView = mRootView.findViewById(R.id.loadingView); initSeekbar(); initAnimations(); initWebView(); @@ -207,27 +204,13 @@ public View onCreateView(LayoutInflater inflater, return mRootView; } - private String getWebviewUrl() { return Constants.LOCALHOST + mBookTitle + "/" + spineItem.href; } - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - float positionTopView = mWebview.getTop(); - float contentHeight = mWebview.getContentHeight(); - float currentScrollPosition = mScrollY; - float percentWebview = (currentScrollPosition - positionTopView) / contentHeight; - float webviewsize = mWebview.getContentHeight() - mWebview.getTop(); - float positionInWV = webviewsize * percentWebview; - int positionY = Math.round(mWebview.getTop() + positionInWV); - mScrollY = positionY; - } - /** * [EVENT BUS FUNCTION] - * Function triggered from {@link FolioActivity#initAudioView()} when pause/play + * Function triggered from {@link MediaControllerView#initListeners()} when pause/play * button is clicked * * @param event of type {@link MediaOverlayPlayPauseEvent} contains if paused/played @@ -294,8 +277,13 @@ public void styleChanged(MediaOverlayHighlightStyleEvent event) { @SuppressWarnings("unused") @Subscribe(threadMode = ThreadMode.MAIN) public void reload(ReloadDataEvent reloadDataEvent) { + + if (isCurrentFragment()) + getLastReadPosition(); + if (isAdded()) { - mLastWebviewScrollpos = mWebview.getScrollY(); + loadingView.updateTheme(); + loadingView.show(); mIsPageReloaded = true; setHtml(true); updatePagesLeftTextBg(); @@ -304,7 +292,7 @@ public void reload(ReloadDataEvent reloadDataEvent) { /** * [EVENT BUS FUNCTION] - * + *

* Function triggered when highlight is deleted and page is needed to * be updated. * @@ -312,28 +300,21 @@ public void reload(ReloadDataEvent reloadDataEvent) { */ @SuppressWarnings("unused") @Subscribe(threadMode = ThreadMode.MAIN) - public void updateHighlight(UpdateHighlightEvent event){ - if(isAdded()) { + public void updateHighlight(UpdateHighlightEvent event) { + if (isAdded()) { this.rangy = HighlightUtil.generateRangyString(getPageName()); loadRangy(mWebview, this.rangy); } } - /** - * [EVENT BUS FUNCTION] - * Function triggered from {@link FolioActivity#onActivityResult(int, int, Intent)} when any item in toc clicked. - * - * @param event of type {@link AnchorIdEvent} contains selected chapter href. - */ - @Subscribe(threadMode = ThreadMode.MAIN) - public void jumpToAnchorPoint(AnchorIdEvent event) { - if (isAdded() && event != null && event.getHref() != null) { - String href = event.getHref(); - if (href != null && href.indexOf('#') != -1 && spineItem.href.equals(href.substring(0, href.lastIndexOf('#')))) { - mAnchorId = href.substring(href.lastIndexOf('#') + 1); - if (mWebview.getContentHeight() > 0 && mAnchorId != null) { - mWebview.loadUrl("javascript:document.getElementById(\"" + mAnchorId + "\").scrollIntoView()"); - } + public void scrollToAnchorId(String href) { + + if (!TextUtils.isEmpty(href) && href.indexOf('#') != -1) { + mAnchorId = href.substring(href.lastIndexOf('#') + 1); + if (loadingView != null && loadingView.getVisibility() != View.VISIBLE) { + loadingView.show(); + mWebview.loadUrl(String.format(getString(R.string.go_to_anchor), mAnchorId)); + mAnchorId = null; } } } @@ -361,32 +342,71 @@ private void setHtml(boolean reloaded) { mediaController.setSMILItems(SMILParser.parseSMIL(mHtmlString)); mediaController.setUpMediaPlayer(spineItem.mediaOverlay, spineItem.mediaOverlay.getAudioPath(spineItem.href), mBookTitle); } - mConfig = AppUtil.getSavedConfig(getActivity()); + mConfig = AppUtil.getSavedConfig(getContext()); String path = ""; int forwardSlashLastIndex = ref.lastIndexOf('/'); if (forwardSlashLastIndex != -1) path = ref.substring(0, forwardSlashLastIndex + 1); + String mimeType; + if (spineItem.typeLink.equalsIgnoreCase(getString(R.string.xhtml_mime_type))) { + mimeType = getString(R.string.xhtml_mime_type); + } else { + mimeType = getString(R.string.html_mime_type); + } + mWebview.loadDataWithBaseURL( Constants.LOCALHOST + mBookTitle + "/" + path, - HtmlUtil.getHtmlContent(getActivity(), mHtmlString, mConfig), - "text/html", + HtmlUtil.getHtmlContent(getContext(), mHtmlString, mConfig), + mimeType, "UTF-8", null); } } + @SuppressWarnings("unused") + @JavascriptInterface + public String getDirection() { + return mActivityCallback.getDirection().toString(); + } + + public void scrollToLast() { + + boolean isPageLoading = loadingView == null || loadingView.getVisibility() == View.VISIBLE; + Log.v(LOG_TAG, "-> scrollToLast -> isPageLoading = " + isPageLoading); + + if (!isPageLoading) { + loadingView.show(); + mWebview.loadUrl("javascript:scrollToLast()"); + } + } + + public void scrollToFirst() { + + boolean isPageLoading = loadingView == null || loadingView.getVisibility() == View.VISIBLE; + Log.v(LOG_TAG, "-> scrollToFirst -> isPageLoading = " + isPageLoading); + + if (!isPageLoading) { + loadingView.show(); + mWebview.loadUrl("javascript:scrollToFirst()"); + } + } + private void initWebView() { - mWebview = (ObservableWebView) mRootView.findViewById(R.id.contentWebView); - mWebview.setSeekBarListener(FolioPageFragment.this); - if (getActivity() instanceof ObservableWebView.ToolBarListener) - mWebview.setToolBarListener((ObservableWebView.ToolBarListener) getActivity()); + FrameLayout webViewLayout = mRootView.findViewById(R.id.webViewLayout); + mWebview = webViewLayout.findViewById(R.id.folioWebView); + webViewPager = webViewLayout.findViewById(R.id.webViewPager); + + if (getActivity() instanceof FolioActivityCallback) + mWebview.setFolioActivityCallback((FolioActivityCallback) getActivity()); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (getActivity() instanceof FolioWebView.ToolBarListener) + mWebview.setToolBarListener((FolioWebView.ToolBarListener) getActivity()); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) WebView.setWebContentsDebuggingEnabled(true); - } setupScrollBar(); mWebview.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @@ -408,174 +428,145 @@ public void onLayoutChange(View view, int left, int top, int right, int bottom, mWebview.addJavascriptInterface(this, "Highlight"); mWebview.addJavascriptInterface(this, "FolioPageFragment"); + mWebview.addJavascriptInterface(webViewPager, "WebViewPager"); + mWebview.addJavascriptInterface(loadingView, "LoadingView"); + mWebview.addJavascriptInterface(mWebview, "FolioWebView"); - mWebview.setScrollListener(new ObservableWebView.ScrollListener() { + mWebview.setScrollListener(new FolioWebView.ScrollListener() { @Override public void onScrollChange(int percent) { - if (mWebview.getScrollY() != 0) - mScrollY = mWebview.getScrollY(); - mScrollSeekbar.setProgressAndThumb(percent); updatePagesLeftText(percent); } }); - mWebview.setWebViewClient(new WebViewClient() { + mWebview.setWebViewClient(webViewClient); + mWebview.setWebChromeClient(webChromeClient); + + mTextSelectionSupport = TextSelectionSupport.support(getActivity(), mWebview); + mTextSelectionSupport.setSelectionListener(new TextSelectionSupport.SelectionListener() { + @Override + public void startSelection() { + } + @Override - public void onPageFinished(WebView view, String url) { + public void selectionChanged(String text) { + mSelectedText = text; + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + mWebview.loadUrl("javascript:alert(getRectForSelectedText())"); + } + }); + } - if (isAdded()) { + @Override + public void endSelection() { - view.loadUrl("javascript:alert(getReadingTime())"); + } + }); - if (!hasMediaOverlay) - view.loadUrl("javascript:wrappingSentencesWithinPTags()"); + mWebview.getSettings().setDefaultTextEncodingName("utf-8"); + new HtmlTask(this).execute(getWebviewUrl()); + } - view.loadUrl(String.format(getString(R.string.setmediaoverlaystyle), - HighlightImpl.HighlightStyle.classForStyle( - HighlightImpl.HighlightStyle.Normal))); + private WebViewClient webViewClient = new WebViewClient() { + @Override + public void onPageFinished(WebView view, String url) { - String rangy = HighlightUtil.generateRangyString(getPageName()); - FolioPageFragment.this.rangy = rangy; - if (!rangy.isEmpty()) - loadRangy(view, rangy); + if (isAdded()) { - if (mIsPageReloaded) { - setWebViewPosition(mLastWebviewScrollpos); - mIsPageReloaded = false; - } else if (!TextUtils.isEmpty(mAnchorId)) { - view.loadUrl("javascript:document.getElementById(\"" + mAnchorId + "\").scrollIntoView()"); - } else if (!TextUtils.isEmpty(highlightId)) { - scrollToHighlightId(); - } else if (isCurrentFragment()) { - - ReadPosition entryReadPosition = mActivityCallback.getEntryReadPosition(); - if (entryReadPosition != null) { - mWebview.loadUrl(String.format("javascript:scrollToSpan(%b, %s)", - entryReadPosition.isUsingId(), entryReadPosition.getValue())); - } - } - } - } + mWebview.loadUrl("javascript:getCompatMode()"); + mWebview.loadUrl("javascript:alert(getReadingTime())"); - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (!url.isEmpty() && url.length() > 0) { - if (Uri.parse(url).getScheme().startsWith("highlight")) { - final Pattern pattern = Pattern.compile(getString(R.string.pattern)); - try { - String htmlDecode = URLDecoder.decode(url, "UTF-8"); - Matcher matcher = pattern.matcher(htmlDecode.substring(12)); - if (matcher.matches()) { - double left = Double.parseDouble(matcher.group(1)); - double top = Double.parseDouble(matcher.group(2)); - double width = Double.parseDouble(matcher.group(3)); - double height = Double.parseDouble(matcher.group(4)); - onHighlight((int) (UiUtil.convertDpToPixel((float) left, - getActivity())), - (int) (UiUtil.convertDpToPixel((float) top, - getActivity())), - (int) (UiUtil.convertDpToPixel((float) width, - getActivity())), - (int) (UiUtil.convertDpToPixel((float) height, - getActivity()))); - } - } catch (UnsupportedEncodingException e) { - Log.d(TAG, e.getMessage()); - } + if (!hasMediaOverlay) + mWebview.loadUrl("javascript:wrappingSentencesWithinPTags()"); + + if (mActivityCallback.getDirection() == Config.Direction.HORIZONTAL) + mWebview.loadUrl("javascript:initHorizontalDirection()"); + + view.loadUrl(String.format(getString(R.string.setmediaoverlaystyle), + HighlightImpl.HighlightStyle.classForStyle( + HighlightImpl.HighlightStyle.Normal))); + + String rangy = HighlightUtil.generateRangyString(getPageName()); + FolioPageFragment.this.rangy = rangy; + if (!rangy.isEmpty()) + loadRangy(mWebview, rangy); + + if (mIsPageReloaded) { + + if (isCurrentFragment()) { + mWebview.loadUrl(String.format("javascript:scrollToSpan(%b, %s)", + lastReadPosition.isUsingId(), lastReadPosition.getValue())); } else { - if (url.contains("storage")) { - mActivityCallback.setPagerToPosition(url); - } else if (url.endsWith(".xhtml") || url.endsWith(".html")) { - mActivityCallback.goToChapter(url); + if (mPosition == mActivityCallback.getChapterPosition() - 1) { + // Scroll to last, the page before current page + mWebview.loadUrl("javascript:scrollToLast()"); } else { - // Otherwise, give the default behavior (open in browser) - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - startActivity(intent); + // Make loading view invisible for all other fragments + loadingView.hide(); } } - } - return true; - } - // prevent favicon.ico to be loaded automatically - @Override - public WebResourceResponse shouldInterceptRequest(WebView view, String url) { - if(url.toLowerCase().contains("/favicon.ico")) { - try { - return new WebResourceResponse("image/png", null, null); - } catch (Exception e) { - Log.e(TAG, "shouldInterceptRequest failed", e); + mIsPageReloaded = false; + + } else if (!TextUtils.isEmpty(mAnchorId)) { + mWebview.loadUrl(String.format(getString(R.string.go_to_anchor), mAnchorId)); + mAnchorId = null; + + } else if (!TextUtils.isEmpty(highlightId)) { + mWebview.loadUrl(String.format(getString(R.string.go_to_highlight), highlightId)); + highlightId = null; + + } else if (isCurrentFragment()) { + + ReadPosition readPosition; + if (savedInstanceState == null) { + Log.v(LOG_TAG, "-> onPageFinished -> took from getEntryReadPosition"); + readPosition = mActivityCallback.getEntryReadPosition(); + } else { + Log.v(LOG_TAG, "-> onPageFinished -> took from bundle"); + readPosition = savedInstanceState.getParcelable(BUNDLE_READ_POSITION_CONFIG_CHANGE); + savedInstanceState.remove(BUNDLE_READ_POSITION_CONFIG_CHANGE); } - } - return null; - } - // prevent favicon.ico to be loaded automatically - @Override - @SuppressLint("NewApi") - public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { - if(!request.isForMainFrame() && request.getUrl().getPath().endsWith("/favicon.ico")) { - try { - return new WebResourceResponse("image/png", null, null); - } catch (Exception e) { - Log.e(TAG, "shouldInterceptRequest failed", e); + if (readPosition != null) { + Log.v(LOG_TAG, "-> scrollToSpan -> " + readPosition.getValue()); + mWebview.loadUrl(String.format("javascript:scrollToSpan(%b, %s)", + readPosition.isUsingId(), readPosition.getValue())); + } else { + loadingView.hide(); } - } - return null; - } - }); - mWebview.setWebChromeClient(new WebChromeClient() { - @Override - public void onProgressChanged(WebView view, int progress) { - - if (view.getProgress() == 100) { - mWebview.postDelayed(new Runnable() { - @Override - public void run() { - Log.d("scroll y", "Scrolly" + mScrollY); - mWebview.scrollTo(0, mScrollY); - } - }, 100); + } else { + + if (mPosition == mActivityCallback.getChapterPosition() - 1) { + // Scroll to last, the page before current page + mWebview.loadUrl("javascript:scrollToLast()"); + } else { + // Make loading view invisible for all other fragments + loadingView.hide(); + } } } + } - @Override - public boolean onJsAlert(WebView view, String url, String message, JsResult result) { - if (FolioPageFragment.this.isVisible()) { - String rangyPattern = "\\d+\\$\\d+\\$\\d+\\$\\w+\\$"; - Pattern pattern = Pattern.compile(rangyPattern); - Matcher matcher = pattern.matcher(message); - if (matcher.matches()) { - HighlightImpl highlightImpl = HighLightTable.getHighlightForRangy(message); - if (HighLightTable.deleteHighlight(message)) { - String rangy = HighlightUtil.generateRangyString(getPageName()); - loadRangy(view, rangy); - mTextSelectionSupport.endSelectionMode(); - if (highlightImpl != null) { - HighlightUtil.sendHighlightBroadcastEvent( - FolioPageFragment.this.getActivity().getApplicationContext(), - highlightImpl, - HighLight.HighLightAction.DELETE); - } - } - } else if (TextUtils.isDigitsOnly(message)) { - try { - mTotalMinutes = Integer.parseInt(message); - } catch (NumberFormatException e) { - mTotalMinutes = 0; - } - } else { - pattern = Pattern.compile(getString(R.string.pattern)); - matcher = pattern.matcher(message); + @Override + public boolean shouldOverrideUrlLoading(WebView view, String url) { + if (!url.isEmpty() && url.length() > 0) { + if (Uri.parse(url).getScheme().startsWith("highlight")) { + final Pattern pattern = Pattern.compile(getString(R.string.pattern)); + try { + String htmlDecode = URLDecoder.decode(url, "UTF-8"); + Matcher matcher = pattern.matcher(htmlDecode.substring(12)); if (matcher.matches()) { double left = Double.parseDouble(matcher.group(1)); double top = Double.parseDouble(matcher.group(2)); double width = Double.parseDouble(matcher.group(3)); double height = Double.parseDouble(matcher.group(4)); - showTextSelectionMenu((int) (UiUtil.convertDpToPixel((float) left, + onHighlight((int) (UiUtil.convertDpToPixel((float) left, getActivity())), (int) (UiUtil.convertDpToPixel((float) top, getActivity())), @@ -583,46 +574,115 @@ public boolean onJsAlert(WebView view, String url, String message, JsResult resu getActivity())), (int) (UiUtil.convertDpToPixel((float) height, getActivity()))); - } else { - // to handle TTS playback when highlight is deleted. - Pattern p = Pattern.compile("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"); - if (!p.matcher(message).matches() && (!message.equals("undefined")) && isCurrentFragment()) { - mediaController.speakAudio(message); - } } + } catch (UnsupportedEncodingException e) { + Log.d(LOG_TAG, e.getMessage()); + } + } else { + if (url.contains("storage")) { + mActivityCallback.setPagerToPosition(url); + } else if (url.endsWith(".xhtml") || url.endsWith(".html")) { + mActivityCallback.goToChapter(url); + } else { + // Otherwise, give the default behavior (open in browser) + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + startActivity(intent); } - result.confirm(); } - return true; } - }); + return true; + } - mTextSelectionSupport = TextSelectionSupport.support(getActivity(), mWebview); - mTextSelectionSupport.setSelectionListener(new TextSelectionSupport.SelectionListener() { - @Override - public void startSelection() { + // prevent favicon.ico to be loaded automatically + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, String url) { + if (url.toLowerCase().contains("/favicon.ico")) { + try { + return new WebResourceResponse("image/png", null, null); + } catch (Exception e) { + Log.e(LOG_TAG, "shouldInterceptRequest failed", e); + } } + return null; + } - @Override - public void selectionChanged(String text) { - mSelectedText = text; - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - mWebview.loadUrl("javascript:alert(getRectForSelectedText())"); - } - }); + // prevent favicon.ico to be loaded automatically + @Override + @SuppressLint("NewApi") + public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { + if (!request.isForMainFrame() + && request.getUrl().getPath() != null + && request.getUrl().getPath().endsWith("/favicon.ico")) { + try { + return new WebResourceResponse("image/png", null, null); + } catch (Exception e) { + Log.e(LOG_TAG, "shouldInterceptRequest failed", e); + } } + return null; + } + }; - @Override - public void endSelection() { + private WebChromeClient webChromeClient = new WebChromeClient() { - } - }); + @Override + public void onProgressChanged(WebView view, int progress) { + } - mWebview.getSettings().setDefaultTextEncodingName("utf-8"); - new HtmlTask(this).execute(getWebviewUrl()); - } + @Override + public boolean onJsAlert(WebView view, String url, String message, JsResult result) { + if (FolioPageFragment.this.isVisible()) { + String rangyPattern = "\\d+\\$\\d+\\$\\d+\\$\\w+\\$"; + Pattern pattern = Pattern.compile(rangyPattern); + Matcher matcher = pattern.matcher(message); + if (matcher.matches()) { + HighlightImpl highlightImpl = HighLightTable.getHighlightForRangy(message); + if (HighLightTable.deleteHighlight(message)) { + String rangy = HighlightUtil.generateRangyString(getPageName()); + loadRangy(view, rangy); + mTextSelectionSupport.endSelectionMode(); + if (highlightImpl != null) { + HighlightUtil.sendHighlightBroadcastEvent( + FolioPageFragment.this.getActivity().getApplicationContext(), + highlightImpl, + HighLight.HighLightAction.DELETE); + } + } + } else if (TextUtils.isDigitsOnly(message)) { + try { + mTotalMinutes = Integer.parseInt(message); + } catch (NumberFormatException e) { + mTotalMinutes = 0; + } + } else { + pattern = Pattern.compile(getString(R.string.pattern)); + matcher = pattern.matcher(message); + if (matcher.matches()) { + double left = Double.parseDouble(matcher.group(1)); + double top = Double.parseDouble(matcher.group(2)); + double width = Double.parseDouble(matcher.group(3)); + double height = Double.parseDouble(matcher.group(4)); + showTextSelectionMenu((int) (UiUtil.convertDpToPixel((float) left, + getActivity())), + (int) (UiUtil.convertDpToPixel((float) top, + getActivity())), + (int) (UiUtil.convertDpToPixel((float) width, + getActivity())), + (int) (UiUtil.convertDpToPixel((float) height, + getActivity()))); + } else { + // to handle TTS playback when highlight is deleted. + Pattern p = Pattern.compile("[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}"); + if (!p.matcher(message).matches() && (!message.equals("undefined")) && isCurrentFragment()) { + mediaController.speakAudio(message); + } + } + } + result.confirm(); + } + return true; + } + }; /** * Calls the /assets/js/Bridge.js#getFirstVisibleSpan(boolean) @@ -630,19 +690,31 @@ public void endSelection() { @Override public void onStop() { super.onStop(); + Log.v(LOG_TAG, "-> onStop -> " + spineItem.originalHref + " -> " + isCurrentFragment()); + mediaController.stop(); //TODO save last media overlay item - if (isCurrentFragment()) { - try { - synchronized (this) { - mWebview.loadUrl("javascript:getFirstVisibleSpan(false)"); - wait(2000); - } - } catch (InterruptedException e) { - Log.e(TAG, "-> " + e); + if (isCurrentFragment()) + getLastReadPosition(); + } + + public ReadPosition getLastReadPosition() { + Log.v(LOG_TAG, "-> getLastReadPosition -> " + spineItem.originalHref); + + try { + synchronized (this) { + boolean isHorizontal = mActivityCallback.getDirection() == + Config.Direction.HORIZONTAL; + mWebview.loadUrl("javascript:getFirstVisibleSpan(" + isHorizontal +")"); + + wait(2000); } + } catch (InterruptedException e) { + Log.e(LOG_TAG, "-> " + e); } + + return lastReadPosition; } /** @@ -652,19 +724,30 @@ public void onStop() { * @param usingId if span tag has id then true or else false * @param value if usingId true then span id else span index */ + @SuppressWarnings("unused") @JavascriptInterface public void storeFirstVisibleSpan(boolean usingId, String value) { synchronized (this) { - ReadPositionImpl readPositionImpl = new ReadPositionImpl(mBookId, spineItem.getId(), + lastReadPosition = new ReadPositionImpl(mBookId, spineItem.getId(), spineItem.getOriginalHref(), mPosition, usingId, value); Intent intent = new Intent(FolioReader.ACTION_SAVE_READ_POSITION); - intent.putExtra(FolioReader.EXTRA_READ_POSITION, readPositionImpl); + intent.putExtra(FolioReader.EXTRA_READ_POSITION, lastReadPosition); LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent); + notify(); } } + @SuppressWarnings("unused") + @JavascriptInterface + public void setHorizontalPageCount(int horizontalPageCount) { + Log.v(LOG_TAG, "-> setHorizontalPageCount = " + horizontalPageCount + + " -> " + spineItem.originalHref); + + mWebview.setHorizontalPageCount(horizontalPageCount); + } + private void loadRangy(WebView view, String rangy) { view.loadUrl(String.format("javascript:if(typeof ssReader !== \"undefined\"){ssReader.setHighlights('%s');}", rangy)); } @@ -725,7 +808,7 @@ private void updatePagesLeftText(int scrollY) { mMinutesLeftTextView.setText(minutesRemainingStr); mPagesLeftTextView.setText(pagesRemainingStr); - } catch (java.lang.ArithmeticException exp) { + } catch (java.lang.ArithmeticException | IllegalStateException exp) { Log.d("divide error", exp.toString()); } } @@ -788,9 +871,22 @@ public void onDestroyView() { super.onDestroyView(); } + /** + * If called, this method will occur after onStop() for applications targeting platforms + * starting with Build.VERSION_CODES.P. For applications targeting earlier platform versions + * this method will occur before onStop() and there are no guarantees about whether it will + * occur before or after onPause() + * + * @see Activity#onSaveInstanceState(Bundle) of Build.VERSION_CODES.P + */ @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); + this.outState = outState; + + if (isCurrentFragment()) + Log.v(LOG_TAG, "-> onSaveInstanceState"); + outState.putInt(KEY_FRAGMENT_FOLIO_POSITION, mPosition); outState.putString(KEY_FRAGMENT_FOLIO_BOOK_TITLE, mBookTitle); outState.putString(KEY_FRAGMENT_EPUB_FILE_NAME, mEpubFileName); @@ -994,30 +1090,6 @@ private String getPageName() { return mBookTitle + "$" + spineItem.href; } - @SuppressWarnings("unused") - @Subscribe(threadMode = ThreadMode.MAIN) - public void setWebView(final WebViewPosition position) { - if (position.getHref().equals(spineItem.href) && isAdded()) { - highlightId = position.getHighlightId(); - - if (mWebview.getContentHeight() > 0) { - scrollToHighlightId(); - //Webview.loadUrl(String.format(getString(R.string.goto_highlight), highlightId)); - } - } - } - - public void setWebViewPosition(final int position) { - mWebview.post(new Runnable() { - @Override - public void run() { - if (isAdded()) { - mWebview.scrollTo(0, position); - } - } - }); - } - @Override public void highLightText(String fragmentId) { mWebview.loadUrl(String.format(getString(R.string.audio_mark_id), fragmentId)); @@ -1051,22 +1123,34 @@ public void run() { @Override public void onDestroy() { super.onDestroy(); + + if (isCurrentFragment()) { + if (outState != null) + outState.putParcelable(BUNDLE_READ_POSITION_CONFIG_CHANGE, lastReadPosition); + mActivityCallback.storeLastReadPosition(lastReadPosition); + } if (mWebview != null) mWebview.destroy(); } private boolean isCurrentFragment() { - return isAdded() && mActivityCallback.getChapterPosition() == mPos; - } - - public void setFragmentPos(int pos) { - mPos = pos; +// Log.d(LOG_TAG, "-> isCurrentFragment -> " +// + ", isAdded = " + isAdded() +// + ", mActivityCallback.getChapterPosition() = " + mActivityCallback.getChapterPosition() +// + ", mPosition = " + mPosition); + return isAdded() && mActivityCallback.getChapterPosition() == mPosition; } @Override public void onError() { } - private void scrollToHighlightId() { - mWebview.loadUrl(String.format(getString(R.string.goto_highlight), highlightId)); + public void scrollToHighlightId(String highlightId) { + this.highlightId = highlightId; + + if (loadingView != null && loadingView.getVisibility() != View.VISIBLE) { + loadingView.show(); + mWebview.loadUrl(String.format(getString(R.string.go_to_highlight), highlightId)); + this.highlightId = null; + } } } diff --git a/folioreader/src/main/java/com/folioreader/util/AppUtil.java b/folioreader/src/main/java/com/folioreader/util/AppUtil.java index a06c69f8f..d6fef82dc 100644 --- a/folioreader/src/main/java/com/folioreader/util/AppUtil.java +++ b/folioreader/src/main/java/com/folioreader/util/AppUtil.java @@ -1,7 +1,9 @@ package com.folioreader.util; import android.content.Context; +import android.os.Build; import android.util.Log; +import android.view.MotionEvent; import com.folioreader.Config; import com.folioreader.Constants; @@ -89,12 +91,13 @@ public static void saveConfig(Context context, Config config) { try { obj.put(Config.CONFIG_FONT, config.getFont()); obj.put(Config.CONFIG_FONT_SIZE, config.getFontSize()); - obj.put(Config.CONFIG_IS_NIGHTMODE, config.isNightMode()); - obj.put(Config.CONFIG_IS_THEMECOLOR, config.getThemeColor()); - obj.put(Config.CONFIG_IS_TTS,config.isShowTts()); - SharedPreferenceUtil. - putSharedPreferencesString( - context, Config.INTENT_CONFIG, obj.toString()); + obj.put(Config.CONFIG_IS_NIGHT_MODE, config.isNightMode()); + obj.put(Config.CONFIG_IS_THEME_COLOR, config.getThemeColor()); + obj.put(Config.CONFIG_IS_TTS, config.isShowTts()); + obj.put(Config.CONFIG_ALLOWED_DIRECTION, config.getAllowedDirection().toString()); + obj.put(Config.CONFIG_DIRECTION, config.getDirection().toString()); + SharedPreferenceUtil.putSharedPreferencesString(context, Config.INTENT_CONFIG, + obj.toString()); } catch (JSONException e) { Log.e(TAG, e.getMessage()); } @@ -113,6 +116,48 @@ public static Config getSavedConfig(Context context) { } return null; } + + public static String actionToString(int action) { + switch (action) { + case MotionEvent.ACTION_DOWN: + return "ACTION_DOWN"; + case MotionEvent.ACTION_UP: + return "ACTION_UP"; + case MotionEvent.ACTION_CANCEL: + return "ACTION_CANCEL"; + case MotionEvent.ACTION_OUTSIDE: + return "ACTION_OUTSIDE"; + case MotionEvent.ACTION_MOVE: + return "ACTION_MOVE"; + case MotionEvent.ACTION_HOVER_MOVE: + return "ACTION_HOVER_MOVE"; + case MotionEvent.ACTION_SCROLL: + return "ACTION_SCROLL"; + case MotionEvent.ACTION_HOVER_ENTER: + return "ACTION_HOVER_ENTER"; + case MotionEvent.ACTION_HOVER_EXIT: + return "ACTION_HOVER_EXIT"; + } + + if (Build.VERSION.SDK_INT >= 23) { + switch(action) { + case MotionEvent.ACTION_BUTTON_PRESS: + return "ACTION_BUTTON_PRESS"; + case MotionEvent.ACTION_BUTTON_RELEASE: + return "ACTION_BUTTON_RELEASE"; + } + } + + int index = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_POINTER_DOWN: + return "ACTION_POINTER_DOWN(" + index + ")"; + case MotionEvent.ACTION_POINTER_UP: + return "ACTION_POINTER_UP(" + index + ")"; + default: + return Integer.toString(action); + } + } } diff --git a/folioreader/src/main/java/com/folioreader/util/UiUtil.java b/folioreader/src/main/java/com/folioreader/util/UiUtil.java index 7676ed6de..9ccb78946 100644 --- a/folioreader/src/main/java/com/folioreader/util/UiUtil.java +++ b/folioreader/src/main/java/com/folioreader/util/UiUtil.java @@ -120,7 +120,7 @@ public static void setBackColorToTextView(UnderlinedTextView textView, String ty } - private static void setUnderLineColor(UnderlinedTextView underlinedTextView, Context context, int background,int underlinecolor) { + private static void setUnderLineColor(UnderlinedTextView underlinedTextView, Context context, int background, int underlinecolor) { underlinedTextView.setBackgroundColor(ContextCompat.getColor(context, background)); underlinedTextView.setUnderLineColor(ContextCompat.getColor(context, diff --git a/folioreader/src/main/java/com/folioreader/view/ConfigBottomSheetDialogFragment.kt b/folioreader/src/main/java/com/folioreader/view/ConfigBottomSheetDialogFragment.kt index f6623dc51..bf03e5aec 100644 --- a/folioreader/src/main/java/com/folioreader/view/ConfigBottomSheetDialogFragment.kt +++ b/folioreader/src/main/java/com/folioreader/view/ConfigBottomSheetDialogFragment.kt @@ -4,6 +4,7 @@ import android.animation.Animator import android.animation.ArgbEvaluator import android.animation.ValueAnimator import android.app.Activity +import android.os.Build import android.os.Bundle import android.support.design.widget.BottomSheetBehavior import android.support.design.widget.BottomSheetDialog @@ -18,6 +19,8 @@ import com.folioreader.Config import com.folioreader.Constants import com.folioreader.R import com.folioreader.model.event.ReloadDataEvent +import com.folioreader.ui.folio.activity.FolioActivity +import com.folioreader.ui.folio.activity.FolioActivityCallback import com.folioreader.util.AppUtil import com.folioreader.util.UiUtil import kotlinx.android.synthetic.main.view_config.* @@ -27,20 +30,26 @@ import org.greenrobot.eventbus.EventBus * Created by mobisys2 on 11/16/2016. */ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() { - private lateinit var callback: ConfigDialogCallback - private lateinit var config: Config - private var isNightMode = false - interface ConfigDialogCallback { - fun onOrientationChange(orientation: Int) + companion object { + const val FADE_DAY_NIGHT_MODE = 500 + @JvmField val LOG_TAG:String = ConfigBottomSheetDialogFragment::class.java.simpleName } + private lateinit var config: Config + private var isNightMode = false + private lateinit var activityCallback: FolioActivityCallback + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return inflater.inflate(R.layout.view_config, container) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + if (activity is FolioActivity) + activityCallback = activity as FolioActivity + view.viewTreeObserver.addOnGlobalLayoutListener { val dialog = dialog as BottomSheetDialog val bottomSheet = dialog.findViewById(android.support.design.R.id.design_bottom_sheet) as FrameLayout? @@ -82,11 +91,16 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() { UiUtil.setColorToImage(activity, config.themeColor, view_config_ib_day_mode!!.drawable) UiUtil.setColorToImage(activity, R.color.app_gray, view_config_ib_night_mode.drawable) } - - callback = activity as ConfigDialogCallback } private fun inflateView() { + + if (config.allowedDirection != Config.AllowedDirection.VERTICAL_AND_HORIZONTAL) { + view5.visibility = View.GONE + buttonVertical.visibility = View.GONE + buttonHorizontal.visibility = View.GONE + } + view_config_ib_day_mode.setOnClickListener { isNightMode = true toggleBlackTheme() @@ -97,41 +111,57 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() { UiUtil.setColorToImage(activity, R.color.app_gray, view_config_ib_night_mode.drawable) UiUtil.setColorToImage(activity, config.themeColor, view_config_ib_day_mode.drawable) } + view_config_ib_night_mode.setOnClickListener { isNightMode = false toggleBlackTheme() view_config_ib_day_mode.isSelected = false view_config_ib_night_mode.isSelected = true - UiUtil.setColorToImage(activity, config.themeColor, view_config_ib_day_mode.drawable) - UiUtil.setColorToImage(activity, R.color.app_gray, view_config_ib_night_mode.drawable) + UiUtil.setColorToImage(activity, R.color.app_gray, view_config_ib_day_mode.drawable) + UiUtil.setColorToImage(activity, config.themeColor, view_config_ib_night_mode.drawable) setToolBarColor() setAudioPlayerBackground() } - view_config_btn_vertical_orientation.isSelected = true + + if (activityCallback.direction == Config.Direction.HORIZONTAL) { + buttonHorizontal.isSelected = true + } else if (activityCallback.direction == Config.Direction.VERTICAL) { + buttonVertical.isSelected = true + } + + buttonVertical.setOnClickListener { + config = AppUtil.getSavedConfig(context) + config.direction = Config.Direction.VERTICAL + AppUtil.saveConfig(context, config) + activityCallback.onDirectionChange(Config.Direction.VERTICAL) + buttonHorizontal.isSelected = false + buttonVertical.isSelected = true + } + + buttonHorizontal.setOnClickListener { + config = AppUtil.getSavedConfig(context) + config.direction = Config.Direction.HORIZONTAL + AppUtil.saveConfig(context, config) + activityCallback.onDirectionChange(Config.Direction.HORIZONTAL) + buttonHorizontal.isSelected = true + buttonVertical.isSelected = false + } } private fun configFonts() { - view_config_font_andada.setTextColor(UiUtil.getColorList(activity, config.themeColor, R.color.grey_color)) - view_config_font_lato.setTextColor(UiUtil.getColorList(activity, config.themeColor, R.color.grey_color)) - view_config_font_lora.setTextColor(UiUtil.getColorList(activity, config.themeColor, R.color.grey_color)) - view_config_font_raleway.setTextColor(UiUtil.getColorList(activity, config.themeColor, R.color.grey_color)) - view_config_btn_vertical_orientation.setTextColor(UiUtil.getColorList(activity, config.themeColor, R.color.grey_color)) - view_config_btn_horizontal_orientation.setTextColor(UiUtil.getColorList(activity, config.themeColor, R.color.grey_color)) + + val colorStateList = UiUtil.getColorList(activity, config.themeColor, R.color.grey_color) + buttonVertical.setTextColor(colorStateList) + buttonHorizontal.setTextColor(colorStateList) + view_config_font_andada.setTextColor(colorStateList) + view_config_font_lato.setTextColor(colorStateList) + view_config_font_lora.setTextColor(colorStateList) + view_config_font_raleway.setTextColor(colorStateList) + view_config_font_andada.setOnClickListener { selectFont(Constants.FONT_ANDADA, true) } view_config_font_lato.setOnClickListener { selectFont(Constants.FONT_LATO, true) } view_config_font_lora.setOnClickListener { selectFont(Constants.FONT_LORA, true) } view_config_font_raleway.setOnClickListener { selectFont(Constants.FONT_RALEWAY, true) } - view_config_btn_vertical_orientation.setOnClickListener { - callback.onOrientationChange(1) - view_config_btn_horizontal_orientation.isSelected = false - view_config_btn_vertical_orientation.isSelected = true - } - - view_config_btn_horizontal_orientation.setOnClickListener { - callback.onOrientationChange(0) - view_config_btn_horizontal_orientation.isSelected = true - view_config_btn_vertical_orientation.isSelected = false - } } private fun selectFont(selectedFont: Int, isReloadNeeded: Boolean) { @@ -156,11 +186,14 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() { } private fun toggleBlackTheme() { + val day = ContextCompat.getColor(context!!, R.color.white) val night = ContextCompat.getColor(context!!, R.color.night) + val colorAnimation = ValueAnimator.ofObject(ArgbEvaluator(), if (isNightMode) night else day, if (isNightMode) day else night) colorAnimation.duration = FADE_DAY_NIGHT_MODE.toLong() + colorAnimation.addUpdateListener { animator -> val value = animator.animatedValue as Int container.setBackgroundColor(value) @@ -182,6 +215,28 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() { }) colorAnimation.duration = FADE_DAY_NIGHT_MODE.toLong() + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + + val attrs = intArrayOf(android.R.attr.navigationBarColor) + val typedArray = activity?.theme?.obtainStyledAttributes(attrs) + val defaultNavigationBarColor = typedArray?.getColor(0, + ContextCompat.getColor(context!!, R.color.white)) + val black = ContextCompat.getColor(context!!, R.color.black) + + val navigationColorAnim = ValueAnimator.ofObject(ArgbEvaluator(), + if (isNightMode) black else defaultNavigationBarColor, + if (isNightMode) defaultNavigationBarColor else black) + + navigationColorAnim.addUpdateListener { valueAnimator -> + val value = valueAnimator.animatedValue as Int + activity?.window?.navigationBarColor = value + } + + navigationColorAnim.duration = FADE_DAY_NIGHT_MODE.toLong() + navigationColorAnim.start() + } + colorAnimation.start() } @@ -220,8 +275,4 @@ class ConfigBottomSheetDialogFragment : BottomSheetDialogFragment() { (context as Activity).findViewById(R.id.container).setBackgroundColor(ContextCompat.getColor(context!!, R.color.night)) } } - - companion object { - const val FADE_DAY_NIGHT_MODE = 500 - } } diff --git a/folioreader/src/main/java/com/folioreader/view/DirectionalViewpager.java b/folioreader/src/main/java/com/folioreader/view/DirectionalViewpager.java index 7ea607bac..fd5a67ca7 100644 --- a/folioreader/src/main/java/com/folioreader/view/DirectionalViewpager.java +++ b/folioreader/src/main/java/com/folioreader/view/DirectionalViewpager.java @@ -48,6 +48,7 @@ import android.view.animation.Interpolator; import android.widget.Scroller; +import com.folioreader.Config; import com.folioreader.R; import java.lang.reflect.Method; @@ -4109,6 +4110,11 @@ public void setDirection(Direction direction) { initViewPager(); } + public void setDirection(Config.Direction direction) { + mDirection = direction.name(); + initViewPager(); + } + private String logDestroyItem(int pos, View object) { return "populate() - destroyItem() with pos: " + pos + " view: " + object; } diff --git a/folioreader/src/main/java/com/folioreader/view/FolioToolbar.kt b/folioreader/src/main/java/com/folioreader/view/FolioToolbar.kt index bedc2d992..cea80ae3c 100644 --- a/folioreader/src/main/java/com/folioreader/view/FolioToolbar.kt +++ b/folioreader/src/main/java/com/folioreader/view/FolioToolbar.kt @@ -20,7 +20,7 @@ import kotlinx.android.synthetic.main.folio_toolbar.view.* */ class FolioToolbar : RelativeLayout { private lateinit var config: Config - private var visible: Boolean = false + var visible: Boolean = true lateinit var callback: FolioToolbarCallback constructor(context: Context) : this(context, null, 0) @@ -65,9 +65,7 @@ class FolioToolbar : RelativeLayout { } fun setTitle(title: String?) { - title?.let { - label_center?.text = title - } + label_center?.text = title } fun showOrHideIfVisible() { @@ -79,7 +77,7 @@ class FolioToolbar : RelativeLayout { visible = !visible } - private fun show() { + fun show() { this.animate().translationY(0f) .setInterpolator(DecelerateInterpolator(2f)) .start() @@ -95,10 +93,10 @@ class FolioToolbar : RelativeLayout { label_center.setTextColor(ContextCompat.getColor(context, R.color.black)) } - private fun hide() { - this.animate().translationY((-this.height) + fun hide() { + post({ this.animate().translationY((-this.height) .toFloat()) .setInterpolator(AccelerateInterpolator(2f)) - .start() + .start() }) } } diff --git a/folioreader/src/main/java/com/folioreader/view/FolioWebView.java b/folioreader/src/main/java/com/folioreader/view/FolioWebView.java new file mode 100644 index 000000000..08091ccef --- /dev/null +++ b/folioreader/src/main/java/com/folioreader/view/FolioWebView.java @@ -0,0 +1,261 @@ +package com.folioreader.view; + +import android.content.Context; +import android.os.Handler; +import android.support.v4.view.GestureDetectorCompat; +import android.util.AttributeSet; +import android.util.Log; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.webkit.JavascriptInterface; +import android.webkit.WebView; + +import com.folioreader.Config; +import com.folioreader.R; +import com.folioreader.ui.folio.activity.FolioActivityCallback; + +/** + * @author by mahavir on 3/31/16. + */ +public class FolioWebView extends WebView + implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener { + + private static final String LOG_TAG = FolioWebView.class.getSimpleName(); + private float touchSlop; + private int horizontalPageCount = 0; + private float density; + private ScrollListener mScrollListener; + private SeekBarListener mSeekBarListener; + private ToolBarListener mToolBarListener; + private GestureDetectorCompat gestureDetector; + private MotionEvent eventActionDown; + private int pageWidthCssPixels; + private WebViewPager webViewPager; + private Handler handler; + private FolioActivityCallback folioActivityCallback; + + public FolioWebView(Context context) { + super(context); + if (!isInEditMode()) + init(); + } + + public FolioWebView(Context context, AttributeSet attrs) { + super(context, attrs); + if (!isInEditMode()) + init(); + } + + public FolioWebView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + if (!isInEditMode()) + init(); + } + + private void init() { + + handler = new Handler(); + gestureDetector = new GestureDetectorCompat(getContext(), this); + gestureDetector.setOnDoubleTapListener(this); + density = getResources().getDisplayMetrics().density; + touchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); + } + + @SuppressWarnings("unused") + @JavascriptInterface + public void setCompatMode(String compatMode) { + Log.v(LOG_TAG, "-> setCompatMode -> compatMode = " + compatMode); + if (compatMode.equals(getContext().getString(R.string.back_compat))) { + Log.e(LOG_TAG, "-> Web page loaded in Quirks mode. Please report to developer " + + "for debugging with current EPUB file as many features might stop working " + + "(ex. Horizontal scroll feature)."); + } + } + + public void setFolioActivityCallback(FolioActivityCallback folioActivityCallback) { + this.folioActivityCallback = folioActivityCallback; + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + + double widthDp = Math.ceil((getMeasuredWidth() / density)); + pageWidthCssPixels = (int) (widthDp * density); + } + + public void setScrollListener(ScrollListener listener) { + mScrollListener = listener; + } + + public void setSeekBarListener(SeekBarListener listener) { + mSeekBarListener = listener; + } + + public void setToolBarListener(ToolBarListener listener) { + mToolBarListener = listener; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + //Log.v(LOG_TAG, "-> onTouchEvent -> " + AppUtil.actionToString(event.getAction())); + + hideOrShowToolBar(event); + + if (folioActivityCallback.getDirection() == Config.Direction.HORIZONTAL) { + return computeHorizontalScroll(event); + } else { + return computeVerticalScroll(event); + } + } + + private boolean computeVerticalScroll(MotionEvent event) { + return super.onTouchEvent(event); + } + + private boolean computeHorizontalScroll(MotionEvent event) { + //Log.v(LOG_TAG, "-> computeHorizontalScroll"); + + webViewPager.dispatchTouchEvent(event); + boolean gestureReturn = gestureDetector.onTouchEvent(event); + if (gestureReturn) + return true; + return super.onTouchEvent(event); + } + + public int getScrollXForPage(int page) { + //Log.v(LOG_TAG, "-> getScrollXForPage -> page = " + page); + return page * pageWidthCssPixels; + } + + private void hideOrShowToolBar(MotionEvent event) { + + switch (event.getAction()) { + + case MotionEvent.ACTION_DOWN: + eventActionDown = MotionEvent.obtain(event); + if (mSeekBarListener != null) + mSeekBarListener.fadeInSeekBarIfInvisible(); + break; + + case MotionEvent.ACTION_UP: + if (mToolBarListener != null && + ((Math.abs(event.getY() - eventActionDown.getY()) < touchSlop) && + (Math.abs(event.getX() - eventActionDown.getX()) < touchSlop))) { + //SingleTap + mToolBarListener.hideOrShowToolBar(); + } + break; + } + } + + public void setHorizontalPageCount(int horizontalPageCount) { + this.horizontalPageCount = horizontalPageCount; + + handler.post(new Runnable() { + @Override + public void run() { + if (webViewPager == null) + webViewPager = ((View) getParent()).findViewById(R.id.webViewPager); + + webViewPager.setHorizontalPageCount(FolioWebView.this.horizontalPageCount); + } + }); + } + + @Override + protected void onScrollChanged(int l, int t, int oldl, int oldt) { + if (mToolBarListener != null) mToolBarListener.hideToolBarIfVisible(); + if (mScrollListener != null) mScrollListener.onScrollChange(t); + super.onScrollChanged(l, t, oldl, oldt); + } + + public int getContentHeightVal() { + return (int) Math.floor(this.getContentHeight() * this.getScale()); + } + + public int getWebViewHeight() { + return this.getMeasuredHeight(); + } + + @Override + public boolean onDown(MotionEvent event) { + //Log.v(LOG_TAG, "-> onDown -> " + event.toString()); + + eventActionDown = MotionEvent.obtain(event); + super.onTouchEvent(event); + return true; + } + + @Override + public boolean onFling(MotionEvent event1, MotionEvent event2, + float velocityX, float velocityY) { + + if (!webViewPager.isScrolling()) { + //TODO: -> check for right edge to left flings from right edge + // Need to complete the scroll as ViewPager thinks these touch events should not + // scroll it's pages. + //Log.d(LOG_TAG, "-> onFling -> completing scroll"); + invalidate(); + scrollTo(getScrollXForPage(webViewPager.getCurrentItem()), 0); + } + return true; + } + + @Override + public void onLongPress(MotionEvent event) { + //Log.v(LOG_TAG, "-> onLongPress -> " + event.toString()); + } + + @Override + public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, + float distanceY) { + //Log.v(LOG_TAG, "-> onScroll -> " + event1.toString() + event2.toString() + ", distanceX = " + distanceX + ", distanceY = " + distanceY); + return false; + } + + @Override + public void onShowPress(MotionEvent event) { + //Log.v(LOG_TAG, "-> onShowPress -> " + event.toString()); + } + + @Override + public boolean onSingleTapUp(MotionEvent event) { + //Log.v(LOG_TAG, "-> onSingleTapUp -> " + event.toString()); + return false; + } + + @Override + public boolean onDoubleTap(MotionEvent event) { + //Log.v(LOG_TAG, "-> onDoubleTap -> " + event.toString()); + return false; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent event) { + //Log.v(LOG_TAG, "-> onDoubleTapEvent -> " + event.toString()); + return false; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent event) { + //Log.v(LOG_TAG, "-> onSingleTapConfirmed -> " + event.toString()); + return false; + } + + public interface ScrollListener { + void onScrollChange(int percent); + } + + public interface SeekBarListener { + void fadeInSeekBarIfInvisible(); + } + + public interface ToolBarListener { + void hideOrShowToolBar(); + + void hideToolBarIfVisible(); + } +} diff --git a/folioreader/src/main/java/com/folioreader/view/LoadingView.java b/folioreader/src/main/java/com/folioreader/view/LoadingView.java new file mode 100644 index 000000000..8baa5701f --- /dev/null +++ b/folioreader/src/main/java/com/folioreader/view/LoadingView.java @@ -0,0 +1,110 @@ +package com.folioreader.view; + +import android.content.Context; +import android.os.Handler; +import android.support.constraint.ConstraintLayout; +import android.support.v4.content.ContextCompat; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.webkit.JavascriptInterface; +import android.widget.FrameLayout; +import android.widget.ProgressBar; + +import com.folioreader.Config; +import com.folioreader.R; +import com.folioreader.util.AppUtil; +import com.folioreader.util.UiUtil; + +@SuppressWarnings("PMD.AvoidDuplicateLiterals") +public class LoadingView extends FrameLayout { + + private ConstraintLayout rootView; + private ProgressBar progressBar; + private static final int VISIBLE_DURATION = 6000; + private Handler handler; + + private Runnable hideRunnable = new Runnable() { + @Override + public void run() { + hide(); + } + }; + + private static final String LOG_TAG = LoadingView.class.getSimpleName(); + + public LoadingView(Context context) { + super(context); + init(context, null, 0); + } + + public LoadingView(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0); + } + + public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context, attrs, defStyleAttr); + } + + private void init(Context context, AttributeSet attrs, int defStyleAttr) { + + LayoutInflater.from(context).inflate(R.layout.view_loading, this); + + if (isInEditMode()) + return; + + handler = new Handler(); + rootView = findViewById(R.id.rootView); + progressBar = findViewById(R.id.progressBar); + + updateTheme(); + show(); + } + + public void updateTheme() { + + Config config = AppUtil.getSavedConfig(getContext()); + if (config == null) + config = new Config(); + UiUtil.setColorToImage(getContext(), config.getThemeColor(), progressBar.getIndeterminateDrawable()); + if (config.isNightMode()) { + rootView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.webview_night)); + } else { + rootView.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.white)); + } + } + + @SuppressWarnings("unused") + @JavascriptInterface + public void show() { + //Log.d(LOG_TAG, "-> show"); + + handler.removeCallbacks(hideRunnable); + setVisibility(VISIBLE); + handler.postDelayed(hideRunnable, VISIBLE_DURATION); + } + + @SuppressWarnings("unused") + @JavascriptInterface + public void hide() { + //Log.d(LOG_TAG, "-> hide"); + + handler.removeCallbacks(hideRunnable); + setVisibility(INVISIBLE); + } + + @SuppressWarnings("unused") + @JavascriptInterface + public void visible() { + //Log.d(LOG_TAG, "-> visible"); + setVisibility(VISIBLE); + } + + @SuppressWarnings("unused") + @JavascriptInterface + public void invisible() { + //Log.d(LOG_TAG, "-> invisible"); + setVisibility(INVISIBLE); + } +} diff --git a/folioreader/src/main/java/com/folioreader/view/ObservableWebView.java b/folioreader/src/main/java/com/folioreader/view/ObservableWebView.java deleted file mode 100644 index d472a31d3..000000000 --- a/folioreader/src/main/java/com/folioreader/view/ObservableWebView.java +++ /dev/null @@ -1,171 +0,0 @@ -package com.folioreader.view; - -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build; -import android.util.AttributeSet; -import android.view.ActionMode; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MotionEvent; -import android.view.View; -import android.webkit.WebView; - -/** - * Created by mahavir on 3/31/16. - */ -public class ObservableWebView extends WebView { - - private float mDownPosX = 0; - private float mDownPosY = 0; - - public interface ScrollListener { - void onScrollChange(int percent); - } - - public interface SeekBarListener { - void fadeInSeekBarIfInvisible(); - } - - public interface ToolBarListener { - void hideOrShowToolBar(); - } - - private ScrollListener mScrollListener; - private SeekBarListener mSeekBarListener; - private ToolBarListener mToolBarListener; - - public ObservableWebView(Context context) { - super(context); - } - - public ObservableWebView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ObservableWebView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public ObservableWebView(Context context, AttributeSet attrs, - int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - } - - public void setScrollListener(ScrollListener listener) { - mScrollListener = listener; - } - - public void setSeekBarListener(SeekBarListener listener) { - mSeekBarListener = listener; - } - - public void setToolBarListener(ToolBarListener listener) { - mToolBarListener = listener; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - final int action = event.getAction(); - float MOVE_THRESHOLD_DP = 20 * getResources().getDisplayMetrics().density; - - switch (action) { - case MotionEvent.ACTION_DOWN: - mDownPosX = event.getX(); - mDownPosY = event.getY(); - if (mSeekBarListener != null) mSeekBarListener.fadeInSeekBarIfInvisible(); - break; - case MotionEvent.ACTION_UP: - if (mToolBarListener != null && - (Math.abs(event.getX() - mDownPosX) < MOVE_THRESHOLD_DP - || Math.abs(event.getY() - mDownPosY) < MOVE_THRESHOLD_DP)) { - mToolBarListener.hideOrShowToolBar(); - } - break; - } - return super.onTouchEvent(event); - } - - @Override - protected void onScrollChanged(int l, int t, int oldl, int oldt) { - if (mToolBarListener != null) mToolBarListener.hideOrShowToolBar(); - if (mScrollListener != null) mScrollListener.onScrollChange(t); - super.onScrollChanged(l, t, oldl, oldt); - } - - public int getContentHeightVal() { - return (int) Math.floor(this.getContentHeight() * this.getScale()); - } - - public int getWebViewHeight() { - return this.getMeasuredHeight(); - } - - @Override - public ActionMode startActionMode(ActionMode.Callback callback, int type) { - return this.dummyActionMode(); - } - - @Override - public ActionMode startActionMode(ActionMode.Callback callback) { - return this.dummyActionMode(); - } - - public ActionMode dummyActionMode() { - return new ActionMode() { - @Override - public void setTitle(CharSequence title) { - } - - @Override - public void setTitle(int resId) { - } - - @Override - public void setSubtitle(CharSequence subtitle) { - } - - @Override - public void setSubtitle(int resId) { - } - - @Override - public void setCustomView(View view) { - } - - @Override - public void invalidate() { - } - - @Override - public void finish() { - } - - @Override - public Menu getMenu() { - return null; - } - - @Override - public CharSequence getTitle() { - return null; - } - - @Override - public CharSequence getSubtitle() { - return null; - } - - @Override - public View getCustomView() { - return null; - } - - @Override - public MenuInflater getMenuInflater() { - return null; - } - }; - } -} diff --git a/folioreader/src/main/java/com/folioreader/view/WebViewPager.java b/folioreader/src/main/java/com/folioreader/view/WebViewPager.java new file mode 100644 index 000000000..91678c9ca --- /dev/null +++ b/folioreader/src/main/java/com/folioreader/view/WebViewPager.java @@ -0,0 +1,192 @@ +package com.folioreader.view; + +import android.content.Context; +import android.os.Handler; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.JavascriptInterface; + +import com.folioreader.R; + +public class WebViewPager extends ViewPager { + + private static final String LOG_TAG = WebViewPager.class.getSimpleName(); + private int horizontalPageCount; + private FolioWebView folioWebView; + private boolean takeOverScrolling; + private boolean scrolling; + private Handler handler; + + public WebViewPager(@NonNull Context context) { + super(context); + init(); + } + + public WebViewPager(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + + handler = new Handler(); + + addOnPageChangeListener(new OnPageChangeListener() { + @Override + public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { +// Log.d(LOG_TAG, "-> onPageScrolled -> position = " + position + +// ", positionOffset = " + positionOffset + ", positionOffsetPixels = " + positionOffsetPixels); + + scrolling = true; + + if (takeOverScrolling && folioWebView != null) { + int scrollX = folioWebView.getScrollXForPage(position) + positionOffsetPixels; + //Log.d(LOG_TAG, "-> onPageScrolled -> scrollX = " + scrollX); + folioWebView.scrollTo(scrollX, 0); + } + + if (positionOffsetPixels == 0) { + takeOverScrolling = false; + scrolling = false; + } + } + + @Override + public void onPageSelected(int position) { + Log.v(LOG_TAG, "-> onPageSelected -> " + position); + } + + @Override + public void onPageScrollStateChanged(int state) { + } + }); + } + + public boolean isScrolling() { + return scrolling; + } + + private String getScrollStateString(int state) { + switch (state) { + case SCROLL_STATE_IDLE: + return "SCROLL_STATE_IDLE"; + case SCROLL_STATE_DRAGGING: + return "SCROLL_STATE_DRAGGING"; + case SCROLL_STATE_SETTLING: + return "SCROLL_STATE_SETTLING"; + default: + return "UNKNOWN_STATE"; + } + } + + public void setHorizontalPageCount(int horizontalPageCount) { + //Log.d(LOG_TAG, "-> horizontalPageCount = " + horizontalPageCount); + + this.horizontalPageCount = horizontalPageCount; + setAdapter(new WebViewPagerAdapter()); + setCurrentItem(0); + + if (folioWebView == null) + folioWebView = ((View) getParent()).findViewById(R.id.folioWebView); + } + + @SuppressWarnings("unused") + @JavascriptInterface + public void setCurrentPage(final int pageIndex) { + Log.v(LOG_TAG, "-> setCurrentItem -> pageIndex = " + pageIndex); + + handler.post(new Runnable() { + @Override + public void run() { + folioWebView.postInvalidate(); + setCurrentItem(pageIndex, false); + } + }); + } + + @SuppressWarnings("unused") + @JavascriptInterface + public void setPageToLast() { + + handler.post(new Runnable() { + @Override + public void run() { + folioWebView.postInvalidate(); + setCurrentItem(horizontalPageCount - 1); + } + }); + } + + @SuppressWarnings("unused") + @JavascriptInterface + public void setPageToFirst() { + + handler.post(new Runnable() { + @Override + public void run() { + folioWebView.postInvalidate(); + setCurrentItem(0); + } + }); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + //Log.d(LOG_TAG, "-> onTouchEvent -> " + AppUtil.actionToString(event.getAction())); + + boolean superReturn = super.onTouchEvent(event); + + if (event.getAction() == MotionEvent.ACTION_UP) + takeOverScrolling = true; + + return superReturn; + } + + private class WebViewPagerAdapter extends PagerAdapter { + + @Override + public int getCount() { + return horizontalPageCount; + } + + @Override + public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { + return view == object; + } + + @NonNull + @Override + public Object instantiateItem(@NonNull ViewGroup container, int position) { + + View view = LayoutInflater.from(container.getContext()) + .inflate(R.layout.view_webview_pager, container, false); + + // Debug code + // Set alpha for folioWebView in folio_page_fragment.xml to 0.5f also. + /*if (position % 2 == 0) { + view.setBackgroundResource(R.drawable.green_border_background); + } else { + view.setBackgroundResource(R.drawable.blue_border_background); + } + + TextView textView = view.findViewById(R.id.textView); + textView.setText(Integer.toString(position));*/ + + container.addView(view); + return view; + } + + @Override + public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { + container.removeView((View) object); + } + } +} diff --git a/gradle.properties b/gradle.properties index 9f1fbf99c..5c64d0435 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,20 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx1536m +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true + VERSION_NAME=1.0 VERSION_CODE=1 -ANDROID_BUILD_TOOLS_VERSION=23.0.2 -ANDROID_COMPILE_SDK_VERSION=23 -ANDROID_TARGET_SDK_VERSION=23 +ANDROID_COMPILE_SDK_VERSION=28 +ANDROID_TARGET_SDK_VERSION=28 ANDROID_MIN_SDK=14 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 8c0fb64a8..7a3265ee9 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 868b7fb98..a0ac26c85 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Wed May 09 16:00:44 IST 2018 +#Tue Jun 05 17:41:05 IST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 91a7e269e..cccdd3d51 100755 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,31 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# For Cygwin, ensure paths are in UNIX format before anything is touched. -if $cygwin ; then - [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` -fi - -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >&- -APP_HOME="`pwd -P`" -cd "$SAVED" >&- - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -90,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -114,6 +113,7 @@ fi if $cygwin ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` @@ -154,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec99730b..e95643d6a 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/sample/.gitignore b/sample/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/sample/.gitignore @@ -0,0 +1 @@ +/build diff --git a/sample/build.gradle b/sample/build.gradle index 1e6d345a6..f1d4ccb3c 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -3,60 +3,60 @@ apply plugin: 'checkstyle' android { + compileSdkVersion Integer.parseInt(project.ANDROID_COMPILE_SDK_VERSION) + + defaultConfig { + applicationId "com.folioreader.android.sample" + minSdkVersion Integer.parseInt(project.ANDROID_MIN_SDK) + targetSdkVersion Integer.parseInt(project.ANDROID_TARGET_SDK_VERSION) + versionCode Integer.parseInt(project.VERSION_CODE) + versionName project.VERSION_NAME + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + dexOptions { + javaMaxHeapSize "4G" + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } - dexOptions { - javaMaxHeapSize "4G" - } - - compileSdkVersion 27 - buildToolsVersion "27.0.3" - - defaultConfig { - applicationId "com.folioreader.android.sample" - versionCode Integer.parseInt(project.VERSION_CODE) - versionName project.VERSION_NAME - minSdkVersion Integer.parseInt(project.ANDROID_MIN_SDK) - targetSdkVersion Integer.parseInt(project.ANDROID_TARGET_SDK_VERSION) - } - - sourceSets { - main { - manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = ['src/main/java'] - res.srcDirs = ['res'] + packagingOptions { + exclude 'META-INF/ASL2.0' + exclude 'META-INF/DEPENDENCIES.txt' + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + exclude 'META-INF/NOTICE' + exclude 'META-INF/LICENSE' + exclude 'META-INF/DEPENDENCIES' + exclude 'META-INF/notice.txt' + exclude 'META-INF/license.txt' + exclude 'META-INF/dependencies.txt' + exclude 'META-INF/LGPL2.1' + exclude 'META-INF/services/javax.annotation.processing.Processor' } - test { - java.srcDirs = ['src/test/java'] + + lintOptions { + abortOnError false } - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_7 - targetCompatibility JavaVersion.VERSION_1_7 - } - - packagingOptions { - exclude 'META-INF/ASL2.0' - exclude 'META-INF/DEPENDENCIES.txt' - exclude 'META-INF/LICENSE.txt' - exclude 'META-INF/NOTICE.txt' - exclude 'META-INF/NOTICE' - exclude 'META-INF/LICENSE' - exclude 'META-INF/DEPENDENCIES' - exclude 'META-INF/notice.txt' - exclude 'META-INF/license.txt' - exclude 'META-INF/dependencies.txt' - exclude 'META-INF/LGPL2.1' - exclude 'META-INF/services/javax.annotation.processing.Processor' - } - - lintOptions { - abortOnError false - } } dependencies { - implementation project(':folioreader') - implementation 'com.android.support.constraint:constraint-layout:1.1.0' - implementation 'com.android.support:appcompat-v7:27.1.1' + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation "com.android.support:appcompat-v7:$ANDROID_LIB_VERSION" + implementation 'com.android.support.constraint:constraint-layout:1.1.2' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + + implementation project(':folioreader') } diff --git a/sample/hs_err_pid10790.log b/sample/hs_err_pid10790.log deleted file mode 100644 index 4ef854fb6..000000000 --- a/sample/hs_err_pid10790.log +++ /dev/null @@ -1,636 +0,0 @@ -# -# There is insufficient memory for the Java Runtime Environment to continue. -# Native memory allocation (mmap) failed to map 286261248 bytes for committing reserved memory. -# Possible reasons: -# The system is out of physical RAM or swap space -# In 32 bit mode, the process size limit was hit -# Possible solutions: -# Reduce memory load on the system -# Increase physical memory or swap space -# Check if swap backing store is full -# Use 64 bit Java on a 64 bit OS -# Decrease Java heap size (-Xmx/-Xms) -# Decrease number of Java threads -# Decrease Java thread stack sizes (-Xss) -# Set larger code cache with -XX:ReservedCodeCacheSize= -# This output file may be truncated or incomplete. -# -# Out of Memory Error (os_linux.cpp:2627), pid=10790, tid=0x00007f832b0f0700 -# -# JRE version: OpenJDK Runtime Environment (8.0_112-b224) (build 1.8.0_112-release-b736) -# Java VM: OpenJDK 64-Bit Server VM (25.112-b736 mixed mode linux-amd64 compressed oops) -# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again -# - ---------------- T H R E A D --------------- - -Current thread (0x00007f8354077800): VMThread [stack: 0x00007f832aff0000,0x00007f832b0f1000] [id=10813] - -Stack: [0x00007f832aff0000,0x00007f832b0f1000], sp=0x00007f832b0ef4c0, free space=1021k -Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) -V [libjvm.so+0x9e476d] VMError::report_and_die()+0x15d -V [libjvm.so+0x4b6ada] report_vm_out_of_memory(char const*, int, unsigned long, VMErrorType, char const*)+0x8a -V [libjvm.so+0x84c890] os::pd_commit_memory(char*, unsigned long, unsigned long, bool)+0xf0 -V [libjvm.so+0x8473af] os::commit_memory(char*, unsigned long, unsigned long, bool)+0x1f -V [libjvm.so+0x8bd40b] PSVirtualSpace::expand_by(unsigned long)+0x5b -V [libjvm.so+0x8be080] PSYoungGen::resize_generation(unsigned long, unsigned long)+0xb0 -V [libjvm.so+0x8be39b] PSYoungGen::resize(unsigned long, unsigned long)+0x1b -V [libjvm.so+0x8baa8c] PSScavenge::invoke_no_policy()+0xdac -V [libjvm.so+0x8bb268] PSScavenge::invoke()+0x38 -V [libjvm.so+0x86fd23] ParallelScavengeHeap::failed_mem_allocate(unsigned long)+0x63 -V [libjvm.so+0x9e6234] VM_ParallelGCFailedAllocation::doit()+0x84 -V [libjvm.so+0x9ea647] VM_Operation::evaluate()+0x47 -V [libjvm.so+0x9e9108] VMThread::evaluate_operation(VM_Operation*)+0x2c8 -V [libjvm.so+0x9e9589] VMThread::loop()+0x219 -V [libjvm.so+0x9e99d2] VMThread::run()+0x72 -V [libjvm.so+0x849cb2] java_start(Thread*)+0xf2 - -VM_Operation (0x00007f835c73ae90): ParallelGCFailedAllocation, mode: safepoint, requested by thread 0x00007f835400a000 - - ---------------- P R O C E S S --------------- - -Java Threads: ( => current thread ) - 0x00007f83540bf800 JavaThread "Service Thread" daemon [_thread_blocked, id=10840, stack(0x00007f832a611000,0x00007f832a712000)] - 0x00007f83540bc800 JavaThread "C1 CompilerThread2" daemon [_thread_blocked, id=10836, stack(0x00007f832a712000,0x00007f832a813000)] - 0x00007f83540ba800 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=10834, stack(0x00007f832a813000,0x00007f832a914000)] - 0x00007f83540b8000 JavaThread "C2 CompilerThread0" daemon [_thread_blocked, id=10829, stack(0x00007f832a914000,0x00007f832aa15000)] - 0x00007f83540b6800 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=10826, stack(0x00007f832aa15000,0x00007f832ab16000)] - 0x00007f8354084000 JavaThread "Finalizer" daemon [_thread_blocked, id=10817, stack(0x00007f832adee000,0x00007f832aeef000)] - 0x00007f835407f000 JavaThread "Reference Handler" daemon [_thread_blocked, id=10816, stack(0x00007f832aeef000,0x00007f832aff0000)] - 0x00007f835400a000 JavaThread "main" [_thread_blocked, id=10792, stack(0x00007f835c63c000,0x00007f835c73d000)] - -Other Threads: -=>0x00007f8354077800 VMThread [stack: 0x00007f832aff0000,0x00007f832b0f1000] [id=10813] - 0x00007f83540c2000 WatcherThread [stack: 0x00007f832a510000,0x00007f832a611000] [id=10841] - -VM state:at safepoint (normal execution) - -VM Mutex/Monitor currently owned by a thread: ([mutex/lock_event]) -[0x00007f83540066c0] Threads_lock - owner thread: 0x00007f8354077800 -[0x00007f8354006bc0] Heap_lock - owner thread: 0x00007f835400a000 - -Heap: - PSYoungGen total 274944K, used 29165K [0x000000076ab00000, 0x000000077d800000, 0x00000007c0000000) - eden space 245760K, 0% used [0x000000076ab00000,0x000000076ab00000,0x0000000779b00000) - from space 29184K, 99% used [0x0000000779b00000,0x000000077b77b708,0x000000077b780000) - to space 25088K, 0% used [0x000000077b780000,0x000000077b780000,0x000000077d000000) - ParOldGen total 83456K, used 70447K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 84% used [0x00000006c0000000,0x00000006c44cbdd8,0x00000006c5180000) - Metaspace used 6472K, capacity 7218K, committed 7296K, reserved 1056768K - class space used 595K, capacity 618K, committed 640K, reserved 1048576K - -Card table byte_map: [0x00007f8358cca000,0x00007f83594cb000] byte_map_base: 0x00007f83556ca000 - -Marking Bits: (ParMarkBitMap*) 0x00007f835bb06340 - Begin Bits: [0x00007f833d000000, 0x00007f8341000000) - End Bits: [0x00007f8341000000, 0x00007f8345000000) - -Polling page: 0x00007f835c758000 - -CodeCache: size=245760Kb used=8073Kb max_used=8073Kb free=237686Kb - bounds [0x00007f8345000000, 0x00007f83457f0000, 0x00007f8354000000] - total_blobs=2392 nmethods=2124 adapters=182 - compilation: enabled - -Compilation events (10 events): -Event: 10.106 Thread 0x00007f83540bc800 2433 3 com.android.dx.dex.code.StdCatchBuilder::hasAnyCatches (57 bytes) -Event: 10.107 Thread 0x00007f83540bc800 nmethod 2433 0x00007f83457e11d0 code [0x00007f83457e13e0, 0x00007f83457e20f8] -Event: 10.183 Thread 0x00007f83540bc800 2434 % 3 com.android.dx.dex.file.CodeItem::addContents @ 142 (174 bytes) -Event: 10.189 Thread 0x00007f83540bc800 nmethod 2434% 0x00007f83457e2650 code [0x00007f83457e2960, 0x00007f83457e43c8] -Event: 10.189 Thread 0x00007f83540bc800 2435 3 com.android.dx.dex.file.CodeItem::addContents (174 bytes) -Event: 10.190 Thread 0x00007f83540bc800 nmethod 2435 0x00007f83457e4ed0 code [0x00007f83457e51e0, 0x00007f83457e6be8] -Event: 10.305 Thread 0x00007f83540bc800 2439 2 java.util.HashSet:: (17 bytes) -Event: 10.305 Thread 0x00007f83540bc800 nmethod 2439 0x00007f83457e76d0 code [0x00007f83457e7860, 0x00007f83457e7a68] -Event: 10.308 Thread 0x00007f83540bc800 2440 2 com.android.dx.dex.code.StdCatchBuilder::getCatchTypes (97 bytes) -Event: 10.309 Thread 0x00007f83540bc800 nmethod 2440 0x00007f83457e7b50 code [0x00007f83457e7d60, 0x00007f83457e8318] - -GC Heap History (10 events): -Event: 3.371 GC heap after -Heap after GC invocations=2 (full 0): - PSYoungGen total 67584K, used 5106K [0x000000076ab00000, 0x000000076f200000, 0x00000007c0000000) - eden space 62464K, 0% used [0x000000076ab00000,0x000000076ab00000,0x000000076e800000) - from space 5120K, 99% used [0x000000076ed00000,0x000000076f1fcb58,0x000000076f200000) - to space 5120K, 0% used [0x000000076e800000,0x000000076e800000,0x000000076ed00000) - ParOldGen total 83456K, used 5754K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 6% used [0x00000006c0000000,0x00000006c059eaa8,0x00000006c5180000) - Metaspace used 5812K, capacity 6832K, committed 7040K, reserved 1056768K - class space used 570K, capacity 616K, committed 640K, reserved 1048576K -} -Event: 4.660 GC heap before -{Heap before GC invocations=3 (full 0): - PSYoungGen total 67584K, used 67570K [0x000000076ab00000, 0x000000076f200000, 0x00000007c0000000) - eden space 62464K, 100% used [0x000000076ab00000,0x000000076e800000,0x000000076e800000) - from space 5120K, 99% used [0x000000076ed00000,0x000000076f1fcb58,0x000000076f200000) - to space 5120K, 0% used [0x000000076e800000,0x000000076e800000,0x000000076ed00000) - ParOldGen total 83456K, used 5754K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 6% used [0x00000006c0000000,0x00000006c059eaa8,0x00000006c5180000) - Metaspace used 5897K, capacity 6896K, committed 7040K, reserved 1056768K - class space used 571K, capacity 616K, committed 640K, reserved 1048576K -Event: 4.811 GC heap after -Heap after GC invocations=3 (full 0): - PSYoungGen total 67584K, used 5106K [0x000000076ab00000, 0x0000000772f00000, 0x00000007c0000000) - eden space 62464K, 0% used [0x000000076ab00000,0x000000076ab00000,0x000000076e800000) - from space 5120K, 99% used [0x000000076e800000,0x000000076ecfc810,0x000000076ed00000) - to space 5120K, 0% used [0x0000000772a00000,0x0000000772a00000,0x0000000772f00000) - ParOldGen total 83456K, used 15268K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 18% used [0x00000006c0000000,0x00000006c0ee9128,0x00000006c5180000) - Metaspace used 5897K, capacity 6896K, committed 7040K, reserved 1056768K - class space used 571K, capacity 616K, committed 640K, reserved 1048576K -} -Event: 5.410 GC heap before -{Heap before GC invocations=4 (full 0): - PSYoungGen total 67584K, used 67570K [0x000000076ab00000, 0x0000000772f00000, 0x00000007c0000000) - eden space 62464K, 100% used [0x000000076ab00000,0x000000076e800000,0x000000076e800000) - from space 5120K, 99% used [0x000000076e800000,0x000000076ecfc810,0x000000076ed00000) - to space 5120K, 0% used [0x0000000772a00000,0x0000000772a00000,0x0000000772f00000) - ParOldGen total 83456K, used 15268K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 18% used [0x00000006c0000000,0x00000006c0ee9128,0x00000006c5180000) - Metaspace used 5969K, capacity 6960K, committed 7040K, reserved 1056768K - class space used 571K, capacity 616K, committed 640K, reserved 1048576K -Event: 5.496 GC heap after -Heap after GC invocations=4 (full 0): - PSYoungGen total 130048K, used 5094K [0x000000076ab00000, 0x0000000772f00000, 0x00000007c0000000) - eden space 124928K, 0% used [0x000000076ab00000,0x000000076ab00000,0x0000000772500000) - from space 5120K, 99% used [0x0000000772a00000,0x0000000772ef9850,0x0000000772f00000) - to space 5120K, 0% used [0x0000000772500000,0x0000000772500000,0x0000000772a00000) - ParOldGen total 83456K, used 23906K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 28% used [0x00000006c0000000,0x00000006c1758878,0x00000006c5180000) - Metaspace used 5969K, capacity 6960K, committed 7040K, reserved 1056768K - class space used 571K, capacity 616K, committed 640K, reserved 1048576K -} -Event: 6.593 GC heap before -{Heap before GC invocations=5 (full 0): - PSYoungGen total 130048K, used 130022K [0x000000076ab00000, 0x0000000772f00000, 0x00000007c0000000) - eden space 124928K, 100% used [0x000000076ab00000,0x0000000772500000,0x0000000772500000) - from space 5120K, 99% used [0x0000000772a00000,0x0000000772ef9850,0x0000000772f00000) - to space 5120K, 0% used [0x0000000772500000,0x0000000772500000,0x0000000772a00000) - ParOldGen total 83456K, used 23906K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 28% used [0x00000006c0000000,0x00000006c1758878,0x00000006c5180000) - Metaspace used 6101K, capacity 7088K, committed 7296K, reserved 1056768K - class space used 571K, capacity 616K, committed 640K, reserved 1048576K -Event: 6.745 GC heap after -Heap after GC invocations=5 (full 0): - PSYoungGen total 130048K, used 5099K [0x000000076ab00000, 0x000000077d000000, 0x00000007c0000000) - eden space 124928K, 0% used [0x000000076ab00000,0x000000076ab00000,0x0000000772500000) - from space 5120K, 99% used [0x0000000772500000,0x00000007729fae18,0x0000000772a00000) - to space 25088K, 0% used [0x000000077b780000,0x000000077b780000,0x000000077d000000) - ParOldGen total 83456K, used 42782K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 51% used [0x00000006c0000000,0x00000006c29c7af0,0x00000006c5180000) - Metaspace used 6101K, capacity 7088K, committed 7296K, reserved 1056768K - class space used 571K, capacity 616K, committed 640K, reserved 1048576K -} -Event: 7.800 GC heap before -{Heap before GC invocations=6 (full 0): - PSYoungGen total 130048K, used 130027K [0x000000076ab00000, 0x000000077d000000, 0x00000007c0000000) - eden space 124928K, 100% used [0x000000076ab00000,0x0000000772500000,0x0000000772500000) - from space 5120K, 99% used [0x0000000772500000,0x00000007729fae18,0x0000000772a00000) - to space 25088K, 0% used [0x000000077b780000,0x000000077b780000,0x000000077d000000) - ParOldGen total 83456K, used 42782K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 51% used [0x00000006c0000000,0x00000006c29c7af0,0x00000006c5180000) - Metaspace used 6202K, capacity 7152K, committed 7296K, reserved 1056768K - class space used 571K, capacity 616K, committed 640K, reserved 1048576K -Event: 7.944 GC heap after -Heap after GC invocations=6 (full 0): - PSYoungGen total 270848K, used 24117K [0x000000076ab00000, 0x000000077d800000, 0x00000007c0000000) - eden space 245760K, 0% used [0x000000076ab00000,0x000000076ab00000,0x0000000779b00000) - from space 25088K, 96% used [0x000000077b780000,0x000000077cf0d438,0x000000077d000000) - to space 29184K, 0% used [0x0000000779b00000,0x0000000779b00000,0x000000077b780000) - ParOldGen total 83456K, used 42782K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 51% used [0x00000006c0000000,0x00000006c29c7af0,0x00000006c5180000) - Metaspace used 6202K, capacity 7152K, committed 7296K, reserved 1056768K - class space used 571K, capacity 616K, committed 640K, reserved 1048576K -} -Event: 10.575 GC heap before -{Heap before GC invocations=7 (full 0): - PSYoungGen total 270848K, used 269877K [0x000000076ab00000, 0x000000077d800000, 0x00000007c0000000) - eden space 245760K, 100% used [0x000000076ab00000,0x0000000779b00000,0x0000000779b00000) - from space 25088K, 96% used [0x000000077b780000,0x000000077cf0d438,0x000000077d000000) - to space 29184K, 0% used [0x0000000779b00000,0x0000000779b00000,0x000000077b780000) - ParOldGen total 83456K, used 42782K [0x00000006c0000000, 0x00000006c5180000, 0x000000076ab00000) - object space 83456K, 51% used [0x00000006c0000000,0x00000006c29c7af0,0x00000006c5180000) - Metaspace used 6472K, capacity 7218K, committed 7296K, reserved 1056768K - class space used 595K, capacity 618K, committed 640K, reserved 1048576K - -Deoptimization events (10 events): -Event: 8.554 Thread 0x00007f8354132000 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f83452f7074 method=java.util.HashMap.putVal(ILjava/lang/Object;Ljava/lang/Object;ZZ)Ljava/lang/Object; @ 162 -Event: 8.566 Thread 0x00007f8354132000 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f834520c658 method=java.util.HashMap.getNode(ILjava/lang/Object;)Ljava/util/HashMap$Node; @ 84 -Event: 8.566 Thread 0x00007f8354132000 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f83456800bc method=java.util.HashMap.getNode(ILjava/lang/Object;)Ljava/util/HashMap$Node; @ 84 -Event: 9.263 Thread 0x00007f8354132000 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f83454ee508 method=com.android.dx.ssa.SCCP.simulateStmt(Lcom/android/dx/ssa/SsaInsn;)V @ 53 -Event: 9.523 Thread 0x00007f835413b000 Uncommon trap: reason=unstable_if action=reinterpret pc=0x00007f83456b7cc8 method=java.util.HashMap.putVal(ILjava/lang/Object;Ljava/lang/Object;ZZ)Ljava/lang/Object; @ 162 -Event: 9.728 Thread 0x00007f835400a000 Uncommon trap: reason=class_check action=maybe_recompile pc=0x00007f834540409c method=java.util.Arrays.hashCode([Ljava/lang/Object;)I @ 43 -Event: 9.728 Thread 0x00007f835400a000 Uncommon trap: reason=class_check action=maybe_recompile pc=0x00007f834540409c method=java.util.Arrays.hashCode([Ljava/lang/Object;)I @ 43 -Event: 9.729 Thread 0x00007f835400a000 Uncommon trap: reason=class_check action=maybe_recompile pc=0x00007f834540409c method=java.util.Arrays.hashCode([Ljava/lang/Object;)I @ 43 -Event: 9.729 Thread 0x00007f835400a000 Uncommon trap: reason=class_check action=maybe_recompile pc=0x00007f834540409c method=java.util.Arrays.hashCode([Ljava/lang/Object;)I @ 43 -Event: 9.729 Thread 0x00007f835400a000 Uncommon trap: reason=class_check action=maybe_recompile pc=0x00007f83453f94bc method=java.util.Arrays.hashCode([Ljava/lang/Object;)I @ 43 - -Internal exceptions (7 events): -Event: 0.055 Thread 0x00007f835400a000 Exception (0x000000076ab07c78) thrown at [/ssd/Android/AOSP-openjdk-git/jdk8u/hotspot/src/share/vm/prims/jni.cp -Event: 0.056 Thread 0x00007f835400a000 Exception (0x000000076ab07f60) thrown at [/ssd/Android/AOSP-openjdk-git/jdk8u/hotspot/src/share/vm/prims/jni.cpp, line 4011] -Event: 2.560 Thread 0x00007f835413b000 Implicit null exception at 0x00007f83452d990a to 0x00007f83452dc01d -Event: 3.904 Thread 0x00007f835413e800 Implicit null exception at 0x00007f8345273162 to 0x00007f834527325b -Event: 8.561 Thread 0x00007f8354132000 Exception (0x000000077092b7a0) thrown at [/ssd/Android/AOSP-openjdk-git/jdk8u/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp, line 366] -Event: 8.562 Thread 0x00007f8354132000 Exception (0x000000077092d320) thrown at [/ssd/Android/AOSP-openjdk-git/jdk8u/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp, line 366] -Event: 8.564 Thread 0x00007f8354132000 Exception (0x000000077092e608) thrown at [/ssd/Android/AOSP-openjdk-git/jdk8u/hotspot/src/share/vm/runtime/sharedRuntime.cpp, line 605] - -Events (10 events): -Event: 9.970 Thread 0x00007f835400a000 DEOPT UNPACKING pc=0x00007f8345047373 sp=0x00007f835c73b198 mode 0 -Event: 9.972 Thread 0x00007f835400a000 DEOPT PACKING pc=0x00007f8345530819 sp=0x00007f835c73b4b0 -Event: 9.972 Thread 0x00007f835400a000 DEOPT UNPACKING pc=0x00007f8345047373 sp=0x00007f835c73b200 mode 0 -Event: 9.989 Thread 0x00007f835400a000 DEOPT PACKING pc=0x00007f83457d68d6 sp=0x00007f835c73b4b0 -Event: 9.989 Thread 0x00007f835400a000 DEOPT UNPACKING pc=0x00007f8345047373 sp=0x00007f835c73b260 mode 0 -Event: 10.107 Thread 0x00007f835400a000 DEOPT PACKING pc=0x00007f83457d7314 sp=0x00007f835c73b4e0 -Event: 10.107 Thread 0x00007f835400a000 DEOPT UNPACKING pc=0x00007f8345047373 sp=0x00007f835c73b250 mode 0 -Event: 10.190 Thread 0x00007f835400a000 DEOPT PACKING pc=0x00007f83457d7fe8 sp=0x00007f835c73b570 -Event: 10.190 Thread 0x00007f835400a000 DEOPT UNPACKING pc=0x00007f8345047373 sp=0x00007f835c73b310 mode 0 -Event: 10.575 Executing VM operation: ParallelGCFailedAllocation - - -Dynamic libraries: -00400000-00401000 r-xp 00000000 08:05 1336328 /home/gautam/android-studio-3/jre/bin/java -00600000-00601000 r--p 00000000 08:05 1336328 /home/gautam/android-studio-3/jre/bin/java -00601000-00602000 rw-p 00001000 08:05 1336328 /home/gautam/android-studio-3/jre/bin/java -00d5e000-00d7f000 rw-p 00000000 00:00 0 [heap] -6c0000000-6c5180000 rw-p 00000000 00:00 0 -6c5180000-76ab00000 ---p 00000000 00:00 0 -76ab00000-77d800000 rw-p 00000000 00:00 0 -78e900000-7c0000000 ---p 00000000 00:00 0 -7c0000000-7c00a0000 rw-p 00000000 00:00 0 -7c00a0000-800000000 ---p 00000000 00:00 0 -7f82ec000000-7f82ec021000 rw-p 00000000 00:00 0 -7f82ec021000-7f82f0000000 ---p 00000000 00:00 0 -7f82f4000000-7f82f4028000 rw-p 00000000 00:00 0 -7f82f4028000-7f82f8000000 ---p 00000000 00:00 0 -7f82f8000000-7f82f8021000 rw-p 00000000 00:00 0 -7f82f8021000-7f82fc000000 ---p 00000000 00:00 0 -7f82fc000000-7f82fc033000 rw-p 00000000 00:00 0 -7f82fc033000-7f8300000000 ---p 00000000 00:00 0 -7f8300000000-7f8300021000 rw-p 00000000 00:00 0 -7f8300021000-7f8304000000 ---p 00000000 00:00 0 -7f8304000000-7f8304021000 rw-p 00000000 00:00 0 -7f8304021000-7f8308000000 ---p 00000000 00:00 0 -7f8308000000-7f8308021000 rw-p 00000000 00:00 0 -7f8308021000-7f830c000000 ---p 00000000 00:00 0 -7f830c000000-7f830ca26000 rw-p 00000000 00:00 0 -7f830ca26000-7f8310000000 ---p 00000000 00:00 0 -7f8310000000-7f8310a2d000 rw-p 00000000 00:00 0 -7f8310a2d000-7f8314000000 ---p 00000000 00:00 0 -7f8314000000-7f8314cb4000 rw-p 00000000 00:00 0 -7f8314cb4000-7f8318000000 ---p 00000000 00:00 0 -7f8318000000-7f8318021000 rw-p 00000000 00:00 0 -7f8318021000-7f831c000000 ---p 00000000 00:00 0 -7f831c000000-7f831c021000 rw-p 00000000 00:00 0 -7f831c021000-7f8320000000 ---p 00000000 00:00 0 -7f8320000000-7f8320021000 rw-p 00000000 00:00 0 -7f8320021000-7f8324000000 ---p 00000000 00:00 0 -7f8324000000-7f832427e000 rw-p 00000000 00:00 0 -7f832427e000-7f8328000000 ---p 00000000 00:00 0 -7f832a00b000-7f832a00e000 ---p 00000000 00:00 0 -7f832a00e000-7f832a10c000 rw-p 00000000 00:00 0 -7f832a10c000-7f832a10f000 ---p 00000000 00:00 0 -7f832a10f000-7f832a20d000 rw-p 00000000 00:00 0 -7f832a20d000-7f832a210000 ---p 00000000 00:00 0 -7f832a210000-7f832a30e000 rw-p 00000000 00:00 0 -7f832a30e000-7f832a311000 ---p 00000000 00:00 0 -7f832a311000-7f832a40f000 rw-p 00000000 00:00 0 -7f832a40f000-7f832a412000 ---p 00000000 00:00 0 -7f832a412000-7f832a510000 rw-p 00000000 00:00 0 -7f832a510000-7f832a511000 ---p 00000000 00:00 0 -7f832a511000-7f832a611000 rw-p 00000000 00:00 0 -7f832a611000-7f832a614000 ---p 00000000 00:00 0 -7f832a614000-7f832a712000 rw-p 00000000 00:00 0 -7f832a712000-7f832a715000 ---p 00000000 00:00 0 -7f832a715000-7f832a813000 rw-p 00000000 00:00 0 -7f832a813000-7f832a816000 ---p 00000000 00:00 0 -7f832a816000-7f832a914000 rw-p 00000000 00:00 0 -7f832a914000-7f832a917000 ---p 00000000 00:00 0 -7f832a917000-7f832aa15000 rw-p 00000000 00:00 0 -7f832aa15000-7f832aa18000 ---p 00000000 00:00 0 -7f832aa18000-7f832ab16000 rw-p 00000000 00:00 0 -7f832ab16000-7f832adee000 r--p 00000000 08:05 1703 /usr/lib/locale/locale-archive -7f832adee000-7f832adf1000 ---p 00000000 00:00 0 -7f832adf1000-7f832aeef000 rw-p 00000000 00:00 0 -7f832aeef000-7f832aef2000 ---p 00000000 00:00 0 -7f832aef2000-7f832aff0000 rw-p 00000000 00:00 0 -7f832aff0000-7f832aff1000 ---p 00000000 00:00 0 -7f832aff1000-7f832c000000 rw-p 00000000 00:00 0 -7f832c000000-7f832c021000 rw-p 00000000 00:00 0 -7f832c021000-7f8330000000 ---p 00000000 00:00 0 -7f8330000000-7f8330021000 rw-p 00000000 00:00 0 -7f8330021000-7f8334000000 ---p 00000000 00:00 0 -7f8334000000-7f8334021000 rw-p 00000000 00:00 0 -7f8334021000-7f8338000000 ---p 00000000 00:00 0 -7f8338000000-7f8338021000 rw-p 00000000 00:00 0 -7f8338021000-7f833c000000 ---p 00000000 00:00 0 -7f833c000000-7f833c680000 rw-p 00000000 00:00 0 -7f833c680000-7f833c800000 ---p 00000000 00:00 0 -7f833c800000-7f8345000000 rw-p 00000000 00:00 0 -7f8345000000-7f83457f0000 rwxp 00000000 00:00 0 -7f83457f0000-7f8354000000 ---p 00000000 00:00 0 -7f8354000000-7f835437a000 rw-p 00000000 00:00 0 -7f835437a000-7f8358000000 ---p 00000000 00:00 0 -7f8358038000-7f835812b000 rw-p 00000000 00:00 0 -7f835812b000-7f83582fa000 r--s 03c21000 08:05 1336386 /home/gautam/android-studio-3/jre/jre/lib/rt.jar -7f83582fa000-7f8358370000 rw-p 00000000 00:00 0 -7f8358370000-7f8358371000 ---p 00000000 00:00 0 -7f8358371000-7f8358471000 rw-p 00000000 00:00 0 -7f8358471000-7f8358472000 ---p 00000000 00:00 0 -7f8358472000-7f8358572000 rw-p 00000000 00:00 0 -7f8358572000-7f8358573000 ---p 00000000 00:00 0 -7f8358573000-7f8358673000 rw-p 00000000 00:00 0 -7f8358673000-7f8358674000 ---p 00000000 00:00 0 -7f8358674000-7f835879d000 rw-p 00000000 00:00 0 -7f835879d000-7f8358cca000 ---p 00000000 00:00 0 -7f8358cca000-7f8358cf3000 rw-p 00000000 00:00 0 -7f8358cf3000-7f835921f000 ---p 00000000 00:00 0 -7f835921f000-7f83592b6000 rw-p 00000000 00:00 0 -7f83592b6000-7f83594ca000 ---p 00000000 00:00 0 -7f83594ca000-7f83594eb000 rw-p 00000000 00:00 0 -7f83594eb000-7f835988b000 ---p 00000000 00:00 0 -7f835988b000-7f83598a5000 r-xp 00000000 08:05 1336414 /home/gautam/android-studio-3/jre/jre/lib/amd64/libzip.so -7f83598a5000-7f8359aa5000 ---p 0001a000 08:05 1336414 /home/gautam/android-studio-3/jre/jre/lib/amd64/libzip.so -7f8359aa5000-7f8359aa6000 r--p 0001a000 08:05 1336414 /home/gautam/android-studio-3/jre/jre/lib/amd64/libzip.so -7f8359aa6000-7f8359aa7000 rw-p 0001b000 08:05 1336414 /home/gautam/android-studio-3/jre/jre/lib/amd64/libzip.so -7f8359aa7000-7f8359ab2000 r-xp 00000000 08:05 1836131 /lib/x86_64-linux-gnu/libnss_files-2.23.so -7f8359ab2000-7f8359cb1000 ---p 0000b000 08:05 1836131 /lib/x86_64-linux-gnu/libnss_files-2.23.so -7f8359cb1000-7f8359cb2000 r--p 0000a000 08:05 1836131 /lib/x86_64-linux-gnu/libnss_files-2.23.so -7f8359cb2000-7f8359cb3000 rw-p 0000b000 08:05 1836131 /lib/x86_64-linux-gnu/libnss_files-2.23.so -7f8359cb3000-7f8359cb9000 rw-p 00000000 00:00 0 -7f8359cb9000-7f8359cc4000 r-xp 00000000 08:05 1836123 /lib/x86_64-linux-gnu/libnss_nis-2.23.so -7f8359cc4000-7f8359ec3000 ---p 0000b000 08:05 1836123 /lib/x86_64-linux-gnu/libnss_nis-2.23.so -7f8359ec3000-7f8359ec4000 r--p 0000a000 08:05 1836123 /lib/x86_64-linux-gnu/libnss_nis-2.23.so -7f8359ec4000-7f8359ec5000 rw-p 0000b000 08:05 1836123 /lib/x86_64-linux-gnu/libnss_nis-2.23.so -7f8359ec5000-7f8359edb000 r-xp 00000000 08:05 1836125 /lib/x86_64-linux-gnu/libnsl-2.23.so -7f8359edb000-7f835a0da000 ---p 00016000 08:05 1836125 /lib/x86_64-linux-gnu/libnsl-2.23.so -7f835a0da000-7f835a0db000 r--p 00015000 08:05 1836125 /lib/x86_64-linux-gnu/libnsl-2.23.so -7f835a0db000-7f835a0dc000 rw-p 00016000 08:05 1836125 /lib/x86_64-linux-gnu/libnsl-2.23.so -7f835a0dc000-7f835a0de000 rw-p 00000000 00:00 0 -7f835a0de000-7f835a0e6000 r-xp 00000000 08:05 1836135 /lib/x86_64-linux-gnu/libnss_compat-2.23.so -7f835a0e6000-7f835a2e5000 ---p 00008000 08:05 1836135 /lib/x86_64-linux-gnu/libnss_compat-2.23.so -7f835a2e5000-7f835a2e6000 r--p 00007000 08:05 1836135 /lib/x86_64-linux-gnu/libnss_compat-2.23.so -7f835a2e6000-7f835a2e7000 rw-p 00008000 08:05 1836135 /lib/x86_64-linux-gnu/libnss_compat-2.23.so -7f835a2e7000-7f835a314000 r-xp 00000000 08:05 1336424 /home/gautam/android-studio-3/jre/jre/lib/amd64/libjava.so -7f835a314000-7f835a513000 ---p 0002d000 08:05 1336424 /home/gautam/android-studio-3/jre/jre/lib/amd64/libjava.so -7f835a513000-7f835a514000 r--p 0002c000 08:05 1336424 /home/gautam/android-studio-3/jre/jre/lib/amd64/libjava.so -7f835a514000-7f835a516000 rw-p 0002d000 08:05 1336424 /home/gautam/android-studio-3/jre/jre/lib/amd64/libjava.so -7f835a516000-7f835a526000 r-xp 00000000 08:05 1336440 /home/gautam/android-studio-3/jre/jre/lib/amd64/libverify.so -7f835a526000-7f835a725000 ---p 00010000 08:05 1336440 /home/gautam/android-studio-3/jre/jre/lib/amd64/libverify.so -7f835a725000-7f835a727000 r--p 0000f000 08:05 1336440 /home/gautam/android-studio-3/jre/jre/lib/amd64/libverify.so -7f835a727000-7f835a728000 rw-p 00011000 08:05 1336440 /home/gautam/android-studio-3/jre/jre/lib/amd64/libverify.so -7f835a728000-7f835a72f000 r-xp 00000000 08:05 1836153 /lib/x86_64-linux-gnu/librt-2.23.so -7f835a72f000-7f835a92e000 ---p 00007000 08:05 1836153 /lib/x86_64-linux-gnu/librt-2.23.so -7f835a92e000-7f835a92f000 r--p 00006000 08:05 1836153 /lib/x86_64-linux-gnu/librt-2.23.so -7f835a92f000-7f835a930000 rw-p 00007000 08:05 1836153 /lib/x86_64-linux-gnu/librt-2.23.so -7f835a930000-7f835aa38000 r-xp 00000000 08:05 1836124 /lib/x86_64-linux-gnu/libm-2.23.so -7f835aa38000-7f835ac37000 ---p 00108000 08:05 1836124 /lib/x86_64-linux-gnu/libm-2.23.so -7f835ac37000-7f835ac38000 r--p 00107000 08:05 1836124 /lib/x86_64-linux-gnu/libm-2.23.so -7f835ac38000-7f835ac39000 rw-p 00108000 08:05 1836124 /lib/x86_64-linux-gnu/libm-2.23.so -7f835ac39000-7f835b829000 r-xp 00000000 08:05 1336444 /home/gautam/android-studio-3/jre/jre/lib/amd64/server/libjvm.so -7f835b829000-7f835ba29000 ---p 00bf0000 08:05 1336444 /home/gautam/android-studio-3/jre/jre/lib/amd64/server/libjvm.so -7f835ba29000-7f835bac8000 r--p 00bf0000 08:05 1336444 /home/gautam/android-studio-3/jre/jre/lib/amd64/server/libjvm.so -7f835bac8000-7f835baf1000 rw-p 00c8f000 08:05 1336444 /home/gautam/android-studio-3/jre/jre/lib/amd64/server/libjvm.so -7f835baf1000-7f835bb35000 rw-p 00000000 00:00 0 -7f835bb35000-7f835bb4d000 r-xp 00000000 08:05 1836160 /lib/x86_64-linux-gnu/libpthread-2.23.so -7f835bb4d000-7f835bd4c000 ---p 00018000 08:05 1836160 /lib/x86_64-linux-gnu/libpthread-2.23.so -7f835bd4c000-7f835bd4d000 r--p 00017000 08:05 1836160 /lib/x86_64-linux-gnu/libpthread-2.23.so -7f835bd4d000-7f835bd4e000 rw-p 00018000 08:05 1836160 /lib/x86_64-linux-gnu/libpthread-2.23.so -7f835bd4e000-7f835bd52000 rw-p 00000000 00:00 0 -7f835bd52000-7f835bd55000 r-xp 00000000 08:05 1836122 /lib/x86_64-linux-gnu/libdl-2.23.so -7f835bd55000-7f835bf54000 ---p 00003000 08:05 1836122 /lib/x86_64-linux-gnu/libdl-2.23.so -7f835bf54000-7f835bf55000 r--p 00002000 08:05 1836122 /lib/x86_64-linux-gnu/libdl-2.23.so -7f835bf55000-7f835bf56000 rw-p 00003000 08:05 1836122 /lib/x86_64-linux-gnu/libdl-2.23.so -7f835bf56000-7f835c115000 r-xp 00000000 08:05 1836126 /lib/x86_64-linux-gnu/libc-2.23.so -7f835c115000-7f835c315000 ---p 001bf000 08:05 1836126 /lib/x86_64-linux-gnu/libc-2.23.so -7f835c315000-7f835c319000 r--p 001bf000 08:05 1836126 /lib/x86_64-linux-gnu/libc-2.23.so -7f835c319000-7f835c31b000 rw-p 001c3000 08:05 1836126 /lib/x86_64-linux-gnu/libc-2.23.so -7f835c31b000-7f835c31f000 rw-p 00000000 00:00 0 -7f835c31f000-7f835c335000 r-xp 00000000 08:05 1336302 /home/gautam/android-studio-3/jre/lib/amd64/jli/libjli.so -7f835c335000-7f835c534000 ---p 00016000 08:05 1336302 /home/gautam/android-studio-3/jre/lib/amd64/jli/libjli.so -7f835c534000-7f835c535000 r--p 00015000 08:05 1336302 /home/gautam/android-studio-3/jre/lib/amd64/jli/libjli.so -7f835c535000-7f835c536000 rw-p 00016000 08:05 1336302 /home/gautam/android-studio-3/jre/lib/amd64/jli/libjli.so -7f835c536000-7f835c55c000 r-xp 00000000 08:05 1836127 /lib/x86_64-linux-gnu/ld-2.23.so -7f835c569000-7f835c63c000 rw-p 00000000 00:00 0 -7f835c63c000-7f835c63f000 ---p 00000000 00:00 0 -7f835c63f000-7f835c741000 rw-p 00000000 00:00 0 -7f835c741000-7f835c74f000 r--s 000e0000 08:05 932687 /home/gautam/Android/Sdk/build-tools/25.0.0/lib/dx.jar -7f835c74f000-7f835c757000 rw-s 00000000 08:05 1194232 /tmp/hsperfdata_gautam/10790 -7f835c757000-7f835c758000 rw-p 00000000 00:00 0 -7f835c758000-7f835c759000 ---p 00000000 00:00 0 -7f835c759000-7f835c75b000 rw-p 00000000 00:00 0 -7f835c75b000-7f835c75c000 r--p 00025000 08:05 1836127 /lib/x86_64-linux-gnu/ld-2.23.so -7f835c75c000-7f835c75d000 rw-p 00026000 08:05 1836127 /lib/x86_64-linux-gnu/ld-2.23.so -7f835c75d000-7f835c75e000 rw-p 00000000 00:00 0 -7fff3b477000-7fff3b498000 rw-p 00000000 00:00 0 [stack] -7fff3b4f0000-7fff3b4f2000 r--p 00000000 00:00 0 [vvar] -7fff3b4f2000-7fff3b4f4000 r-xp 00000000 00:00 0 [vdso] -ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] - -VM Arguments: -jvm_args: -Djava.awt.headless=true -Xmx4G -Dfile.encoding=UTF-8 -Duser.country=IN -Duser.language=en -Duser.variant -java_command: com.android.dx.command.Main --dex --num-threads=4 --output /home/gautam/workspace/work/FolioReader-Android/sample/build/intermediates/pre-dexed/debug/jackson-databind-2.8.6_f01c2a29d5fb6662f6d226bb5ea7931a9ac47a70.jar /home/gautam/.gradle/caches/modules-2/files-2.1/com.fasterxml.jackson.core/jackson-databind/2.8.6/c43de61f74ecc61322ef8f402837ba65b0aa2bf4/jackson-databind-2.8.6.jar -java_class_path (initial): /home/gautam/Android/Sdk/build-tools/25.0.0/lib/dx.jar -Launcher Type: SUN_STANDARD - -Environment Variables: -JAVA_HOME=/usr/local/java/jdk1.8.0_65 -JRE_HOME=/usr/local/java/jre -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/bin:/bin -LD_LIBRARY_PATH=/home/gautam/android-studio-3/bin: -SHELL=/bin/bash -DISPLAY=:0 - -Signal Handlers: -SIGSEGV: [libjvm.so+0x9e5260], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO -SIGBUS: [libjvm.so+0x9e5260], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO -SIGFPE: [libjvm.so+0x848480], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO -SIGPIPE: [libjvm.so+0x848480], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO -SIGXFSZ: [libjvm.so+0x848480], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO -SIGILL: [libjvm.so+0x848480], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO -SIGUSR1: SIG_DFL, sa_mask[0]=00000000000000000000000000000000, sa_flags=none -SIGUSR2: [libjvm.so+0x848350], sa_mask[0]=00100000000000000000000000000000, sa_flags=SA_RESTART|SA_SIGINFO -SIGHUP: [libjvm.so+0x848540], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO -SIGINT: [libjvm.so+0x848540], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO -SIGTERM: [libjvm.so+0x848540], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO -SIGQUIT: [libjvm.so+0x848540], sa_mask[0]=11111111011111111101111111111110, sa_flags=SA_RESTART|SA_SIGINFO - - ---------------- S Y S T E M --------------- - -OS:DISTRIB_ID=Ubuntu -DISTRIB_RELEASE=16.04 -DISTRIB_CODENAME=xenial -DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS" - -uname:Linux 4.4.0-79-generic #100-Ubuntu SMP Wed May 17 19:58:14 UTC 2017 x86_64 -libc:glibc 2.23 NPTL 2.23 -rlimit: STACK 8192k, CORE 0k, NPROC 30580, NOFILE 65536, AS infinity -load average:6.07 2.17 1.13 - -/proc/meminfo: -MemTotal: 7869244 kB -MemFree: 156696 kB -MemAvailable: 70240 kB -Buffers: 1292 kB -Cached: 1064008 kB -SwapCached: 0 kB -Active: 6615360 kB -Inactive: 880956 kB -Active(anon): 6593172 kB -Inactive(anon): 861152 kB -Active(file): 22188 kB -Inactive(file): 19804 kB -Unevictable: 128 kB -Mlocked: 128 kB -SwapTotal: 0 kB -SwapFree: 0 kB -Dirty: 1176 kB -Writeback: 0 kB -AnonPages: 6431560 kB -Mapped: 352344 kB -Shmem: 1022972 kB -Slab: 98664 kB -SReclaimable: 54872 kB -SUnreclaim: 43792 kB -KernelStack: 13136 kB -PageTables: 50852 kB -NFS_Unstable: 0 kB -Bounce: 0 kB -WritebackTmp: 0 kB -CommitLimit: 3934620 kB -Committed_AS: 12828968 kB -VmallocTotal: 34359738367 kB -VmallocUsed: 0 kB -VmallocChunk: 0 kB -HardwareCorrupted: 0 kB -AnonHugePages: 3416064 kB -CmaTotal: 0 kB -CmaFree: 0 kB -HugePages_Total: 0 -HugePages_Free: 0 -HugePages_Rsvd: 0 -HugePages_Surp: 0 -Hugepagesize: 2048 kB -DirectMap4k: 155512 kB -DirectMap2M: 7923712 kB - - -CPU:total 4 (2 cores per cpu, 2 threads per core) family 6 model 58 stepping 9, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt, avx, aes, clmul, erms, ht, tsc, tscinvbit, tscinv - -/proc/cpuinfo: -processor : 0 -vendor_id : GenuineIntel -cpu family : 6 -model : 58 -model name : Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz -stepping : 9 -microcode : 0x1c -cpu MHz : 3099.992 -cache size : 3072 KB -physical id : 0 -siblings : 4 -core id : 0 -cpu cores : 2 -apicid : 0 -initial apicid : 0 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm epb tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt dtherm ida arat pln pts -bugs : -bogomips : 5188.09 -clflush size : 64 -cache_alignment : 64 -address sizes : 36 bits physical, 48 bits virtual -power management: - -processor : 1 -vendor_id : GenuineIntel -cpu family : 6 -model : 58 -model name : Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz -stepping : 9 -microcode : 0x1c -cpu MHz : 3099.992 -cache size : 3072 KB -physical id : 0 -siblings : 4 -core id : 0 -cpu cores : 2 -apicid : 1 -initial apicid : 1 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm epb tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt dtherm ida arat pln pts -bugs : -bogomips : 5188.09 -clflush size : 64 -cache_alignment : 64 -address sizes : 36 bits physical, 48 bits virtual -power management: - -processor : 2 -vendor_id : GenuineIntel -cpu family : 6 -model : 58 -model name : Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz -stepping : 9 -microcode : 0x1c -cpu MHz : 3099.992 -cache size : 3072 KB -physical id : 0 -siblings : 4 -core id : 1 -cpu cores : 2 -apicid : 2 -initial apicid : 2 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm epb tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt dtherm ida arat pln pts -bugs : -bogomips : 5188.09 -clflush size : 64 -cache_alignment : 64 -address sizes : 36 bits physical, 48 bits virtual -power management: - -processor : 3 -vendor_id : GenuineIntel -cpu family : 6 -model : 58 -model name : Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz -stepping : 9 -microcode : 0x1c -cpu MHz : 3099.992 -cache size : 3072 KB -physical id : 0 -siblings : 4 -core id : 1 -cpu cores : 2 -apicid : 3 -initial apicid : 3 -fpu : yes -fpu_exception : yes -cpuid level : 13 -wp : yes -flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf eagerfpu pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm epb tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms xsaveopt dtherm ida arat pln pts -bugs : -bogomips : 5188.09 -clflush size : 64 -cache_alignment : 64 -address sizes : 36 bits physical, 48 bits virtual -power management: - - - -Memory: 4k page, physical 7869244k(156696k free), swap 0k(0k free) - -vm_info: OpenJDK 64-Bit Server VM (25.112-b736) for linux-amd64 JRE (1.8.0_112-release-b736), built on Mar 6 2017 09:31:19 by "builder" with gcc 4.8.4 - -time: Thu Jun 8 15:56:01 2017 -elapsed time: 11 seconds (0d 0h 0m 11s) - diff --git a/sample/proguard-rules.pro b/sample/proguard-rules.pro new file mode 100644 index 000000000..f1b424510 --- /dev/null +++ b/sample/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/sample/res/mipmap-hdpi/ic_launcher.png b/sample/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index cde69bccc..000000000 Binary files a/sample/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/sample/res/mipmap-mdpi/ic_launcher.png b/sample/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index c133a0cbd..000000000 Binary files a/sample/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/sample/res/mipmap-xhdpi/ic_launcher.png b/sample/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index bfa42f0e7..000000000 Binary files a/sample/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/sample/res/mipmap-xxhdpi/ic_launcher.png b/sample/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 324e72cdd..000000000 Binary files a/sample/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/sample/res/values-w820dp/dimens.xml b/sample/res/values-w820dp/dimens.xml deleted file mode 100644 index f11f7450a..000000000 --- a/sample/res/values-w820dp/dimens.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/sample/res/values/dimens.xml b/sample/res/values/dimens.xml deleted file mode 100644 index f11f7450a..000000000 --- a/sample/res/values/dimens.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/sample/res/values/strings.xml b/sample/res/values/strings.xml deleted file mode 100644 index 64644c568..000000000 --- a/sample/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - FolioReader sample - - diff --git a/sample/res/values/styles.xml b/sample/res/values/styles.xml deleted file mode 100644 index 1355d0900..000000000 --- a/sample/res/values/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/sample/src/androidTest/java/com/folioreader/android/sample/ExampleInstrumentedTest.java b/sample/src/androidTest/java/com/folioreader/android/sample/ExampleInstrumentedTest.java new file mode 100644 index 000000000..414b25209 --- /dev/null +++ b/sample/src/androidTest/java/com/folioreader/android/sample/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.folioreader.android.sample; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.folioreader.android.sample", appContext.getPackageName()); + } +} diff --git a/sample/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml similarity index 68% rename from sample/AndroidManifest.xml rename to sample/src/main/AndroidManifest.xml index d34928ff6..330ec6898 100644 --- a/sample/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -1,32 +1,33 @@ + package="com.folioreader.android.sample"> + android:largeHeap="true" + android:networkSecurityConfig="@xml/network_security_config" + android:roundIcon="@mipmap/ic_launcher_round" + android:supportsRtl="false" + android:theme="@style/AppTheme"> + + android:label="@string/app_name"> - + - + android:theme="@style/AppTheme.NoActionBar" /> + - + \ No newline at end of file diff --git a/sample/src/main/java/com/folioreader/android/sample/HomeActivity.java b/sample/src/main/java/com/folioreader/android/sample/HomeActivity.java index 4a98f319b..8503046bd 100644 --- a/sample/src/main/java/com/folioreader/android/sample/HomeActivity.java +++ b/sample/src/main/java/com/folioreader/android/sample/HomeActivity.java @@ -1,18 +1,18 @@ /* -* Copyright (C) 2016 Pedro Paulo de Amorim -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ + * Copyright (C) 2016 Pedro Paulo de Amorim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package com.folioreader.android.sample; import android.os.Bundle; @@ -25,11 +25,13 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; +import com.folioreader.Config; +import com.folioreader.FolioReader; import com.folioreader.model.HighLight; import com.folioreader.model.ReadPosition; import com.folioreader.model.ReadPositionImpl; import com.folioreader.ui.base.OnSaveHighlight; -import com.folioreader.FolioReader; +import com.folioreader.util.AppUtil; import com.folioreader.util.ObjectMapperSingleton; import com.folioreader.util.OnHighlightListener; import com.folioreader.util.ReadPositionListener; @@ -56,49 +58,61 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { .setOnHighlightListener(this) .setReadPositionListener(this); + getHighlightsAndSave(); + findViewById(R.id.btn_raw).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - folioReader.openBook(R.raw.adventures); + + Config config = AppUtil.getSavedConfig(getApplicationContext()); + if (config == null) + config = new Config(); + + config.setAllowedDirection(Config.AllowedDirection.VERTICAL_AND_HORIZONTAL); + + folioReader.setConfig(config, true) + .openBook(R.raw.adventures); } }); findViewById(R.id.btn_assest).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - folioReader.openBook("file:///android_asset/TheSilverChair.epub"); + + ReadPosition readPosition = getLastReadPosition(); + + Config config = AppUtil.getSavedConfig(getApplicationContext()); + if (config == null) + config = new Config(); + + config.setAllowedDirection(Config.AllowedDirection.VERTICAL_AND_HORIZONTAL); + + folioReader.setReadPosition(readPosition) + .setConfig(config, true) + .openBook("file:///android_asset/TheSilverChair.epub"); } }); - - getHighlightsAndSave(); - getLastReadPosition(); } - private void getLastReadPosition() { + private ReadPosition getLastReadPosition() { - new Thread(new Runnable() { - @Override - public void run() { - - ObjectReader objectReader = ObjectMapperSingleton.getObjectMapper().reader(); - ReadPosition readPosition = null; + ReadPosition readPosition = null; + ObjectReader objectReader = ObjectMapperSingleton.getObjectMapper().reader(); - try { - readPosition = objectReader.forType(ReadPositionImpl.class) - .readValue(getAssets().open("read_positions/read_position.json")); - } catch (IOException e) { - e.printStackTrace(); - } + try { + readPosition = objectReader.forType(ReadPositionImpl.class) + .readValue(getAssets().open("read_positions/read_position.json")); + } catch (IOException e) { + e.printStackTrace(); + } - folioReader.setReadPosition(readPosition); - } - }).start(); + return readPosition; } @Override public void saveReadPosition(ReadPosition readPosition) { - Toast.makeText(this, "ReadPosition = " + readPosition.toJson(), Toast.LENGTH_SHORT).show(); + //Toast.makeText(this, "ReadPosition = " + readPosition.toJson(), Toast.LENGTH_SHORT).show(); Log.i(LOG_TAG, "-> ReadPosition = " + readPosition.toJson()); } diff --git a/sample/src/main/java/com/folioreader/android/sample/TestFragment.java b/sample/src/main/java/com/folioreader/android/sample/TestFragment.java deleted file mode 100644 index 5707b9142..000000000 --- a/sample/src/main/java/com/folioreader/android/sample/TestFragment.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.folioreader.android.sample; - -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.webkit.WebView; -import android.widget.LinearLayout; -import android.widget.TextView; - -/** - * Created by priyank on 4/1/16. - */ -public class TestFragment extends Fragment { - private static final String KEY_CONTENT = "TestFragment:Content"; - private static final String HTML = "\n" + - "The Silver Chair

The Silver Chair

C. S. Lewis

Copyright © 2014 epubBooks

All Rights Reserved.

This publication is protected by copyright. By payment of the required fees, you have been granted the non-exclusive, non-transferable right to access and read the text of this ebook on-screen or via personal text-to-speech computer systems. No part of this text may be reproduced, transmitted, downloaded, decompiled, reverse engineered, stored in or introduced into any information storage and retrieval system, in any form or by any means, whether electronic or mechanical, now known or hereinafter invented, without the express written permission of epubBooks.

This publication is protected by copyright. By payment of the required fees, you have been granted the non-exclusive, non-transferable right to access and read the text of this ebook on-screen or via personal text-to-speech computer systems. No part of this text may be reproduced, transmitted, downloaded, decompiled, reverse engineered, stored in or introduced into any information storage and retrieval system, in any form or by any means, whether electronic or mechanical, now known or hereinafter invented, without the express written permission of epubBooks.

\n" + - "www.epubbooks.com

Dedication

To

Nicholas Hardie