01-14-2012, 10:54 AM | #1 |
Enthusiast
Posts: 32
Karma: 10040
Join Date: Jan 2012
Device: Sony Prs T1
|
No refresh mode in every app
Hello
i was using the sony browser on my t1 and i left it alone for something like 5/10 minutes cause i had to do some stuff,when i picked it back something odd happened: the screen did not refreshed, like when you scroll a webpage and the screen enter a low definition mode to avoid continuous flashing due to e-ink refresh; i tried using some app (adw launcher,rssdemon,dolphin browser mini etc.) and saw it was applied globally! Maybe this non refresh mode can be activated outside the stock browser for the other apps,i think it would be really useful i made a video (and discovered that returning to the home deactivated the trick ) http://www.youtube.com/watch?v=o1PslEW6uLE I'll try to reproduce this behavior and add further details Last edited by robyshot; 01-14-2012 at 10:56 AM. |
01-14-2012, 11:44 AM | #2 |
Enthusiast
Posts: 33
Karma: 10
Join Date: Jan 2012
Device: Sony PRS-T1
|
Wow, that would be very nice (in my calendar app for example)!
Eagerly awaiting your testing |
Advert | |
|
01-14-2012, 03:21 PM | #3 |
Groupie
Posts: 194
Karma: 4637
Join Date: Sep 2009
Location: United States
Device: All
|
Nice find! I figured out how to replicate this. When scrolling with the default web browser there's a delay before it resets. Just scroll with the browser and then quickly tap the top of the screen to open the notifications bar. It will keep it from resetting and enter it in a semi-permanent partial refresh state. Going to the Sony homescreen or opening an ebook with the Sony Reader app resets it back to normal.
This partial refresh trick is actually really helpful for whenever you need to scroll through lists like Dropbox and the file manager. It also works with FBReader for perma-partial page refresh. It doesn't look too bad but the text is definitely rougher than usual. It makes page turns faster, especially when holding down. Last edited by The-eBook-Reader; 01-14-2012 at 03:33 PM. |
01-16-2012, 07:52 AM | #4 |
Member
Posts: 13
Karma: 662
Join Date: Jan 2012
Device: PRS-T1
|
Funky find!
... Much more usable like that but does get too lumpy in some apps - Just need to find a way to force a refresh without taking it out of scroll mode |
01-16-2012, 01:07 PM | #5 |
Evangelist
Posts: 425
Karma: 75216
Join Date: Nov 2011
Location: old europe
Device: Kobo Mini, Tolino Epos 2
|
I also ran into this several times, but it turned everything to 1-bit black&white, i.e. no grey scale anymore....
But as far as I remember there are driver settings (either at /sys or /proc) that determine at which ratio of changed screen content there will be a full refresh. And these settings should be tweakable! Just need to find the time to do more research.... |
Advert | |
|
01-16-2012, 04:46 PM | #6 |
Enthusiast
Posts: 33
Karma: 10
Join Date: Jan 2012
Device: Sony PRS-T1
|
Indeed, that works perfectly... you've definitely less pixels (and details), but that's logically...
If someone has some time to dig in deeper, maybe it would be possible to activate some "switch"-script by pressing the home or menu button for e.g. 2 seconds (which then activates/deactivates the refresh mode) => but we can already use it sometimes (when you know you're going to scroll to much, and when there is some wifi-connection :-) ) |
01-16-2012, 05:05 PM | #7 | |
Grand Sorcerer
Posts: 11,732
Karma: 128354696
Join Date: May 2009
Location: 26 kly from Sgr A*
Device: T100TA,PW2,PRS-T1,KT,FireHD 8.9,K2, PB360,BeBook One,Axim51v,TC1000
|
Quote:
I got it to work on my very first try. The setting survives sleep mode, BTW, and switching to other non-Sony apps. And yes, it looks like it switches to a pure B&W mode; Coolreader and Kindle work fine. Aldiko, not so much. But paging in all three apps is ridiculously fast--no black flash at all, for those that care--so if a 2-bit mode could be enabled via a software switch, it should still be a major speed boost with no significant text quality loss. |
|
01-17-2012, 07:29 AM | #8 |
Member
Posts: 13
Karma: 662
Join Date: Jan 2012
Device: PRS-T1
|
I'm thinking there should be a way of attaching a method to change modes to the global TouchDown/Up methods (if they exist!) and that there should be some clue in the browser code.
So I've extracted the browser code and found this file Here which has a lot of hopeful variables in it like INVALIDATE_DELAY_FOR_CHANGE_EINK_MODE and methods like startTouch etc, although as I've not done any android dev or whatever this ddx is before it's all a bit foreign at the moment. I'll let you know if I find anything useful! |
01-18-2012, 12:23 PM | #9 | |
meat popsicle
Posts: 225
Karma: 100000
Join Date: Jul 2007
Location: USA
Device: Kindles, Pixels, iPads
|
Quote:
Standard Android SDK has been modified and new interface introduced: ViewParentEink. It has following methods (which track standard View methods with an extra parameter at the end - updateMode): .method public final invalidateChild(Landroid/view/View;Landroid/graphics/Rect;I)V .registers 20 .parameter "child" .parameter "dirty" .parameter "updateMode" .method public invalidateChildInParent([ILandroid/graphics/Rect;I)Landroid/view/ViewParentEink; .registers 11 .parameter "location" .parameter "dirty" .parameter "updateMode" Interface has been implemented in ViewGroup - so any view which implements AbsoluteLayout has access to those methods. Sony's browser WebView keeps current updateMode in a class variable and updates it when necessary (touch, zoom with eInk mode constants). All calls to invalidate are using this "new" framework functions - the rest happens automatically. Something like that... |
|
01-18-2012, 12:59 PM | #10 |
Evangelist
Posts: 425
Karma: 75216
Join Date: Nov 2011
Location: old europe
Device: Kobo Mini, Tolino Epos 2
|
According to dmesg, the T1 has a TPS6518x eInk powermanagement IC (although with Freescale i.MX508 instead of OMAP):
http://focus.ti.com/pdfs/wtbu/SWPT045.pdf Does anybody know, what the Nook is based on? Maybe drivers are interchangeable.... |
01-19-2012, 07:19 PM | #11 | |
Connoisseur
Posts: 80
Karma: 68347
Join Date: Oct 2009
Location: Sweden
Device: PRS-T1
|
Quote:
I made an "EinkListView" class when experimenting, which is just a ListView that overrides all the methods that have updateMode overloads in Sony's android.view.View to use the updateMode ones: Code:
public class EinkListView extends ListView { public int mUpdateMode = 0; public EinkListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public EinkListView(Context context, AttributeSet attrs) { super(context, attrs); } public EinkListView(Context context) { super(context); } @Override public void invalidate() { super.invalidate(mUpdateMode); } @Override public void invalidate(int l, int t, int r, int b) { super.invalidate(l, t, r, b, mUpdateMode); } @Override public void invalidate(Rect dirty) { super.invalidate(dirty, mUpdateMode); } @Override public void invalidateDrawable(Drawable drawable) { super.invalidateDrawable(drawable, mUpdateMode); } @Override public void postInvalidate() { super.postInvalidate(mUpdateMode); } @Override public void postInvalidate(int left, int top, int right, int bottom) { super.postInvalidate(left, top, right, bottom, mUpdateMode); } @Override public void postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom) { super.postInvalidateDelayed(delayMilliseconds, left, top, right, bottom, mUpdateMode); } @Override public void postInvalidateDelayed(long delayMilliseconds) { super.postInvalidateDelayed(delayMilliseconds, mUpdateMode); } @Override public void scrollBy(int x, int y) { super.scrollBy(x, y, mUpdateMode); } @Override public void scrollTo(int x, int y) { super.scrollTo(x, y, mUpdateMode); } } |
|
01-20-2012, 02:20 AM | #12 | |
Member
Posts: 17
Karma: 548
Join Date: Jan 2012
Device: PRS-T1
|
Quote:
Being not an Android programmer, I looked around for generic code which could make it in such a replacement. So far I found these: - The flicker-free page turn code used in cool reader: credits to DairyKnight <dairyknight@gmail.com> http://crengine.git.sourceforge.net/...ontroller.java - Max Kammerer's code for his nook port of aarddict: http:///github.com/max-kammerer/aarddict_nook Code:
// from kbs - trook.projectsource code. private final void pageUp() { int cury = articleView2.getScrollY(); if (cury == 0) { return; } int newy = cury - WEB_SCROLL_PX; if (newy < 0) { newy = 0; } articleView2.scrollTo(0, newy); } private final void pageDown() { int cury = articleView2.getScrollY(); int hmax = articleView2.getContentHeight() - 200; if (hmax < 0) { hmax = 0; } int newy = cury + WEB_SCROLL_PX; if (newy > hmax) { newy = hmax; } if (cury != newy) { articleView2.scrollTo(0, newy); } } In an e-ink friendly app, there would be an option to select high-contrast skins and optimize page refreshes. Once the keyword "e-ink" or "e-ink friendly" will show up in the Android Market, then we've got the ball rolling. Last edited by bardo; 01-20-2012 at 11:07 AM. |
|
01-21-2012, 10:07 PM | #13 | ||
Connoisseur
Posts: 80
Karma: 68347
Join Date: Oct 2009
Location: Sweden
Device: PRS-T1
|
Quote:
Quote:
I guess the former is what everyone would like to be able to do, and the latter is something that should be the very minimal effort expected from a developer of an app if it is to be called E-ink friendly (i.e. avoiding animations of all kinds, aiming instead for static screens whenever possible). Luckily, Sony has provided us with a higher level interface with the "update modes" in the android.view.View class, so on the PRS-T1 a non-flickery app doesn't have to worry about the hardware as long as it utilizes the update modes. It still goes in the former category though, since the methods are device-specific. Anyhow, the source code for my ListView experiment is available at SourceForge if anyone wants to take a peek, and an APK is available here. |
||
01-23-2012, 06:58 AM | #14 |
Member
Posts: 17
Karma: 548
Join Date: Jan 2012
Device: PRS-T1
|
Thanks for providing sample code for android.view.View, I will try it out (still a way to go to set up the dev environment and start coding..)
Below is how Aardict (btw an amazing offline Wikipedia viewer including MathML!) actually does its page turn. Could the articleView.pageUp function work with your interface? How to include this in the generic Aard Dicitonary code so that other non-Sony devices still work? Thanks, Bardo Code:
/* This file is part of Aard Dictionary for Android <http://aarddict.org>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License <http://www.gnu.org/licenses/gpl-3.0.txt> * for more details. * * Copyright (C) 2010 Igor Tkach */ package aarddict.android; import android.content.Context; import android.util.AttributeSet; import android.webkit.WebView; class ArticleView extends WebView { interface ScrollListener { void onScroll(int l, int t, int oldl, int oldt); } private ScrollListener scrollListener; public ArticleView(Context context) { super(context); } public ArticleView(Context context, AttributeSet attrs) { super(context, attrs); } public ArticleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (scrollListener != null) { scrollListener.onScroll(l, t, oldl, oldt); } } public void setOnScrollListener(ScrollListener l) { this.scrollListener = l; } } Code:
package aarddict.android; public class Article extends ArticleViewActivity { } Code:
/* This file is part of Aard Dictionary for Android <http://aarddict.org>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License <http://www.gnu.org/licenses/gpl-3.0.txt> * for more details. * * Copyright (C) 2010 Igor Tkach */ package aarddict.android; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Timer; import java.util.TimerTask; import aarddict.Article; import aarddict.ArticleNotFound; import aarddict.Entry; import aarddict.LookupWord; import aarddict.RedirectTooManyLevels; import aarddict.Volume; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.DialogInterface.OnClickListener; import android.content.SharedPreferences.Editor; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.Window; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.webkit.JsResult; import android.webkit.WebChromeClient; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.Button; import android.widget.Toast; public class ArticleViewActivity extends BaseDictionaryActivity { private final static String TAG = ArticleViewActivity.class.getName(); private ArticleView articleView; private String sharedCSS; private String mediawikiSharedCSS; private String mediawikiMonobookCSS; private String js; private List<HistoryItem> backItems; private Timer timer; private TimerTask currentTask; private TimerTask currentHideNextButtonTask; private AlphaAnimation fadeOutAnimation; private boolean useAnimation = false; private Map<Article, ScrollXY> scrollPositionsH; private Map<Article, ScrollXY> scrollPositionsV; private boolean saveScrollPos = true; static class AnimationAdapter implements AnimationListener { public void onAnimationEnd(Animation animation) {} public void onAnimationRepeat(Animation animation) {} public void onAnimationStart(Animation animation) {} } @Override void initUI() { this.scrollPositionsH = Collections.synchronizedMap(new HashMap<Article, ScrollXY>()); this.scrollPositionsV = Collections.synchronizedMap(new HashMap<Article, ScrollXY>()); loadAssets(); //Animation is broken before 2.1 - animation listener notified, //only sometimes so we can't use it try { useAnimation = Integer.parseInt(Build.VERSION.SDK) > 6; } catch (Exception e) { Log.w(TAG, "Failed to parse SDK version string as int: " + Build.VERSION.SDK); } Log.d(TAG, "Build.VERSION.SDK: " + Build.VERSION.SDK); Log.d(TAG, "use animation? " + useAnimation); fadeOutAnimation = new AlphaAnimation(1f, 0f); fadeOutAnimation.setDuration(600); fadeOutAnimation.setAnimationListener(new AnimationAdapter() { public void onAnimationEnd(Animation animation) { Button nextButton = (Button)findViewById(R.id.NextButton); nextButton.setVisibility(Button.GONE); } }); timer = new Timer(); backItems = Collections.synchronizedList(new LinkedList<HistoryItem>()); getWindow().requestFeature(Window.FEATURE_PROGRESS); setContentView(R.layout.article_view); articleView = (ArticleView)findViewById(R.id.ArticleView); articleView.setOnScrollListener(new ArticleView.ScrollListener(){ public void onScroll(int l, int t, int oldl, int oldt) { saveScrollPos(l, t); } }); articleView.getSettings().setJavaScriptEnabled(true); articleView.addJavascriptInterface(new SectionMatcher(), "matcher"); articleView.setWebChromeClient(new WebChromeClient(){ @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { Log.d(TAG + ".js", String.format("[%s]: %s", url, message)); result.cancel(); return true; } public void onProgressChanged(WebView view, int newProgress) { Log.d(TAG, "Progress: " + newProgress); setProgress(5000 + newProgress * 50); } }); articleView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { Log.d(TAG, "Page finished: " + url); currentTask = null; String section = null; if (url.contains("#")) { LookupWord lookupWord = LookupWord.splitWord(url); section = lookupWord.section; if (backItems.size() > 0) { HistoryItem currentHistoryItem = backItems.get(backItems.size() - 1); HistoryItem h = new HistoryItem(currentHistoryItem); h.article.section = section; backItems.add(h); } } else if (backItems.size() > 0) { Article current = backItems.get(backItems.size() - 1).article; section = current.section; } if (!restoreScrollPos()) { goToSection(section); } } @Override public boolean shouldOverrideUrlLoading(WebView view, final String url) { Log.d(TAG, "URL clicked: " + url); String urlLower = url.toLowerCase(); if (urlLower.startsWith("http://") || urlLower.startsWith("https://") || urlLower.startsWith("ftp://") || urlLower.startsWith("sftp://") || urlLower.startsWith("mailto:")) { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(browserIntent); } else { if (currentTask == null) { currentTask = new TimerTask() { public void run() { try { Article currentArticle = backItems.get(backItems.size() - 1).article; try { Iterator<Entry> currentIterator = dictionaryService.followLink(url, currentArticle.volumeId); List<Entry> result = new ArrayList<Entry>(); while (currentIterator.hasNext() && result.size() < 20) { result.add(currentIterator.next()); } showNext(new HistoryItem(result)); } catch (ArticleNotFound e) { showMessage(getString(R.string.msgArticleNotFound, e.word.toString())); } } catch (Exception e) { StringBuilder msgBuilder = new StringBuilder("There was an error following link ") .append("\"").append(url).append("\""); if (e.getMessage() != null) { msgBuilder.append(": ").append(e.getMessage()); } final String msg = msgBuilder.toString(); Log.e(TAG, msg, e); showError(msg); } } }; try { timer.schedule(currentTask, 0); } catch (Exception e) { Log.d(TAG, "Failed to schedule task", e); } } } return true; } }); final Button nextButton = (Button)findViewById(R.id.NextButton); nextButton.getBackground().setAlpha(180); nextButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (nextButton.getVisibility() == View.VISIBLE) { updateNextButtonVisibility(); nextArticle(); updateNextButtonVisibility(); } } }); articleView.setOnTouchListener( new View.OnTouchListener() { public boolean onTouch(View v, MotionEvent event) { updateNextButtonVisibility(); return false; } } ); setProgressBarVisibility(true); } private void scrollTo(ScrollXY s) { scrollTo(s.x, s.y); } private void scrollTo(int x, int y) { saveScrollPos = false; Log.d(TAG, "Scroll to " + x + ", " + y); articleView.scrollTo(x, y); saveScrollPos = true; } private void goToSection(String section) { Log.d(TAG, "Go to section " + section); if (section == null || section.trim().equals("")) { scrollTo(0, 0); } else { articleView.loadUrl(String.format("javascript:scrollToMatch(\"%s\")", section)); } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { switch (keyCode) { case KeyEvent.KEYCODE_BACK: goBack(); break; case KeyEvent.KEYCODE_VOLUME_UP: if (!articleView.pageUp(false)) { goBack(); } break; case KeyEvent.KEYCODE_VOLUME_DOWN: if (!articleView.pageDown(false)) { nextArticle(); }; break; // add PRS-T1 hardware keys case KeyEvent.KEYCODE_DPAD_RIGHT: if (!articleView.pageUp(false)) { goBack(); } break; case KeyEvent.KEYCODE_DPAD_RIGHT: if (!articleView.pageDown(false)) { nextArticle(); }; break; default: return super.onKeyDown(keyCode, event); } return true; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { //eat key ups corresponding to key downs so that volume keys don't beep switch (keyCode) { case KeyEvent.KEYCODE_BACK: case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: break; default: return super.onKeyDown(keyCode, event); } return true; } private boolean zoomIn() { boolean zoomed = articleView.zoomIn(); float scale = articleView.getScale(); articleView.setInitialScale(Math.round(scale*100)); return zoomed; } private boolean zoomOut() { boolean zoomed = articleView.zoomOut(); float scale = articleView.getScale(); articleView.setInitialScale(Math.round(scale*100)); return zoomed; } private void goBack() { if (backItems.size() == 1) { finish(); } if (currentTask != null) { return; } if (backItems.size() > 1) { HistoryItem current = backItems.remove(backItems.size() - 1); HistoryItem prev = backItems.get(backItems.size() - 1); Article prevArticle = prev.article; if (prevArticle.equalsIgnoreSection(current.article)) { resetTitleToCurrent(); if (!prevArticle.sectionEquals(current.article) && !restoreScrollPos()) { goToSection(prevArticle.section); } } else { showCurrentArticle(); } } } private void nextArticle() { HistoryItem current = backItems.get(backItems.size() - 1); if (current.hasNext()) { showNext(current); } } @Override public boolean onSearchRequested() { finish(); return true; } final static int MENU_VIEW_ONLINE = 1; final static int MENU_NEW_LOOKUP = 2; final static int MENU_ZOOM_IN = 3; final static int MENU_ZOOM_OUT = 4; private MenuItem miViewOnline; @Override public boolean onCreateOptionsMenu(Menu menu) { miViewOnline = menu.add(0, MENU_VIEW_ONLINE, 0, R.string.mnViewOnline).setIcon(android.R.drawable.ic_menu_view); menu.add(0, MENU_NEW_LOOKUP, 0, R.string.mnNewLookup).setIcon(android.R.drawable.ic_menu_search); menu.add(0, MENU_ZOOM_OUT, 0, R.string.mnZoomOut).setIcon(R.drawable.ic_menu_zoom_out); menu.add(0, MENU_ZOOM_IN, 0, R.string.mnZoomIn).setIcon(R.drawable.ic_menu_zoom_in); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { boolean enableViewOnline = false; if (this.backItems.size() > 0) { HistoryItem historyItem = backItems.get(backItems.size() - 1); Article current = historyItem.article; Volume d = dictionaryService.getVolume(current.volumeId); enableViewOnline = d.getArticleURLTemplate() != null; } miViewOnline.setEnabled(enableViewOnline); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case MENU_VIEW_ONLINE: viewOnline(); break; case MENU_NEW_LOOKUP: onSearchRequested(); break; case MENU_ZOOM_IN: zoomIn(); break; case MENU_ZOOM_OUT: zoomOut(); break; default: return super.onOptionsItemSelected(item); } return true; } private void viewOnline() { if (this.backItems.size() > 0) { Article current = this.backItems.get(this.backItems.size() - 1).article; Volume d = dictionaryService.getVolume(current.volumeId); String url = d == null ? null : d.getArticleURL(current.title); if (url != null) { Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); startActivity(browserIntent); } } } private void showArticle(String volumeId, long articlePointer, String word, String section) { Log.d(TAG, "word: " + word); Log.d(TAG, "dictionaryId: " + volumeId); Log.d(TAG, "articlePointer: " + articlePointer); Log.d(TAG, "section: " + section); Volume d = dictionaryService.getVolume(volumeId); Entry entry = new Entry(d.getId(), word, articlePointer); entry.section = section; this.showArticle(entry); } private void showArticle(Entry entry) { List<Entry> result = new ArrayList<Entry>(); result.add(entry); try { Iterator<Entry> currentIterator = dictionaryService.followLink(entry.title, entry.volumeId); while (currentIterator.hasNext() && result.size() < 20) { Entry next = currentIterator.next(); if (!next.equals(entry)) { result.add(next); } } } catch (ArticleNotFound e) { Log.d(TAG, String.format("Article \"%s\" not found - unexpected", e.word)); } showNext(new HistoryItem(result)); } private Map<Article, ScrollXY> getScrollPositions() { int orientation = getWindowManager().getDefaultDisplay().getOrientation(); switch (orientation) { case Surface.ROTATION_0: case Surface.ROTATION_180: return scrollPositionsV; default: return scrollPositionsH; } } private void saveScrollPos(int x, int y) { if (!saveScrollPos) { //Log.d(TAG, "Not saving scroll position (disabled)"); return; } if (backItems.size() > 0) { Article a = backItems.get(backItems.size() - 1).article; Map<Article, ScrollXY> positions = getScrollPositions(); ScrollXY s = positions.get(a); if (s == null) { s = new ScrollXY(x, y); positions.put(a, s); } else { s.x = x; s.y = y; } //Log.d(TAG, String.format("Saving scroll position %s for %s", s, a.title)); getScrollPositions().put(a, s); } } private boolean restoreScrollPos() { if (backItems.size() > 0) { Article a = backItems.get(backItems.size() - 1).article; ScrollXY s = getScrollPositions().get(a); if (s == null) { return false; } scrollTo(s); return true; } return false; } private void showNext(HistoryItem item_) { final HistoryItem item = new HistoryItem(item_); final Entry entry = item.next(); runOnUiThread(new Runnable() { public void run() { setTitle(item); setProgress(1000); } }); currentTask = new TimerTask() { public void run() { try { Article a = dictionaryService.getArticle(entry); try { a = dictionaryService.redirect(a); item.article = new Article(a); } catch (ArticleNotFound e) { showMessage(getString(R.string.msgRedirectNotFound, e.word.toString())); return; } catch (RedirectTooManyLevels e) { showMessage(getString(R.string.msgTooManyRedirects, a.getRedirect())); return; } catch (Exception e) { Log.e(TAG, "Redirect failed", e); showError(getString(R.string.msgErrorLoadingArticle, a.title)); return; } HistoryItem oldCurrent = null; if (!backItems.isEmpty()) oldCurrent = backItems.get(backItems.size() - 1); backItems.add(item); if (oldCurrent != null) { HistoryItem newCurrent = item; if (newCurrent.article.equalsIgnoreSection(oldCurrent.article)) { final String section = oldCurrent.article.sectionEquals(newCurrent.article) ? null : newCurrent.article.section; runOnUiThread(new Runnable() { public void run() { resetTitleToCurrent(); if (section != null) { goToSection(section); } setProgress(10000); currentTask = null; } }); } else { showCurrentArticle(); } } else { showCurrentArticle(); } } catch (Exception e) { String msg = getString(R.string.msgErrorLoadingArticle, entry.title); Log.e(TAG, msg, e); showError(msg); } } }; try { timer.schedule(currentTask, 0); } catch (Exception e) { Log.d(TAG, "Failed to schedule task", e); } } private void showCurrentArticle() { runOnUiThread(new Runnable() { public void run() { setProgress(5000); resetTitleToCurrent(); Article a = backItems.get(backItems.size() - 1).article; Log.d(TAG, "Show article: " + a.text); articleView.loadDataWithBaseURL("", wrap(a.text), "text/html", "utf-8", null); } }); } private void updateNextButtonVisibility() { if (currentHideNextButtonTask != null) { currentHideNextButtonTask.cancel(); currentHideNextButtonTask = null; } boolean hasNextArticle = false; if (backItems.size() > 0) { HistoryItem historyItem = backItems.get(backItems.size() - 1); hasNextArticle = historyItem.hasNext(); } final Button nextButton = (Button)findViewById(R.id.NextButton); if (hasNextArticle) { if (nextButton.getVisibility() == View.GONE){ nextButton.setVisibility(View.VISIBLE); } currentHideNextButtonTask = new TimerTask() { @Override public void run() { runOnUiThread(new Runnable() { public void run() { if (useAnimation) { nextButton.startAnimation(fadeOutAnimation); } else { nextButton.setVisibility(View.GONE); } currentHideNextButtonTask = null; } }); } }; try { timer.schedule(currentHideNextButtonTask, 1800); } catch (IllegalStateException e) { //this may happen if orientation changes while users touches screen Log.d(TAG, "Failed to schedule \"Next\" button hide", e); } } else { nextButton.setVisibility(View.GONE); } } private void showMessage(final String message) { runOnUiThread(new Runnable() { public void run() { currentTask = null; setProgress(10000); resetTitleToCurrent(); Toast.makeText(ArticleViewActivity.this, message, Toast.LENGTH_LONG).show(); if (backItems.isEmpty()) { finish(); } } }); } private void showError(final String message) { runOnUiThread(new Runnable() { public void run() { currentTask = null; setProgress(10000); resetTitleToCurrent(); AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(ArticleViewActivity.this); dialogBuilder.setTitle(R.string.titleError).setMessage(message).setNeutralButton(R.string.btnDismiss, new OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); if (backItems.isEmpty()) { finish(); } } }); dialogBuilder.show(); } }); } private void setTitle(CharSequence articleTitle, CharSequence dictTitle) { setTitle(getString(R.string.titleArticleViewActivity, articleTitle, dictTitle)); } private void resetTitleToCurrent() { if (!backItems.isEmpty()) { HistoryItem current = backItems.get(backItems.size() - 1); setTitle(current); } } private void setTitle(HistoryItem item) { StringBuilder title = new StringBuilder(); if (item.entries.size() > 1) { title .append(item.entryIndex + 1) .append("/") .append(item.entries.size()) .append(" "); } Entry entry = item.current(); title.append(entry.title); setTitle(title, dictionaryService.getDisplayTitle(entry.volumeId)); } private String wrap(String articleText) { return new StringBuilder("<html>") .append("<head>") .append(this.sharedCSS) .append(this.mediawikiSharedCSS) .append(this.mediawikiMonobookCSS) .append(this.js) .append("</head>") .append("<body>") .append("<div id=\"globalWrapper\">") .append(articleText) .append("</div>") .append("</body>") .append("</html>") .toString(); } private String wrapCSS(String css) { return String.format("<style type=\"text/css\">%s</style>", css); } private String wrapJS(String js) { return String.format("<script type=\"text/javascript\">%s</script>", js); } private void loadAssets() { try { this.sharedCSS = wrapCSS(readFile("shared.css")); this.mediawikiSharedCSS = wrapCSS(readFile("mediawiki_shared.css")); this.mediawikiMonobookCSS = wrapCSS(readFile("mediawiki_monobook.css")); this.js = wrapJS(readFile("aar.js")); } catch (IOException e) { Log.e(TAG, "Failed to load assets", e); } } private String readFile(String name) throws IOException { final char[] buffer = new char[0x1000]; StringBuilder out = new StringBuilder(); InputStream is = getResources().getAssets().open(name); Reader in = new InputStreamReader(is, "UTF-8"); int read; do { read = in.read(buffer, 0, buffer.length); if (read>0) { out.append(buffer, 0, read); } } while (read>=0); return out.toString(); } @Override protected void onPause() { super.onPause(); SharedPreferences prefs = getPreferences(MODE_PRIVATE); Editor e = prefs.edit(); e.putFloat("articleView.scale", articleView.getScale()); boolean success = e.commit(); if (!success) { Log.w(TAG, "Failed to save article view scale pref"); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SharedPreferences prefs = getPreferences(MODE_PRIVATE); float scale = prefs.getFloat("articleView.scale", 1.0f); int initialScale = Math.round(scale*100); Log.d(TAG, "Setting initial article view scale to " + initialScale); articleView.setInitialScale(initialScale); } @Override protected void onDestroy() { super.onDestroy(); timer.cancel(); scrollPositionsH.clear(); scrollPositionsV.clear(); backItems.clear(); } @Override void onDictionaryServiceReady() { if (this.backItems.isEmpty()) { final Intent intent = getIntent(); if (intent != null && intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SEARCH)) { final String word = intent.getStringExtra("query"); if (currentTask != null) { currentTask.cancel(); } currentTask = new TimerTask() { @Override public void run() { setProgress(500); Log.d(TAG, "intent.getDataString(): " + intent.getDataString()); Iterator<Entry> results = dictionaryService.lookup(word); Log.d(TAG, "Looked up " + word ); if (results.hasNext()) { currentTask = null; Entry entry = results.next(); showArticle(entry); } else { showMessage(getString(R.string.msgArticleNotFound, word)); } } }; try { timer.schedule(currentTask, 0); } catch (Exception e) { Log.d(TAG, "Failed to schedule task", e); showError(getString(R.string.msgErrorLoadingArticle, word)); } } else { String word = intent.getStringExtra("word"); String section = intent.getStringExtra("section"); String volumeId = intent.getStringExtra("volumeId"); long articlePointer = intent.getLongExtra("articlePointer", -1); dictionaryService.setPreferred(volumeId); showArticle(volumeId, articlePointer, word, section); } } else { showCurrentArticle(); } } @SuppressWarnings("unchecked") @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable("backItems", new LinkedList(backItems)); outState.putSerializable("scrollPositionsH", new HashMap(scrollPositionsH)); outState.putSerializable("scrollPositionsV", new HashMap(scrollPositionsV)); } @SuppressWarnings("unchecked") @Override protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); backItems = Collections.synchronizedList((List)savedInstanceState.getSerializable("backItems")); scrollPositionsH = Collections.synchronizedMap((Map)savedInstanceState.getSerializable("scrollPositionsH")); scrollPositionsV = Collections.synchronizedMap((Map)savedInstanceState.getSerializable("scrollPositionsV")); } } Last edited by bardo; 01-23-2012 at 08:58 AM. |
01-27-2012, 07:51 AM | #15 | |
Connoisseur
Posts: 80
Karma: 68347
Join Date: Oct 2009
Location: Sweden
Device: PRS-T1
|
Quote:
Code:
class ArticleView extends WebView { private int mUpdateMode = 3; public void setUpdateMode(int m) { this.mUpdateMode = m; } interface ScrollListener { void onScroll(int l, int t, int oldl, int oldt); } private ScrollListener scrollListener; public ArticleView(Context context) { super(context); } public ArticleView(Context context, AttributeSet attrs) { super(context, attrs); } public ArticleView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (scrollListener != null) { scrollListener.onScroll(l, t, oldl, oldt); } } public void setOnScrollListener(ScrollListener l) { this.scrollListener = l; } @Override public void invalidate() { super.invalidate(mUpdateMode); } @Override public void invalidate(int l, int t, int r, int b) { super.invalidate(l, t, r, b, mUpdateMode); } @Override public void invalidate(Rect dirty) { super.invalidate(dirty, mUpdateMode); } @Override public void invalidateDrawable(Drawable drawable) { super.invalidateDrawable(drawable, mUpdateMode); } @Override public void postInvalidate() { super.postInvalidate(mUpdateMode); } @Override public void postInvalidate(int left, int top, int right, int bottom) { super.postInvalidate(left, top, right, bottom, mUpdateMode); } @Override public void postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom) { super.postInvalidateDelayed(delayMilliseconds, left, top, right, bottom, mUpdateMode); } @Override public void postInvalidateDelayed(long delayMilliseconds) { super.postInvalidateDelayed(delayMilliseconds, mUpdateMode); } @Override public void scrollBy(int x, int y) { super.scrollBy(x, y, mUpdateMode); } @Override public void scrollTo(int x, int y) { super.scrollTo(x, y, mUpdateMode); } } Code:
@Override public void invalidate() { if (It's.A.Sony()) { super.invalidate(mUpdateMode); } else super.invalidate(); } |
|
|
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
USB Host Mode (Master Mode) on K3 | ericepe | Kindle Developer's Corner | 1 | 01-24-2012 04:59 AM |
Request Safe mode or recovery mode for Pocket Edge? | felixblackcat | enTourage eDGe | 25 | 01-08-2012 05:07 PM |
What Does Everyone think of the K3 refresh | Scarpad | Amazon Kindle | 6 | 08-29-2010 10:00 PM |
After refresh | maxhyl | iRex | 1 | 11-23-2008 03:50 AM |