diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 995a5808f7086da9ff7e8304f5af5fb5f098b89b..714780308c07367e63af8b66bb591bb70a86acf5 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -72,11 +72,6 @@
android:name=".eSpeakActivity"
android:label="@string/app_name"
android:exported="true">
-
-
-
-
-
diff --git a/android/src/com/reecedunn/espeak/TtsService.java b/android/src/com/reecedunn/espeak/TtsService.java
index 22b9b4e39a75cbd1cc7e0d0ae974b7c777b06183..fe1f60becf830110e8c259721f8bf588415a9a13 100644
--- a/android/src/com/reecedunn/espeak/TtsService.java
+++ b/android/src/com/reecedunn/espeak/TtsService.java
@@ -31,6 +31,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioTrack;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
@@ -43,6 +44,11 @@ import android.util.Pair;
import com.reecedunn.espeak.SpeechSynthesis.SynthReadyCallback;
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -50,6 +56,8 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
/**
* Implements the eSpeak engine as a {@link TextToSpeechService}.
@@ -73,6 +81,9 @@ public class TtsService extends TextToSpeechService {
private BroadcastReceiver mOnLanguagesDownloaded = null;
+ private AsyncExtract mAsyncExtract;
+ public static final String BROADCAST_LANGUAGES_UPDATED = "com.reecedunn.espeak.LANGUAGES_UPDATED";
+
@Override
public void onCreate() {
storageContext = EspeakApp.getStorageContext();
@@ -88,6 +99,9 @@ public class TtsService extends TextToSpeechService {
if (mOnLanguagesDownloaded != null) {
unregisterReceiver(mOnLanguagesDownloaded);
}
+ if (mAsyncExtract != null) {
+ mAsyncExtract.cancel(true);
+ }
}
/**
@@ -136,9 +150,24 @@ public class TtsService extends TextToSpeechService {
registerReceiver(mOnLanguagesDownloaded, filter);
}
- final Intent intent = new Intent(storageContext, DownloadVoiceData.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
+ final File dataPath = CheckVoiceData.getDataPath(storageContext).getParentFile();
+
+ mAsyncExtract = new AsyncExtract(storageContext, R.raw.espeakdata, dataPath) {
+ @Override
+ protected void onPostExecute(Integer result) {
+ switch (result) {
+ case RESULT_OK:
+ final Intent intent = new Intent(DownloadVoiceData.BROADCAST_LANGUAGES_UPDATED);
+ sendBroadcast(intent);
+ break;
+ case RESULT_CANCELED:
+ // Do nothing?
+ break;
+ }
+ }
+ };
+
+ mAsyncExtract.execute();
return new Pair<>(null, TextToSpeech.LANG_MISSING_DATA);
}
@@ -346,4 +375,96 @@ public class TtsService extends TextToSpeechService {
mCallback.done();
}
};
+
+ /**
+ * Begin voice data download here instead of an activity.
+ */
+
+ private static final int PROGRESS_STARTING = 0;
+ private static final int PROGRESS_EXTRACTING = 1;
+
+
+ private static final int RESULT_OK = -1;
+ private static final int RESULT_CANCELED = -2;
+
+ private static class ExtractProgress {
+ int total;
+ int progress = 0;
+ int state = PROGRESS_STARTING;
+ File file;
+
+ public ExtractProgress(int total) {
+ this.total = total;
+ }
+ }
+
+ private static class AsyncExtract extends AsyncTask {
+ private final Context mContext;
+ private final int mRawResId;
+ private final File mOutput;
+
+ public AsyncExtract(Context context, int rawResId, File output) {
+ mContext = context;
+ mRawResId = rawResId;
+ mOutput = output;
+ }
+
+ @Override
+ protected Integer doInBackground(Void... params) {
+ FileUtils.rmdir(CheckVoiceData.getDataPath(mContext));
+
+ final InputStream stream = mContext.getResources().openRawResource(mRawResId);
+ final ZipInputStream zipStream = new ZipInputStream(new BufferedInputStream(stream));
+
+ try {
+ ExtractProgress progress = new ExtractProgress(stream.available());
+ progress.state = PROGRESS_EXTRACTING;
+
+ final byte[] buffer = new byte[10240];
+
+ int bytesRead;
+ ZipEntry entry;
+
+ while (!isCancelled() && ((entry = zipStream.getNextEntry()) != null)) {
+ progress.file = new File(mOutput, entry.getName());
+ publishProgress(progress);
+
+ if (entry.isDirectory()) {
+ progress.file.mkdirs();
+ continue;
+ }
+
+ // Ensure the target path exists.
+ progress.file.getParentFile().mkdirs();
+
+ final FileOutputStream outputStream = new FileOutputStream(progress.file);
+ try {
+ while (!isCancelled() && ((bytesRead = zipStream.read(buffer)) != -1)) {
+ outputStream.write(buffer, 0, bytesRead);
+ progress.total += bytesRead;
+ }
+ } finally {
+ outputStream.close();
+ }
+ zipStream.closeEntry();
+ }
+
+ final String version = FileUtils.read(mContext.getResources().openRawResource(R.raw.espeakdata_version));
+ final File outputFile = new File(mOutput, "espeak-ng-data/version");
+
+ FileUtils.write(outputFile, version);
+ return RESULT_OK;
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ zipStream.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return RESULT_CANCELED;
+ }
+ }
}