修复语音朗读部分bug

pull/5/head
fengyuecanzhu 4 years ago
parent e1e8f22100
commit 34e2267ba9
  1. BIN
      .idea/caches/build_file_checksums.ser
  2. 17
      README.md
  3. 6
      app/src/main/assets/updatelog.fy
  4. 93
      app/src/main/java/xyz/fycz/myreader/model/audio/AudioPlayer.java
  5. 621
      app/src/main/java/xyz/fycz/myreader/model/audio/ReadAloudService.java
  6. 200
      app/src/main/java/xyz/fycz/myreader/model/audio/ReadService.java
  7. 4
      app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java
  8. 4
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java
  9. 4
      app/src/main/java/xyz/fycz/myreader/widget/ProgressButton.java
  10. 4
      app/version_code.properties

@ -2,7 +2,7 @@
风月读书,一款开源、无广告的小说阅读软件。 风月读书,一款开源、无广告的小说阅读软件。
demo下载:[https://fycz.lanzoui.com/iNvVQiam1cd](https://fycz.lanzoui.com/iNvVQiam1cd) 成品下载【11.11 新增语音朗读】:[https://fycz.lanzoui.com/iETUwib10af](https://fycz.lanzoui.com/iETUwib10af)
#### 一、关于书源 #### 一、关于书源
@ -195,13 +195,8 @@ demo下载:[https://fycz.lanzoui.com/iNvVQiam1cd](https://fycz.lanzoui.com/iNv
* 某点的排行榜、分类,全本小说网 * 某点的排行榜、分类,全本小说网
* 制作发现源方法与书源类似,在此不再赘述 * 制作发现源方法与书源类似,在此不再赘述
![Image](./img/1.png) ![Image](./img/1.png)![Image](./img/2.png)
![Image](./img/2.png) ![Image](./img/3.png)![Image](./img/4.png)
![Image](./img/3.png) ![Image](./img/10.png)![Image](./img/5.png)
![Image](./img/4.png) ![Image](./img/6.png)![Image](./img/7.png)
![Image](./img/10.png) ![Image](./img/8.png)![Image](./img/9.png)
![Image](./img/5.png)
![Image](./img/6.png)
![Image](./img/7.png)
![Image](./img/8.png)
![Image](./img/9.png)

@ -1,3 +1,9 @@
2020.11.12
风月读书v1.20.1111208
1、修复语音朗读定时停止无效的bug
2、修复语音朗读时切换日夜间闪退的bug
3、修复安卓5进入字体界面闪退的bug
2020.11.11 2020.11.11
风月读书v1.20.1111121 风月读书v1.20.1111121
1、新增语音朗读(听书) 1、新增语音朗读(听书)

@ -0,0 +1,93 @@
package xyz.fycz.myreader.model.audio;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
import android.util.Log;
import java.util.concurrent.LinkedBlockingQueue;
public class AudioPlayer {
private static String TAG = "AudioPlayer";
private final int SAMPLE_RATE = 16000;
private boolean playing = false;
private LinkedBlockingQueue<byte[]> audioQueue = new LinkedBlockingQueue();
// 初始化播放器
private int iMinBufSize = AudioTrack.getMinBufferSize(SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_16BIT);
private AudioTrack audioTrack;
private byte[] tempData;
private Thread ttsPlayerThread;
AudioPlayer(){
Log.i(TAG,"init...");
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, SAMPLE_RATE,
AudioFormat.CHANNEL_OUT_MONO
, AudioFormat.ENCODING_PCM_16BIT,
iMinBufSize*10, AudioTrack.MODE_STREAM);
playing = true;
ttsPlayerThread = new Thread(() -> {
while (playing) {
tempData = audioQueue.poll();
if (tempData == null) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
if (audioTrack.getPlayState() != AudioTrack.PLAYSTATE_PLAYING) {
Log.d(TAG, "audioTrack.play");
audioTrack.play();
}
Log.d(TAG, "audioTrack.write");
audioTrack.write(tempData, 0, tempData.length);
}
}
Log.d(TAG, "released!");
});
ttsPlayerThread.start();
}
/**
* 设置要播放的音频数据
* @param data 音频数组
*/
public void setAudioData(byte[] data){
Log.d(TAG, "data enqueue.");
audioQueue.offer(data);
//非阻塞
}
/**
* 停止播放并释放资源此对象无法再用来播放
*/
public void stop(){
release();
stopPlay();
}
/**
* 释放资源此对象无法再用来播放
*/
public void release() {
playing = false;
Log.d(TAG, "releasing...");
}
/**
* 停止当前播放并清空未播放的数据当再用setAudioData()设置新数据时才会播放
*/
public void stopPlay() {
audioQueue.clear();
audioTrack.pause();
audioTrack.flush();
Log.d(TAG, "paused.");
}
}

