package com.masterofcode.android.EPubBookRender; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.Iterator; import java.util.Set; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.content.Intent; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.webkit.ConsoleMessage; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; import com.masterofcode.android.EPubBook.EPubBook; import com.masterofcode.android.magreader.EpubViewerActivity; import com.sandsmedia.apps.mobile.android.epub.lib.R; public class EPubBookTopicContainer extends Object { private static final int PAGINATION_DELAY_M = 1000; static final public int CONTENT_PAGE_FINISHED = 1; static final public int CONTENT_SCROLLING_FINISHED = 2; static final public int CONTENT_PAGINATION_FINISHED = 3; static final public int CONTENT_UPDATE_PAGE_INFO = 4; // static final public int CONTENT_UPDATE_PAGE_INFO = 4; static final public int REQUESTING_TOP_OFFSET_STATUS_NOT_DETERMINED = 0; static final public int REQUESTING_TOP_OFFSET_STATUS_IN_PROCESS = 1; static final public int REQUESTING_TOP_OFFSET_STATUS_PROCESSED = 2; static final public int CONTENT_LOADING_STATUS_NOT_LOADED = 0; static final public int CONTENT_LOADING_STATUS_LOADIN_IN_PROCESS = 1; static final public int CONTENT_LOADING_STATUS_LOADINF_FINISHED = 2; static final private int MESSAGE_CHANGE_CONTENT_OFFSET = 1; static final private int MISC_MESSAGE_PAGINATION = 1; static final private String EMPTY_HTML = "<html><head><style type='text/css'>body { background-color: #FFFFFF; width: 350px; margin: 1px }</style></head><body></body></html>"; private int topicId = -1; private boolean isTopicActual = false; private WebView mediaWebView; private ContentWebView contentWebView; private WebViewClient mediaWebClient; private WebViewClient contentWebClient; private View parentContainer; private Activity context; private boolean fullScreenMode; private String mediaURL, contentURL; private Handler topicHandler; private Handler parentScrollHandler; private String mediaJSON; private HashMap<String, EmbeddedMediaElement> mediaElements; private int requestingMediaElementsTopOffsetStatus = REQUESTING_TOP_OFFSET_STATUS_NOT_DETERMINED; private String contentBaseURL; private int contentLoadingStatus = CONTENT_LOADING_STATUS_NOT_LOADED; private int mediaLoadingStatus = CONTENT_LOADING_STATUS_NOT_LOADED; private float contentOffset = 0.0f; private boolean deviceOrientationIsLandscape = false; private int fontChangeFactor = -1; private int initialFontSize; private boolean isHighlightMode = false; @SuppressWarnings("unused") private EPubBook book = null; private int paginationPageCount = -1; private boolean paginationFinished = false; private int offsetHeightTries = 0; public EPubBookTopicContainer(final Activity context, boolean orientationIsLandscape, Handler ParentScrollHandler) { this.context = context; deviceOrientationIsLandscape = orientationIsLandscape; mediaElements = new HashMap<String, EmbeddedMediaElement>(); LayoutInflater inflater = context.getLayoutInflater(); parentContainer = inflater.inflate(R.layout.epub_container_layout, null); mediaWebView = (WebView) parentContainer.findViewById(R.id.mediaWebView); contentWebView = (ContentWebView) parentContainer.findViewById(R.id.contentWebView); if(!deviceOrientationIsLandscape)mediaWebView.setVisibility(View.GONE); // mediaWebView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); mediaWebView.getSettings().setBuiltInZoomControls(false); //mediaWebView.setInitialScale(100); //mediaWebView.getSettings().setDefaultZoom(ZoomDensity.FAR); // contentWebView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); parentScrollHandler = ParentScrollHandler; contentWebClient = new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if(url.startsWith("http://embedded_select/")) { jumpToMediaWithId(url.replace("http://embedded_select/", "")); } else if(url.startsWith("http://embedded_external/")) { showFullScreenMediaWithId(url.replace("http://embedded_external/", "")); } else { // open external url if(url.matches("(?i)^http(s|)://.*") || url.startsWith("www.")) { ((EpubViewerActivity)context).openLink(url); } } //Log.i("-------", "load url "+url); return true; } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); //Log.i("-------", "TOPIC id="+topicId+", loaded topic "+url); //messageHandler.sendMessageDelayed(messageHandler.obtainMessage(MESSAGE_CHANGE_CONTENT_OFFSET, 0, 0), 1000); // after loadind content, set buttons //if(parentScrollHandler != null)parentScrollHandler.sendMessageDelayed(parentScrollHandler.obtainMessage(CONTENT_SCROLLING_FINISHED, 0, 0), 1000); //if(parentScrollHandler != null)parentScrollHandler.sendMessageDelayed(parentScrollHandler.obtainMessage(CONTENT_SCROLLING_FINISHED, 0, 0), 2000); // scrollHandler.sendMessageDelayed(scrollHandler.obtainMessage(1, 0, 0), 500); //Log.i("---", "paginationFinished="+paginationFinished+", height="+contentWebView.getActualSizeHeight()); } }; contentWebView.setWebChromeClient(new WebChromeClient() { @Override public boolean onConsoleMessage(ConsoleMessage consoleMessage) { //storeContentWebConsoleMessage(consoleMessage.message(), consoleMessage.lineNumber(), consoleMessage.sourceId()); return true; } @Override public boolean onJsTimeout() { return false; } @Override public void onProgressChanged(WebView view, int newProgress) { super.onProgressChanged(view, newProgress); if(newProgress==100) { contentLoadingStatus = CONTENT_LOADING_STATUS_LOADINF_FINISHED; if(topicHandler != null) { topicHandler.sendMessage(topicHandler.obtainMessage(CONTENT_PAGE_FINISHED, 0, 0)); } if(!paginationFinished && contentWebView.getActualSizeHeight()!=-1) { //paginateContent(); } if(mediaURL!=null) requestContentMediaElementsTopOffset(); //messageHandler.sendMessage(messageHandler.obtainMessage(MESSAGE_CHANGE_CONTENT_OFFSET, 0, 0)); messageHandler.sendMessageDelayed(messageHandler.obtainMessage(MESSAGE_CHANGE_CONTENT_OFFSET, 0, 0), 100); } } }); contentWebView.setOnSizeChangeListener(new OnSizeChangedListener() { @Override public void onSizeChanged(int width, int height, int oldWidth, int oldHeight) { contentWebViewSizeChanged(width, height, oldWidth, oldHeight); } }); contentWebView.setOnScrollChangeListener(new OnScrollChangedListener() { @Override public void OnScrollChanged(int l, int t, int oldl, int oldt) { contentScrollChanged(l, t, oldl, oldt); } }); mediaWebClient = new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); mediaLoadingStatus = CONTENT_LOADING_STATUS_LOADINF_FINISHED; } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if(url.startsWith("http://embedded_select/")) { showFullScreenMediaWithId(url.replace("http://embedded_select/", "")); } // Log.i("-------", "load url "+url); return true; } }; mediaWebView.setWebViewClient(mediaWebClient); contentWebView.setWebViewClient(contentWebClient); mediaWebView.getSettings().setJavaScriptEnabled(true); contentWebView.getSettings().setJavaScriptEnabled(true); class ContentScriptInterface { @SuppressWarnings("unused") public void elementTop(String id, int topOffset) { EmbeddedMediaElement element = mediaElements.get(id); if(id!=null) { element.setTopOffset(topOffset); checkTopOffsetEndProcessing(); // Log.d("-------------", "id="+id+", top="+topOffset); } } @SuppressWarnings("unused") public void paginationFinished(int _paginationPageCount) { // paginationPageCount = _paginationPageCount; // paginationFinished = true; // parentScrollHandler.sendMessage(parentScrollHandler.obtainMessage(CONTENT_PAGINATION_FINISHED, 0, 0)); // cachePaginatedContentCall(); // requestContentMediaElementsTopOffset(); //messageHandler.sendMessage(messageHandler.obtainMessage(MESSAGE_CHANGE_CONTENT_OFFSET, 0, 0)); // messageHandler.sendMessageDelayed(messageHandler.obtainMessage(MESSAGE_CHANGE_CONTENT_OFFSET, 0, 0), 100); } @SuppressWarnings("unused") public void documentContent(String content) { if(!isHighlightMode)cachePaginatedContent(content); } @SuppressWarnings("unused") public void bodyElement(String content) { // if(!isHighlightMode)cacheBodyContent(content); } } contentWebView.addJavascriptInterface(new ContentScriptInterface(), "HTMLOUT"); mediaWebView.setClickable(true); mediaWebView.setLongClickable(false); // contentWebView.isS } protected void contentScrollChanged(int l, int t, int oldl, int oldt) { if(requestingMediaElementsTopOffsetStatus==REQUESTING_TOP_OFFSET_STATUS_PROCESSED)scrollToPageMedia(); } private void cachePaginatedContentCall() { if(isHighlightMode)return; if(topicURLIsCaching(contentURL)) return; //contentWebView.loadUrl("javascript:window.HTMLOUT.documentContent(document.getElementsByTagName('html')[0].outerHTML);"); contentWebView.loadUrl("javascript:jtj_get_body();"); } private void cachePaginatedContent(String content) { //Log.i("---", content); } private String cacheFileNameFromOriginalLocalURL(String urlStr) { URL url; try { url = new URL(urlStr); return url.getFile() + String.format(".cache.%s.xhtml", deviceOrientationIsLandscape ? "l" : "p"); } catch (MalformedURLException e) { e.printStackTrace(); } return null; } private boolean topicURLIsCaching(String urlStr) { if(urlStr.contains(".cache.l") || urlStr.contains(".cache.p")) return true; return false; } private void cacheBodyContent(final String content) { Thread background = new Thread (new Runnable() { public void run() { String cacheFileName = cacheFileNameFromOriginalLocalURL(contentURL); if(cacheFileName!=null) { try { URL curl = new URL(contentURL); String srcFilePath = curl.getFile(); File file = new File(srcFilePath); if(file.canRead()) { BufferedReader r; r = new BufferedReader(new InputStreamReader(new FileInputStream(file))); StringBuilder total = new StringBuilder(); String line; while ((line = r.readLine()) != null) { total.append(line); } String oldContent = total.toString(); String newContent = oldContent.replaceAll("(?i)<body.*</body>", content); OutputStreamWriter out = new OutputStreamWriter(new FileOutputStream(cacheFileName)); out.write(newContent); out.close(); out = new OutputStreamWriter(new FileOutputStream(cacheFileName+".done")); out.write("."); out.close(); } } catch (Exception e) { e.printStackTrace(); } } } }); background.start(); } public void loadBlankContent() { String blankContent = "<html><head></head><body><div style='width:2000; height:2000; overflow: hidden;'> </body>"; contentWebView.loadData(blankContent, "text/html", "UTF-8"); } private boolean tryLoadCachedContent() { if(isHighlightMode)return false; if(topicURLIsCaching(contentURL)) { // Log.d("-------", "Topic URL os caching="+contentURL); return false; } String cachFileName = cacheFileNameFromOriginalLocalURL(contentURL); File file = new File(cachFileName + ".done"); if(file.canRead()) { contentURL = "file://" + cachFileName; return true; } return false; } private void storeContentWebConsoleMessage(String message, int lineNumber, String sourceID) { Log.i("jtj", message + " -- From line " + lineNumber + " of " + sourceID); try { URL url = new URL(contentURL); File file = new File(url.getFile()+".log"); OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true)); String msg = lineNumber + ":\n" + message + "\n"; os.write(msg); os.close(); } catch (Exception e) { e.printStackTrace(); } } public boolean isPaginationFinished() { return paginationFinished; } private void clearContentWebConsoleMessageLog() { try { URL url = new URL(contentURL); File file = new File(url.getFile()+".log"); OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, false)); os.write("\n"); os.close(); } catch (Exception e) { e.printStackTrace(); } } public void setHighlightMode(boolean mode) { isHighlightMode = mode; } private void contentWebViewSizeChanged(int width, int height, int oldWidth, int oldHeight) { /* // Log.i("------", String.format("TOPIC %d: size changed to %d x %d from %d x %d", topicId, width, height, oldWidth, oldHeight)); if(oldHeight!=0) { //contentWebView.loadUrl(contentURL); return; } if(contentWebView.getProgress()==100) { paginationFinished = false; paginationPageCount = -1; //paginateContent(); }*/ } private void paginateContent() { if(paginationFinished) return; miscHandler.sendMessageDelayed(miscHandler.obtainMessage(MISC_MESSAGE_PAGINATION, 0, 0), PAGINATION_DELAY_M); } private void paginateContentActual() { // Log.i("-----", "PAGINATE CALL FOR TOPIC "+topicId+", with height="+contentWebView.getActualSizeHeight()+", progress="+contentWebView.getProgress()); contentWebView.loadUrl("javascript:jtj_paginate("+contentWebView.getActualSizeHeight()+");"); } public void setParentScrollHandler(Handler parentScrollHandler) { this.parentScrollHandler = parentScrollHandler; } public int getContentLoadingStatus() { return contentLoadingStatus; } public int getMediaLoadingStatus() { return mediaLoadingStatus; } public Handler getParentScrollHandler() { return parentScrollHandler; } public void changeFontWithFactor(int factor) // factor is absolute, not relative { if(fontChangeFactor==-1) { initialFontSize = contentWebView.getSettings().getDefaultFontSize(); } fontChangeFactor = factor; contentWebView.getSettings().setDefaultFontSize(initialFontSize + fontChangeFactor); mediaWebView.getSettings().setDefaultFontSize(initialFontSize + fontChangeFactor); } protected void jumpToMediaWithId(String id) { if(mediaURL!=null) { mediaWebView.loadUrl("javascript:scrollToElement('" + id + "')"); } } public WebView getMediaWebView() { return mediaWebView; } public WebView getContentWebView() { return contentWebView; } public View getParentContainer() { return parentContainer; } public void setParentContainer(View parentContainer) { this.parentContainer = parentContainer; } private void parseMediaJSON() { if(mediaJSON==null)return; try { JSONArray array = new JSONArray(mediaJSON); for(int i=0; i<array.length(); i++) { JSONObject curObj = array.getJSONObject(i); EmbeddedMediaElement element = new EmbeddedMediaElement(curObj); String elId = element.getId(); if(elId!=null) { mediaElements.put(elId, element); } } } catch (JSONException e) { e.printStackTrace(); } } public int getTopicId() { return topicId; } public void setSpineIndex(EPubBook book, int index) { this.book = book; offsetHeightTries = 0; if(topicId==index) // this container already contain actual topic data { isTopicActual = true; //if(parentScrollHandler != null)parentScrollHandler.sendMessage(parentScrollHandler.obtainMessage(CONTENT_SCROLLING_FINISHED, 0, 0)); // check scroll buttons return; } isTopicActual = false; paginationFinished = false; contentLoadingStatus = CONTENT_LOADING_STATUS_NOT_LOADED; mediaLoadingStatus = CONTENT_LOADING_STATUS_NOT_LOADED; requestingMediaElementsTopOffsetStatus = REQUESTING_TOP_OFFSET_STATUS_NOT_DETERMINED; contentBaseURL = null; mediaURL = null; topicId = index; // new content contentURL = book.getTopicOriginalURLByIndex(index); String proposedContentPath = null, proposedContentURL = null; String proposedContentPathReserve = null, proposedContentURLReserve = null; if(isHighlightMode) { if(deviceOrientationIsLandscape) // with media cutted { proposedContentPath = book.getTopicWithoutMediaHighlightedPathByIndex(index); proposedContentURL = book.getTopicWithoutMediaHighlightedURLByIndex(index); proposedContentPathReserve = book.getTopicOriginalHighlightedPathByIndex(index); proposedContentURLReserve = book.getTopicOriginalHighlightedURLByIndex(index); } else { // with original (uncutted media) proposedContentPath = book.getTopicOriginalHighlightedPathByIndex(index); proposedContentURL = book.getTopicOriginalHighlightedURLByIndex(index); } } else { if(deviceOrientationIsLandscape) { proposedContentPath = book.getTopicContentPathByIndex(index); proposedContentURL = book.getTopicContentURLByIndex(index); } } boolean needLoadReserve = false; if(proposedContentPath!=null && proposedContentURL!=null) { File contentFile = new File(proposedContentPath); if(contentFile.canRead()) { contentURL = proposedContentURL; } else needLoadReserve = true; } else { needLoadReserve = true; } if(needLoadReserve) { if(proposedContentPathReserve!=null && proposedContentURLReserve!=null) { File contentFile = new File(proposedContentPathReserve); if(contentFile.canRead()) { contentURL = proposedContentURLReserve; } } } // new media File mediaFile = new File(book.getTopicMediaPathByIndex(index)); clearMediaJSON(); if(mediaFile.canRead()) { mediaURL = book.getTopicMediaURLByIndex(index); mediaJSON = book.getTopicMediaInfoJSONByIndex(index); parseMediaJSON(); //Log.i("----", "media loaded="+mediaElements.size()); } if(fullScreenMode || mediaURL==null)mediaWebView.setVisibility(View.GONE); else if(deviceOrientationIsLandscape) mediaWebView.setVisibility(View.VISIBLE); // old code, load json only if landsape and not full screen /* fullScreenMode = book.getTopicFullscreenFlag(index); if(deviceOrientationIsLandscape) // with media { File mediaFile = new File(book.getTopicMediaPathByIndex(index)); if(mediaFile.canRead()) { mediaURL = book.getTopicMediaURLByIndex(index); mediaJSON = book.getTopicMediaInfoJSONByIndex(index); parseMediaJSON(); } else { clearMediaJSON(); } } if(fullScreenMode)mediaWebView.setVisibility(View.GONE); else if(deviceOrientationIsLandscape) mediaWebView.setVisibility(View.VISIBLE);*/ } private void clearMediaJSON() { mediaJSON = null; mediaElements.clear(); } private void showFullScreenMediaWithId(String id) { EmbeddedMediaElement element = mediaElements.get(id); if(element!=null) { int contentType = element.getType(); if(contentType==EmbeddedMediaElement.MEDIA_TYPE_IMAGE) { Intent intent = new Intent(context, FullScreenEmbeddedMediaImageActivity.class); String imageURL = element.getImageURL(); intent.putExtra(EPubBookRender.FULLSCREEN_CONTENT_TYPE_KEY, contentType); if(imageURL != null) { intent.putExtra(EPubBookRender.FULLSCREEN_IMAGE_URL_KEY, imageURL); context.startActivity(intent); } } else if (contentType == EmbeddedMediaElement.MEDIA_TYPE_EXTERNAL) { Intent intent = new Intent(context, FullScreenEmbeddedMediaExternalActivity.class); intent.putExtra(EPubBookRender.FULLSCREEN_CONTENT_TYPE_KEY, contentType); String externalContent = element.getExternalContent(); if(externalContent != null) { intent.putExtra(EPubBookRender.FULLSCREEN_EXTERNAL_CONTENT_KEY, externalContent); intent.putExtra(EPubBookRender.FULLSCREEN_BASE_URL_KEY, contentBaseURL); context.startActivity(intent); } } } } public void load() { // check reusing if(isTopicActual) return; contentLoadingStatus = CONTENT_LOADING_STATUS_LOADIN_IN_PROCESS; mediaLoadingStatus = CONTENT_LOADING_STATUS_LOADIN_IN_PROCESS; contentWebView.clearView(); mediaWebView.clearView(); clearContentWebConsoleMessageLog(); //tryLoadCachedContent(); contentWebView.loadUrl(contentURL); if(!fullScreenMode) { if(mediaURL!=null) { mediaWebView.loadUrl(mediaURL); } else { mediaWebView.loadDataWithBaseURL("", EMPTY_HTML, null, "UTF-8", null); } } } public Handler getTopicHandler() { return topicHandler; } public void setTopicHandler(Handler topicHandler) { this.topicHandler = topicHandler; } public void pageDown() { // old behavoir - scrolling using android WebView method /* contentWebView.pageDown(false); if(parentScrollHandler != null)parentScrollHandler.sendMessageDelayed(parentScrollHandler.obtainMessage(CONTENT_SCROLLING_FINISHED, 0, 0), 1000); scrollHandler.sendMessageDelayed(scrollHandler.obtainMessage(1, 0, 0), 1000); */ int webViewHeight = contentWebView.getHeight(), contentHeight = contentWebView.getContentHeight(), yPos = contentWebView.getScrollY(), newYPos = 0; newYPos = yPos + webViewHeight; if(newYPos < contentHeight-1)contentWebView.scrollTo(0, newYPos); if(requestingMediaElementsTopOffsetStatus==REQUESTING_TOP_OFFSET_STATUS_PROCESSED)scrollToPageMedia(); } public int paginationPageCount() { int webViewHeight = contentWebView.getHeight(), contentHeight = contentWebView.getContentHeight() - 1, pages; pages = (int) Math.ceil((double)contentHeight / webViewHeight); if(paginationFinished) { if(paginationPageCount==-1) { return pages == 0 ? 1 : pages; } return paginationPageCount; } return pages == 0 ? 1 : pages; } public int paginationCurrentPage() { int webViewHeight = contentWebView.getHeight(), yPos = contentWebView.getScrollY(); return (yPos / webViewHeight) + 1; } public void pageUp() { /*contentWebView.pageUp(false); if(parentScrollHandler != null)parentScrollHandler.sendMessageDelayed(parentScrollHandler.obtainMessage(CONTENT_SCROLLING_FINISHED, 0, 0), 1000); scrollHandler.sendMessageDelayed(scrollHandler.obtainMessage(1, 0, 0), 1000); */ int webViewHeight = contentWebView.getHeight(), yPos = contentWebView.getScrollY(), newYPos = 0; newYPos = yPos - webViewHeight; if(newYPos < 0)newYPos = 0; contentWebView.scrollTo(0, newYPos); if(requestingMediaElementsTopOffsetStatus==REQUESTING_TOP_OFFSET_STATUS_PROCESSED)scrollToPageMedia(); } // id of media that topOffset in specified range is smallest private String topmostMediaId(int topOffset, int bottomOffset) { if(requestingMediaElementsTopOffsetStatus!=REQUESTING_TOP_OFFSET_STATUS_PROCESSED) return null; // now is not determining topOffsets Set<String> keys = mediaElements.keySet(); Iterator<String> iterator = keys.iterator(); String resultId = null; int resultOffset = contentWebView.getContentHeight() + 1000; while ( iterator.hasNext() ) { String id = iterator.next(); EmbeddedMediaElement element = mediaElements.get(id); if(id!=null && element!=null) { int elementTop = element.getTopOffset(); if(elementTop>=topOffset && elementTop<bottomOffset) { if(resultId != null) { if(elementTop < resultOffset) { resultId = id; resultOffset = elementTop; } } else { resultId = id; resultOffset = elementTop; } } } } return resultId; } // scroll to media that first on this page private void scrollToPageMedia() { int pageTop = contentWebView.getScrollY(); int pageBottom = pageTop + contentWebView.getHeight(); String id = topmostMediaId(pageTop, pageBottom); //Log.d("-----", "scroll to id="+id); //if(pageTop==0)return; // we are in top, dont need jump to media if(id!=null)jumpToMediaWithId(id); } private void requestContentMediaElementsTopOffset() { if(requestingMediaElementsTopOffsetStatus == REQUESTING_TOP_OFFSET_STATUS_IN_PROCESS) return; requestingMediaElementsTopOffsetStatus = REQUESTING_TOP_OFFSET_STATUS_IN_PROCESS; Set<String> keys = mediaElements.keySet(); Iterator<String> iterator = keys.iterator(); // Log.i("------", "media_req_size="+mediaElements.size()); while ( iterator.hasNext() ){ String id = iterator.next(); //Log.i("------", "media_id="+id); contentWebView.loadUrl("javascript:elementTop=0;" + "delement = document.getElementById(\""+id+"\");"+ "while (delement.offsetParent){elementTop += delement.offsetTop; delement = delement.offsetParent;};"+ "window.HTMLOUT.elementTop(\""+id+"\", elementTop);"); } } private void checkTopOffsetEndProcessing() { Set<String> keys = mediaElements.keySet(); Iterator<String> iterator = keys.iterator(); int count = 0, processed = 0; while ( iterator.hasNext() ){ String id = iterator.next(); EmbeddedMediaElement element = mediaElements.get(id); if(id!=null && element!=null) { if(element.getTopOffset()>=0)processed++; count++; } } if(count>0 && count==processed) { requestingMediaElementsTopOffsetStatus = REQUESTING_TOP_OFFSET_STATUS_PROCESSED; scrollToPageMedia(); } } public boolean isCanScrollUp() { // Log.i("----------------", "IS UP SCROLLY="+contentWebView.getScrollY()); return contentWebView.getScrollY() > 0; } public boolean isCanScrollDown() { int contentHeight = contentWebView.getContentHeight(); int webViewHeight = contentWebView.getHeight(); int pos = contentWebView.getScrollY(); // Log.i("----------------", "IS DOWN SCROLL conth="+contentHeight+", wh="+webViewHeight+", y="+pos); if(contentHeight < webViewHeight) return false; // too small topic return pos < contentHeight - webViewHeight; } Handler scrollHandler = new Handler() { public void handleMessage(Message msg) { /*if(requestingMediaElementsTopOffsetStatus==REQUESTING_TOP_OFFSET_STATUS_NOT_DETERMINED) { requestContentMediaElementsTopOffset(); } else if(requestingMediaElementsTopOffsetStatus==REQUESTING_TOP_OFFSET_STATUS_PROCESSED){ scrollToPageMedia(); }*/ // if(parentScrollHandler != null)parentScrollHandler.sendMessageDelayed(parentScrollHandler.obtainMessage(CONTENT_SCROLLING_FINISHED, 0, 0), 1000); } }; Handler messageHandler = new Handler() { public void handleMessage(Message msg) { if(msg.what == MESSAGE_CHANGE_CONTENT_OFFSET) { setContentOffset(); } } }; public int getContentHeight() { return contentWebView.getContentHeight(); } public float getContentOffset() { int contentHeight = contentWebView.getContentHeight(); if(contentHeight==0) return 0; return ((float)contentWebView.getScrollY()) / contentHeight; } private void setContentOffset() { int contentHeight = contentWebView.getContentHeight(); offsetHeightTries++; if(contentHeight==0) { if(offsetHeightTries < 12) { messageHandler.sendMessageDelayed(messageHandler.obtainMessage(MESSAGE_CHANGE_CONTENT_OFFSET, 0, 0), 100); } return; } // Log.i("-----", "TRIES="+offsetHeightTries); float ypos = contentOffset * contentHeight; int visHeight = contentWebView.getHeight(); int page; // try to determine appropriate page //page = (int) Math.ceil(ypos / visHeight); // check over-page //if(page+1 > paginationPageCount) page = paginationPageCount - 1; //if(page < 0) page = 0; if(ypos < 0)ypos = 0; if(ypos > contentHeight-visHeight-1)ypos = contentHeight-visHeight-1; contentWebView.scrollTo(0, (int) Math.ceil(ypos)); // Log.i("----", "set OFFSET ("+contentOffset+"). cheight="+contentHeight+", ypos="+ypos+", visHeight="+visHeight+", page="+page); parentScrollHandler.sendMessage(parentScrollHandler.obtainMessage(CONTENT_UPDATE_PAGE_INFO, 0, 0)); requestContentMediaElementsTopOffset(); } public void setContentOffset(float offset) { contentOffset = offset; //if(contentLoadingStatus==CONTENT_LOADING_STATUS_LOADINF_FINISHED)setContentOffset(); } Handler miscHandler = new Handler() { public void handleMessage(Message msg) { if(msg.what==MISC_MESSAGE_PAGINATION) { //paginateContentActual(); } } }; }