Skip to content
This repository was archived by the owner on May 24, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions FBReader/src/main/assets/resources/application/en.xml
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,10 @@
</node>
<node name="moresettings" value="More settings">
<node name="summary" value="Dictionary, Images"/>
<node name="navigateBySentence" value="Navigation">
<node name="summaryOn" value="Navigate by sentence"/>
<node name="summaryOff" value="Navigate by paragraph"/>
</node>
</node>
<node name="dictionary" value="Dictionary">
<node name="summary" value="Dictionary settings"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,18 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.StringTokenizer;

public class FBReaderWithNavigationBar extends FBReaderWithPinchZoom implements TextToSpeech.OnInitListener, TextToSpeech.OnUtteranceCompletedListener, SimpleGestureFilter.SimpleGestureListener, AsyncResponse<Boolean> {

private static final String LOG_TAG ="FBRsWithNavigationBar";
private static final String ACTIVITY_RESUMING_STATE ="ACTIVITY_RESUMING_STATE";
private static final int PARAGRAPH_ID_SHIFT = 16;
private ApiServerImplementation myApi;
private TextToSpeech myTTS;
private int myParagraphIndex = -1;
Expand Down Expand Up @@ -87,16 +90,18 @@ public class FBReaderWithNavigationBar extends FBReaderWithPinchZoom implements

private TtsSentenceExtractor.SentenceIndex mySentences[] = new TtsSentenceExtractor.SentenceIndex[0];
private static int myCurrentSentence = 0;
private static final String UTTERANCE_ID = "GoReadTTS";
private static HashMap<String, String> myCallbackMap;
private volatile int myInitializationStatus;
private final static int TTS_INITIALIZED = 2;
private final static int FULLY_INITIALIZED = TTS_INITIALIZED;
private volatile PowerManager.WakeLock myWakeLock;
private static final String IS_FIRST_TIME_RUNNING_PREFERENCE_TAG = "first_time_running";

private final Set<String> utterancesInProgress = new HashSet<>();
private final Handler handler = new Handler(Looper.getMainLooper());

private boolean activityResuming = false; // this means that the activity is resuming from being in background or orientation change and not created fresh
private boolean isFirstTimeRunningApp;
private static int idCounter = 0;
static {
initCompatibility();
}
Expand All @@ -110,6 +115,27 @@ private static void initCompatibility() {
}
}

private static String makeStringIdForParagraphAndSentence(
int paragraphIndex, int sentenceNumber) {
idCounter++;
long longId = (((long) idCounter) << 32)
| (paragraphIndex << PARAGRAPH_ID_SHIFT) | sentenceNumber;

return Long.toString(longId);
}

private static int sentenceNumberFromId(String stringId) {
long longId = Long.parseLong(stringId);
int intId = (int) longId;
return intId & ((1 << PARAGRAPH_ID_SHIFT) - 1);
}

private static int paragraphNumberFromId(String stringId) {
long longId = Long.parseLong(stringId);
int intId = (int) longId;
return intId >> PARAGRAPH_ID_SHIFT;
}