@ -0,0 +1,621 @@
package xyz.fycz.myreader.model.audio;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.ui.activity.ReadActivity;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import static android.text.TextUtils.isEmpty;
/**
* Created by GKF on 2018/1/2.
* 朗读服务
*/
public class ReadAloudService extends Service {
private static final String TAG = ReadAloudService.class.getSimpleName();
public static final String ActionStartService = "startService";
public static final String ActionDoneService = "doneService";
public static final String ActionNewReadAloud = "newReadAloud";
public static final String ActionPauseService = "pauseService";
public static final String ActionResumeService = "resumeService";
public static final String ActionLastPService = "lastPService";
public static final String ActionNextPService = "nextPService";
private static final String ActionReadActivity = "readActivity";
private static final String ActionSetTimer = "updateTimer";
private static final String ActionSetProgress = "setProgress";
private static final String ActionUITimerStop = "UITimerStop";
private static final String ActionUITimerRemaining = "UITimerRemaining";
public final static String ALOUD_STATE = "aloud_state";
public final static String ALOUD_TIMER = "aloud_timer";
public final static String READ_ALOUD_NUMBER = "readAloudNumber";
public final static String READ_ALOUD_START = "readAloudStart";
private static final int notificationId = 3222;
public static final int maxTimeMinute = 360;
public static Boolean running = false;
private TextToSpeech textToSpeech;
private TextToSpeech textToSpeech_ui;
private HashMap mParams;
private Boolean ttsInitSuccess = false;
private Boolean speak = true;
private Boolean pause = false;
private List<String> contentList = new ArrayList<>();
private int nowSpeak;
private static int timeMinute = 0;
private boolean timerEnable = false;
private BroadcastReceiver broadcastReceiver;
private SharedPreferences preference;
private int speechRate;
private int pitch;
private String title;
private String text;
private boolean fadeTts;
private Handler handler = new Handler();
private Handler mainHandler = new Handler(Looper.getMainLooper());
private Runnable dsRunnable;
private int readAloudNumber;
private int progress;
private static ReadEvent mReadEvent;
/**
* 朗读
*/
public static void play(Context context, String content, String title, String text, int progress) {
Intent readAloudIntent = new Intent(context, ReadAloudService.class);
readAloudIntent.setAction(ActionNewReadAloud);
readAloudIntent.putExtra("content", content);
readAloudIntent.putExtra("title", title);
readAloudIntent.putExtra("text", text);
readAloudIntent.putExtra("progress", progress);
context.startService(readAloudIntent);
}
/**
* @param context 停止
*/
public static void stop(Context context) {
if (running) {
Intent intent = new Intent(context, ReadAloudService.class);
intent.setAction(ActionDoneService);
context.startService(intent);
}
}
/**
* @param context 暂停
*/
public static void pause(Context context) {
if (running) {
Intent intent = new Intent(context, ReadAloudService.class);
intent.setAction(ActionPauseService);
context.startService(intent);
}
}
/**
* @param context 继续
*/
public static void resume(Context context) {
if (running) {
Intent intent = new Intent(context, ReadAloudService.class);
intent.setAction(ActionResumeService);
context.startService(intent);
}
}
/**
* @param context 上一段
*/
public static void lastP(Context context) {
if (running) {
Intent intent = new Intent(context, ReadAloudService.class);
intent.setAction(ActionLastPService);
context.startService(intent);
}
}
/**
* @param context 下一段
*/
public static void nextP(Context context) {
if (running) {
Intent intent = new Intent(context, ReadAloudService.class);
intent.setAction(ActionNextPService);
context.startService(intent);
}
}
public static void setTimer(Context context, int minute) {
if (running) {
Intent intent = new Intent(context, ReadAloudService.class);
intent.setAction(ActionSetTimer);
intent.putExtra("minute", minute);
context.startService(intent);
}
}
public static void setProgress(Context context, int progress) {
if (running) {
Intent intent = new Intent(context, ReadAloudService.class);
intent.setAction(ActionSetProgress);
intent.putExtra("progress", progress);
context.startService(intent);
}
}
public static void tts_ui_timer_stop(Context context) {
if (running) {
Intent intent = new Intent(context, ReadAloudService.class);
intent.setAction(ActionUITimerStop);
context.startService(intent);
}
}
public static void tts_ui_timer_remaining(Context context) {
if (running) {
Intent intent = new Intent(context, ReadAloudService.class);
intent.setAction(ActionUITimerRemaining);
context.startService(intent);
}
}
@Override
public void onCreate() {
super.onCreate();
running = true;
preference = SharedPreUtils.getInstance().getSharedReadable();
fadeTts = preference.getBoolean("fadeTTS", false);
dsRunnable = this::doDs;
initBroadcastReceiver();
updateNotification();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
String action = intent.getAction();
if (action != null) {
String sText;
switch (action) {
case ActionDoneService:
stopSelf();
break;
case ActionPauseService:
pauseReadAloud(true);
break;
case ActionResumeService:
resumeReadAloud();
break;
case ActionSetTimer:
updateTimer(intent.getIntExtra("minute", 10));
break;
case ActionNewReadAloud:
newReadAloud(intent.getStringExtra("content"),
intent.getStringExtra("title"),
intent.getStringExtra("text"),
intent.getIntExtra("progress", 0));
break;
case ActionUITimerStop:
sText = getString(R.string.read_aloud_timerstop);
textToSpeech_ui.speak(sText,TextToSpeech.QUEUE_FLUSH, mParams);
break;
case ActionUITimerRemaining:
if (timeMinute > 0 && timeMinute <= maxTimeMinute) {
if (timeMinute<=60) {
sText = getString(R.string.read_aloud_timerremaining, timeMinute);
}
else {
int hours = timeMinute / 60;
int minutes = timeMinute % 60;
sText = getString(R.string.read_aloud_timerremaininglong, hours, minutes);
}
} else {
sText = getString(R.string.read_aloud_timerstop);
}
pauseReadAloud(false);
textToSpeech_ui.speak(sText,TextToSpeech.QUEUE_FLUSH, mParams);
resumeReadAloud();
break;
case ActionLastPService:
lastReadAloud();
break;
case ActionNextPService:
nextReadAloud();
break;
}
}
}
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
private void initTTS() {
if (textToSpeech == null)
textToSpeech = new TextToSpeech(MyApplication.getmContext(), new TTSListener());
if (textToSpeech_ui == null)
textToSpeech_ui = new TextToSpeech(MyApplication.getmContext(), new TTSUIListener());
if (mParams == null) {
mParams = new HashMap();
mParams.put(TextToSpeech.Engine.KEY_PARAM_STREAM, "3");
}
}
private void newReadAloud(String content, String title, String text, int progress) {
if (TextUtils.isEmpty(content)) {
stopSelf();
return;
}
this.text = text;
this.title = title;
this.progress = progress;
nowSpeak = 0;
readAloudNumber = 0;
contentList.clear();
initTTS();
String[] splitSpeech = content.split("\n");
for (String aSplitSpeech : splitSpeech) {
if (!isEmpty(aSplitSpeech)) {
contentList.add(aSplitSpeech);
}
}
if (speak) {
speak = false;
pause = false;
playTTS();
}
}
public void playTTS() {
updateNotification();
if (fadeTts) {
handler.postDelayed(this::playTTSN, 200);
} else {
playTTSN();
}
}
public void playTTSN() {
if (contentList.size() < 1) {
postEvent(ALOUD_STATE, Status.NEXT);
return;
}
if (ttsInitSuccess && !speak) {
speak = !speak;
postEvent(ALOUD_STATE, Status.PLAY);
updateNotification();
initSpeechRateAndPitch();
HashMap<String, String> map = new HashMap<>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "content");
for (int i = nowSpeak; i < contentList.size(); i++) {
if (i == 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_FLUSH, null, "content");
} else {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_FLUSH, map);
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_ADD, null, "content");
} else {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_ADD, map);
}
}
}
}
}
public static void toTTSSetting(Context context) {
//跳转到文字转语音设置界面
try {
Intent intent = new Intent();
intent.setAction("com.android.settings.TTS_SETTINGS");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (Exception ignored) {
}
}
private void initSpeechRateAndPitch() {
if (speechRate != preference.getInt("speechRate", 10)) {
speechRate = preference.getInt("speechRate", 10);
float speechRateF = (float) speechRate / 10;
textToSpeech.setSpeechRate(speechRateF);
}
if (pitch != preference.getInt("readPitch", 10)) {
pitch = preference.getInt("readPitch", 10);
float pitchF = (float) pitch / 10;
textToSpeech.setPitch(pitchF);
}
}
/**
* @param pause true 暂停, false 失去焦点
*/
private void pauseReadAloud(Boolean pause) {
this.pause = pause;
speak = false;
updateNotification();
if (fadeTts) {
handler.postDelayed(() -> textToSpeech.stop(), 300);
} else {
textToSpeech.stop();
}
postEvent(ALOUD_STATE, Status.PAUSE);
}
/**
* 恢复朗读
*/
private void resumeReadAloud() {
updateTimer(0);
pause = false;
updateNotification();
playTTS();
postEvent(ALOUD_STATE, Status.PLAY);
}
/**
* 上一段
*/
private void lastReadAloud(){
if (nowSpeak > 0) {
pauseReadAloud(true);
nowSpeak--;
readAloudNumber -= contentList.get(nowSpeak).length() - 1;
resumeReadAloud();
}
}
/**
* 下一段
*/
private void nextReadAloud(){
if (nowSpeak < contentList.size() - 1) {
pauseReadAloud(true);
readAloudNumber += contentList.get(nowSpeak).length() + 1;
nowSpeak++;
resumeReadAloud();
}
}
private void updateTimer(int minute) {
timeMinute = minute;
if (timeMinute > maxTimeMinute) {
timerEnable = false;
handler.removeCallbacks(dsRunnable);
timeMinute = 0;
updateNotification();
} else if (timeMinute <= 0) {
if (timerEnable) {
handler.removeCallbacks(dsRunnable);
stopSelf();
}
} else {
timerEnable = true;
updateNotification();
handler.removeCallbacks(dsRunnable);
handler.postDelayed(dsRunnable, 60000);
}
}
private void doDs() {
if (!pause) {
timeMinute--;
if (timeMinute == 0) {
stopSelf();
} else if (timeMinute > 0) {
handler.postDelayed(dsRunnable, 60000);
}
}
updateNotification();
}
private PendingIntent getReadBookActivityPendingIntent() {
Intent intent = new Intent(this, ReadActivity.class);
intent.setAction(ReadAloudService.ActionReadActivity);
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
private PendingIntent getThisServicePendingIntent(String actionStr) {
Intent intent = new Intent(this, this.getClass());
intent.setAction(actionStr);
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
/**
* 更新通知
*/
private void updateNotification() {
if (text == null)
text = getString(R.string.read_aloud_s);
String nTitle;
if (pause) {
nTitle = getString(R.string.read_aloud_pause);
} else if (timeMinute > 0 && timeMinute <= maxTimeMinute) {
if (timeMinute<=60) {
nTitle = getString(R.string.read_aloud_timer, timeMinute);
}
else {
int hours = timeMinute / 60;
int minutes = timeMinute % 60;
nTitle = getString(R.string.read_aloud_timerlong, hours, minutes);
}
} else {
nTitle = getString(R.string.read_aloud_t);
}
nTitle += ": " + title;
postEvent(ALOUD_TIMER, nTitle);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, APPCONST.channelIdRead)
.setSmallIcon(R.drawable.ic_volume_up)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_read))
.setOngoing(true)
.setContentTitle(nTitle)
.setContentText(text)
.setContentIntent(getReadBookActivityPendingIntent());
builder.addAction(R.drawable.ic_last, getString(R.string.last), getThisServicePendingIntent(ActionLastPService));
if (pause) {
builder.addAction(R.drawable.ic_play_24dp, getString(R.string.resume), getThisServicePendingIntent(ActionResumeService));
} else {
builder.addAction(R.drawable.ic_pause_24dp, getString(R.string.pause), getThisServicePendingIntent(ActionPauseService));
}
builder.addAction(R.drawable.ic_next, getString(R.string.next), getThisServicePendingIntent(ActionNextPService));
builder.addAction(R.drawable.ic_stop_black_24dp, getString(R.string.stop), getThisServicePendingIntent(ActionDoneService));
builder.setStyle(new androidx.media.app.NotificationCompat.MediaStyle()
.setShowActionsInCompactView(0, 1, 2, 3));
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
Notification notification = builder.build();
startForeground(notificationId, notification);
}
@Override
public void onDestroy() {
running = false;
super.onDestroy();
stopForeground(true);
handler.removeCallbacks(dsRunnable);
postEvent(ALOUD_STATE, Status.STOP);
unregisterReceiver(broadcastReceiver);
clearTTS();
}
private void clearTTS() {
if (textToSpeech != null) {
textToSpeech.stop();
textToSpeech.shutdown();
textToSpeech = null;
}
if (textToSpeech_ui != null) {
textToSpeech_ui.stop();
textToSpeech_ui.shutdown();
textToSpeech_ui = null;
}
}
private void initBroadcastReceiver() {
broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(action)) {
pauseReadAloud(true);
}
}
};
IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
registerReceiver(broadcastReceiver, intentFilter);
}
private final class TTSListener implements TextToSpeech.OnInitListener {
@Override
public void onInit(int i) {
if (i == TextToSpeech.SUCCESS) {
textToSpeech.setLanguage(Locale.CHINA);
textToSpeech.setOnUtteranceProgressListener(new ttsUtteranceListener());
ttsInitSuccess = true;
playTTS();
} else {
ToastUtils.showError("TTS初始化失败!");
ReadAloudService.this.stopSelf();
}
}
}
private final class TTSUIListener implements TextToSpeech.OnInitListener {
@Override
public void onInit(int i) {
if (i == TextToSpeech.SUCCESS) {
textToSpeech_ui.setLanguage(Locale.CHINA);
}
}
}
/**
* 朗读监听
*/
private class ttsUtteranceListener extends UtteranceProgressListener {
@Override
public void onStart(String s) {
postEvent(READ_ALOUD_START, readAloudNumber + 1);
postEvent(READ_ALOUD_NUMBER, readAloudNumber + 1);
}
@Override
public void onDone(String s) {
readAloudNumber = readAloudNumber + contentList.get(nowSpeak).length() + 1;
nowSpeak = nowSpeak + 1;
if (nowSpeak >= contentList.size()) {
postEvent(ALOUD_STATE, Status.NEXT);
}
}
@Override
public void onError(String s) {
pauseReadAloud(true);
postEvent(ALOUD_STATE, Status.PAUSE);
}
@Override
public void onRangeStart(String utteranceId, int start, int end, int frame) {
super.onRangeStart(utteranceId, start, end, frame);
postEvent(READ_ALOUD_NUMBER, readAloudNumber + start);
}
}
private void postEvent(String tag, Object event){
if (mReadEvent != null) {
mReadEvent.onEventOccur(tag, event);
}
}
public static void setReadEvent(ReadEvent readEvent){
mReadEvent = readEvent;
}
public enum Status {
PLAY, STOP, PAUSE, NEXT
}
public interface ReadEvent{
void onEventOccur(String tag, Object event);
}
}

@ -0,0 +1,200 @@
package xyz.fycz.myreader.model.audio;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import xyz.fycz.myreader.util.ToastUtils;
import static android.text.TextUtils.isEmpty;
public class ReadService extends Service {
private static final String TAG = "ReadService";
public static Boolean running = false;
public static final String ActionNewRead = "newRead";
private Boolean speak = true;
private Boolean pause = false;
private List<String> contentList = new ArrayList<>();
private int nowSpeak;
private int speechRate;
private String title;
private String text;
private int readAloudNumber;
private int progress;
private Boolean ttsInitSuccess = false;
private TextToSpeech textToSpeech;
private HashMap mParams;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
String action = intent.getAction();
if (action != null) {
switch (action) {
case ActionNewRead:
newReadAloud(intent.getStringExtra("content"),
intent.getStringExtra("title"),
intent.getStringExtra("text"),
intent.getIntExtra("progress", 0));
break;
}
}
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
private void initTTS() {
if (textToSpeech == null)
textToSpeech = new TextToSpeech(this, status -> {
if (status == TextToSpeech.SUCCESS) {
textToSpeech.setLanguage(Locale.CHINA);
textToSpeech.setOnUtteranceProgressListener(new ttsUtteranceListener());
ttsInitSuccess = true;
playTTS();
} else {
ToastUtils.showError("TTS初始化失败!");
ReadService.this.stopSelf();
}
});
if (mParams == null) {
mParams = new HashMap();
mParams.put(TextToSpeech.Engine.KEY_PARAM_STREAM, "3");
}
}
/**
* 朗读监听
*/
private class ttsUtteranceListener extends UtteranceProgressListener {
@Override
public void onStart(String s) {
//updateMediaSessionPlaybackState();
//RxBus.get().post(RxBusTag.READ_ALOUD_START, readAloudNumber + 1);
//RxBus.get().post(RxBusTag.READ_ALOUD_NUMBER, readAloudNumber + 1);
}
@Override
public void onDone(String s) {
readAloudNumber = readAloudNumber + contentList.get(nowSpeak).length() + 1;
nowSpeak = nowSpeak + 1;
if (nowSpeak >= contentList.size()) {
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.NEXT);
}
}
@Override
public void onError(String s) {
//pauseReadAloud(true);
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.PAUSE);
}
@Override
public void onRangeStart(String utteranceId, int start, int end, int frame) {
super.onRangeStart(utteranceId, start, end, frame);
//RxBus.get().post(RxBusTag.READ_ALOUD_NUMBER, readAloudNumber + start);
}
}
/**
* 朗读
*/
public static void play(Context context, String content, String title, String text, int progress) {
Intent readAloudIntent = new Intent(context, ReadService.class);
readAloudIntent.setAction(ActionNewRead);
readAloudIntent.putExtra("content", content);
readAloudIntent.putExtra("title", title);
readAloudIntent.putExtra("text", text);
readAloudIntent.putExtra("progress", progress);
context.startService(readAloudIntent);
}
private void newReadAloud(String content, String title, String text, int progress) {
if (TextUtils.isEmpty(content)) {
stopSelf();
return;
}
this.text = text;
this.title = title;
this.progress = progress;
nowSpeak = 0;
readAloudNumber = 0;
contentList.clear();
initTTS();
String[] splitSpeech = content.split("\n");
for (String aSplitSpeech : splitSpeech) {
if (!isEmpty(aSplitSpeech)) {
contentList.add(aSplitSpeech);
}
}
if (speak) {
speak = false;
pause = false;
playTTS();
}
}
private void playTTS() {
if (contentList.size() < 1) {
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.NEXT);
return;
}
if (ttsInitSuccess && !speak) {
speak = !speak;
//RxBus.get().post(RxBusTag.ALOUD_STATE, Status.PLAY);
//updateNotification();
//initSpeechRate();
HashMap<String, String> map = new HashMap<>();
map.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID, "content");
for (int i = nowSpeak; i < contentList.size(); i++) {
if (i == 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_FLUSH, null, "content");
} else {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_FLUSH, map);
}
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_ADD, null, "content");
} else {
textToSpeech.speak(contentList.get(i), TextToSpeech.QUEUE_ADD, map);
}
}
}
}
}
public enum Status {
PLAY, STOP, PAUSE, NEXT
}
}