@Override
public void onCreate(Bundle savedInstanceState) {
accessibilityManager = (AccessibilityManager) getApplicationContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
Expand Down Expand Up @@ -142,7 +168,11 @@ public void onClick(View v) {
setListener(R.id.navigation_bar_skip_previous, new View.OnClickListener() {
public void onClick(View v) {
((ZLAndroidApplication) getApplication()).trackGoogleAnalyticsEvent(Analytics.EVENT_CATEGORY_UI, Analytics.EVENT_ACTION_BUTTON, Analytics.EVENT_LABEL_PREV);
goBackward();
if (fbReader.NavigateBySentenceOption.getValue()) {
goBackwardOneSentence();
} else {
goBackwardOneParagraph();
}
}
});

Expand All @@ -158,7 +188,11 @@ public void onFocusChange(android.view.View view, boolean b) {
setListener(R.id.navigation_bar_skip_next, new View.OnClickListener() {
public void onClick(View v) {
((ZLAndroidApplication) getApplication()).trackGoogleAnalyticsEvent(Analytics.EVENT_CATEGORY_UI, Analytics.EVENT_ACTION_BUTTON, Analytics.EVENT_LABEL_NEXT);
goForward();
if (fbReader.NavigateBySentenceOption.getValue()) {
goForwardOneSentence();
} else {
goForwardOneParagraph();
}
}
});

Expand All @@ -173,10 +207,6 @@ public void onFocusChange(android.view.View view, boolean b) {

setActive(false);

if (myCallbackMap == null) {
myCallbackMap = new HashMap<String, String>();
myCallbackMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, UTTERANCE_ID);
}
myApi = new ApiServerImplementation();
try {
startActivityForResult(new Intent(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA), CHECK_TTS_INSTALLED);
Expand Down Expand Up @@ -285,7 +315,6 @@ public void onResume() {

if (isPaused() && !screenLockEventOccurred) {
playEarcon(START_READING_EARCON);
//speakParagraph(getNextParagraph());
} else {
screenLockEventOccurred = false;
}
Expand Down Expand Up @@ -333,7 +362,6 @@ private boolean isAndroidVersionOlderThanLollipop() {
}

private void postRepaint() {
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
Expand Down Expand Up @@ -496,6 +524,12 @@ private void doFinalInitialization() {

private void highlightParagraph() {
if (0 <= myParagraphIndex && myParagraphIndex < myParagraphsNumber) {
TextPosition paragraphStart = new TextPosition(myParagraphIndex, 0, 0);
TextPosition paragraphEnd = new TextPosition(myParagraphIndex, Integer.MAX_VALUE, 0);
if (paragraphStart.compareTo(myApi.getPageStart()) < 0
|| paragraphEnd.compareTo(myApi.getPageEnd()) > 0) {
myApi.setPageStart(paragraphStart);
}
myApi.highlightArea(
new TextPosition(myParagraphIndex, 0, 0),
new TextPosition(myParagraphIndex, Integer.MAX_VALUE, 0)
Expand All @@ -509,6 +543,8 @@ private void stopTalking() {
setIsPaused();
setActive(false);
enablePlayButton();
// Prevent us reacting to callback from speech we are canceling
utterancesInProgress.clear();
if (myTTS != null) {
myTTS.stop();
}
Expand Down Expand Up @@ -538,8 +574,10 @@ private synchronized void setActive(final boolean isActiveToUse) {
}

private void speakString(String text, final int sentenceNumber) {
HashMap<String, String> callbackMap = new HashMap<String, String>();
callbackMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, Integer.toString(sentenceNumber));
String utteranceId = makeStringIdForParagraphAndSentence(myParagraphIndex, sentenceNumber);
HashMap<String, String> callbackMap = new HashMap<>();
callbackMap.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, utteranceId);
utterancesInProgress.add(utteranceId);
myTTS.speak(text, TextToSpeech.QUEUE_ADD, callbackMap);
}

Expand Down Expand Up @@ -567,7 +605,7 @@ private String getNextParagraph() {
final FBReaderApp fbReader = (FBReaderApp)FBReaderApp.Instance();
ZLTextRegion region = fbReader.getTextView().getDoubleTapSelectedRegion();

boolean shouldHighlightSentence = false;
boolean shouldHighlightSentence = fbReader.NavigateBySentenceOption.getValue();
if(region == null && fbReader.getTextView().didScroll()){
region = fbReader.getTextView().getTopOfPageRegion();
shouldHighlightSentence = true;
Expand Down Expand Up @@ -610,7 +648,6 @@ private String getNextParagraph() {
}
myCurrentSentence = currentSentence;
}
waitForTextPosition();
if(shouldHighlightSentence){
highlightSentence(myCurrentSentence);
}
Expand Down Expand Up @@ -651,7 +688,7 @@ private void speakParagraph(String text) {
int sentenceNumber = 0;
int numWordIndices = sentenceList.size();

if (isPaused()) {
if (isPaused() || fbReader.NavigateBySentenceOption.getValue()) {
enablePauseButton();
setIsPlaying();
if (myCurrentSentence > 0 && numWordIndices > myCurrentSentence) {
Expand All @@ -678,16 +715,32 @@ private void speakParagraph(String text) {

@Override
public void onUtteranceCompleted(String uttId) {
String lastSentenceID = Integer.toString(lastSentence);
if (isActive() && uttId.equals(lastSentenceID)) {
handler.post(new Runnable() {
@Override
public void run() {
onUtteranceCompletedUiThread(uttId);
}
});
}

private void onUtteranceCompletedUiThread(String uttId) {
if (!utterancesInProgress.contains(uttId)) {
return;
}
utterancesInProgress.remove(uttId);
int sentenceNumber = sentenceNumberFromId(uttId);
if (isActive() && (sentenceNumber == lastSentence)) {
++myParagraphIndex;
speakParagraph(getNextParagraph());
myCurrentSentence = 0;
String text = getNextParagraph();
speakParagraph(text);
if (myParagraphIndex >= myParagraphsNumber) {
stopTalking();
}
} else {
myCurrentSentence = Integer.parseInt(uttId);
myCurrentSentence = sentenceNumber;
if (isActive()) {
// The next sentence is already scheduled. Highlight it.
int listSize = mySentences.length;
if (listSize > 1 && myCurrentSentence < listSize) {
highlightSentence(myCurrentSentence);
Expand Down Expand Up @@ -746,17 +799,24 @@ private void pause() {
setIsPaused();
}

private void highlightSentence(int myCurrentSentence) {
if (myCurrentSentence >= mySentences.length) {
static boolean init = false;
static int lastpp = 0;
static int lastsentence = 0;
private void highlightSentence(int sentenceIndexInCurrentParagraph) {
init = true;
lastpp = myParagraphIndex;
lastsentence = sentenceIndexInCurrentParagraph;
if (sentenceIndexInCurrentParagraph >= mySentences.length) {
return;
}
int endEI = myCurrentSentence < mySentences.length-1 ? mySentences[myCurrentSentence+1].i-1: Integer.MAX_VALUE;
int endEI = (sentenceIndexInCurrentParagraph < mySentences.length - 1)
? mySentences[sentenceIndexInCurrentParagraph+1].i - 1 : Integer.MAX_VALUE;

TextPosition stPos;
if (myCurrentSentence == 0)
if (sentenceIndexInCurrentParagraph == 0)
stPos = new TextPosition(myParagraphIndex, 0, 0);
else
stPos = new TextPosition(myParagraphIndex, mySentences[myCurrentSentence].i, 0);
stPos = new TextPosition(myParagraphIndex, mySentences[sentenceIndexInCurrentParagraph].i, 0);

TextPosition edPos = new TextPosition(myParagraphIndex, endEI, 0);
if (stPos.compareTo(myApi.getPageStart()) < 0 || edPos.compareTo(myApi.getPageEnd()) > 0)
Expand Down Expand Up @@ -798,30 +858,73 @@ private int getPlayButtonImageResource(boolean isPlayButton) {
return R.drawable.ic_pause_white_24dp;
}

private void goForward() {
private void goForwardOneParagraph() {
boolean wasPlaying = isPlaying();
stopTalking();
playEarcon(FORWARD_EARCON);
if (myParagraphIndex < myParagraphsNumber) {
myParagraphIndex++;
myCurrentSentence = 0;
final String nextParagraph = getNextParagraph();
if (wasPlaying) {
speakParagraph(nextParagraph);
}
}
}

private void goBackward() {
private void goForwardOneSentence() {
final boolean wasPlaying = isPlaying();
stopTalking();
playEarcon(FORWARD_EARCON);
final int nextSentence = myCurrentSentence + 1;
final String nextParagraph;
if (nextSentence < mySentences.length) {
nextParagraph = getNextParagraph();
myCurrentSentence = nextSentence;
} else {
myParagraphIndex++;
nextParagraph = getNextParagraph();
myCurrentSentence = 0;
}
if (wasPlaying) {
speakParagraph(nextParagraph);
}
highlightSentence(myCurrentSentence);
}

private void goBackwardOneParagraph() {
boolean wasPlaying = isPlaying();
stopTalking();
playEarcon(BACK_EARCON);
gotoPreviousParagraph();
final String nextParagraph = getNextParagraph();
myCurrentSentence = 0;
if (wasPlaying) {
speakParagraph(nextParagraph);
} else {
highlightSentence(myCurrentSentence);
}
}

private void goBackwardOneSentence() {
boolean wasPlaying = isPlaying();
stopTalking();
playEarcon(BACK_EARCON);
final String nextParagraph;
if (myCurrentSentence == 0) {
gotoPreviousParagraph();
nextParagraph = getNextParagraph();
myCurrentSentence = mySentences.length - 1;
} else {
nextParagraph = getNextParagraph();
myCurrentSentence--;
}
if (wasPlaying) {
speakParagraph(nextParagraph);
}
highlightSentence(myCurrentSentence);
}

private void showMainMenu() {
stopTalking();
playEarcon(MENU_EARCON);
Expand Down Expand Up @@ -890,6 +993,7 @@ public boolean onKeyDown(int keyCode, KeyEvent event) {
}
finish();
}

return super.onKeyDown(keyCode, event);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ protected void onClick() {
final Screen moreSettingsScreen = createPreferenceScreen("moresettings");
myScreen.removePreference(dictionaryScreen.myScreen);
myScreen.removePreference(imagesScreen.myScreen);
moreSettingsScreen.addOption(fbReader.NavigateBySentenceOption, "navigateBySentence");
moreSettingsScreen.addPreference(dictionaryScreen.myScreen);
moreSettingsScreen.addPreference(imagesScreen.myScreen);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.view.ViewGroup;

import org.benetech.android.R;
import org.geometerplus.zlibrary.core.options.ZLBooleanOption;
Expand Down Expand Up @@ -166,7 +166,7 @@ public void setUpNestedScreen(PreferenceScreen preferenceScreen) {
if(dialog != null) {
Toolbar bar;

LinearLayout root = (LinearLayout) dialog.findViewById(android.R.id.list).getParent();
ViewGroup root = (ViewGroup) dialog.findViewById(android.R.id.list).getParent();
bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.sub_settings, root, false);
root.addView(bar, 0); // insert at top

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ public static enum ImageTappingAction {
public final ZLBooleanOption ShowPositionsInCancelMenuOption =
new ZLBooleanOption("CancelMenu", "positions", true);

public final ZLBooleanOption NavigateBySentenceOption =
new ZLBooleanOption("Options", "NavigateBySentence", false);

private final ZLKeyBindings myBindings = new ZLKeyBindings("Keys");

public final FBView BookTextView;
Expand Down