@ -399,11 +399,15 @@ public class ReadActivity extends BaseActivity {
mHandler.sendMessage(mHandler.obtainMessage(4)); mHandler.sendMessage(mHandler.obtainMessage(4));
if ((ReadAloudService.running)) { if ((ReadAloudService.running)) {
if (resetRead) { if (resetRead) {
if (mAudioPlayerDialog != null) {
mHandler.postDelayed(() ->mAudioPlayerDialog.readAloud(), 500); mHandler.postDelayed(() ->mAudioPlayerDialog.readAloud(), 500);
}
return; return;
} }
if (pos == 0) { if (pos == 0) {
if (mAudioPlayerDialog != null) {
mHandler.postDelayed(() ->mAudioPlayerDialog.readAloud(), 500); mHandler.postDelayed(() ->mAudioPlayerDialog.readAloud(), 500);
}
return; return;
} }
} }

@ -39,7 +39,6 @@ import xyz.fycz.myreader.ui.dialog.MultiChoiceDialog;
import xyz.fycz.myreader.ui.dialog.MyAlertDialog; import xyz.fycz.myreader.ui.dialog.MyAlertDialog;
import xyz.fycz.myreader.greendao.entity.BookGroup; import xyz.fycz.myreader.greendao.entity.BookGroup;
import xyz.fycz.myreader.greendao.service.BookGroupService; import xyz.fycz.myreader.greendao.service.BookGroupService;
import xyz.fycz.myreader.model.backup.BackupAndRestore;
import xyz.fycz.myreader.ui.activity.*; import xyz.fycz.myreader.ui.activity.*;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler; import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil; import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
@ -80,8 +79,6 @@ public class BookcasePresenter implements BasePresenter {
private Setting mSetting; private Setting mSetting;
private final List<Book> errorLoadingBooks = new ArrayList<>(); private final List<Book> errorLoadingBooks = new ArrayList<>();
private int finishLoadBookCount = 0; private int finishLoadBookCount = 0;
private final BackupAndRestore mBackupAndRestore;
// private int notifyId = 11;
private ExecutorService es = Executors.newFixedThreadPool(1);//更新/下载线程池 private ExecutorService es = Executors.newFixedThreadPool(1);//更新/下载线程池
public ExecutorService getEs() { public ExecutorService getEs() {
@ -176,7 +173,6 @@ public class BookcasePresenter implements BasePresenter {
mMainActivity = (MainActivity) (mBookcaseFragment.getActivity()); mMainActivity = (MainActivity) (mBookcaseFragment.getActivity());
// mChapterService = new ChapterService(); // mChapterService = new ChapterService();
mSetting = SysManager.getSetting(); mSetting = SysManager.getSetting();
mBackupAndRestore = new BackupAndRestore();
} }
//启动 //启动

@ -47,9 +47,9 @@ public class ProgressButton extends AppCompatButton {
//Get default normal color //Get default normal color
int defaultButtonColor = getResources().getColor(R.color.toast_default); int defaultButtonColor = getResources().getColor(R.color.toast_default);
//Get default progress color //Get default progress color
int defaultProgressColor = getResources().getColor(R.color.colorAccent, null); int defaultProgressColor = getResources().getColor(R.color.colorAccent);
//Get default progress background color //Get default progress background color
int defaultBackColor = getResources().getColor(R.color.toast_default, null); int defaultBackColor = getResources().getColor(R.color.toast_default);
TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.ProgressButton); TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.ProgressButton);

@ -1,2 +1,2 @@
#Wed Nov 11 21:00:58 CST 2020 #Thu Nov 12 08:45:48 CST 2020
VERSION_CODE=155 VERSION_CODE=157

Loading…
Cancel
Save