Add the ability to import an eSpeak dictionary file from the SD card.

This commit is contained in:
Reece H. Dunn
2013-09-17 13:41:01 +01:00
parent dea3ee743f
commit 9c00360347
6 changed files with 239 additions and 4 deletions
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Spinner
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/dictionaries"
android:gravity="bottom"
android:layout_gravity="center_vertical" />
</LinearLayout>
+2
View File
@@ -92,4 +92,6 @@
<string name="variant_old">Old</string>
<string name="variant_croak">Croak</string>
<string name="variant_whisper">Whisper</string>
<string name="import_voice_title">Import eSpeak dictionary</string>
<string name="import_voice_description">Import an eSpeak voice dictionary file from the SD card.</string>
</resources>
@@ -0,0 +1,69 @@
/*
* Copyright (C) 2013 Reece H. Dunn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reecedunn.espeak;
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.io.File;
public class FileListAdapter extends ArrayAdapter<File>
{
private final LayoutInflater mInflater;
static class ViewHolder
{
public TextView text;
}
public FileListAdapter(Activity context, File[] resources)
{
super(context, android.R.layout.simple_list_item_1, resources);
mInflater = context.getLayoutInflater();
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if (convertView == null)
{
convertView = mInflater.inflate(android.R.layout.simple_list_item_1, parent, false);
holder = new ViewHolder();
holder.text = (TextView)convertView.findViewById(android.R.id.text1);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
File file = getItem(position);
holder.text.setText(file.getName());
return convertView;
}
@Override
public View getDropDownView(int position, View convertView, ViewGroup parent)
{
return getView(position, convertView, parent);
}
}
@@ -26,14 +26,30 @@ import java.io.InputStream;
public class FileUtils {
public static String read(File file) throws IOException {
return read(new FileInputStream(file), (int)file.length());
return readByteArray(new FileInputStream(file), (int)file.length()).toString();
}
public static String read(InputStream stream) throws IOException {
return read(stream, stream.available());
return readByteArray(stream, stream.available()).toString();
}
public static String read(InputStream stream, int length) throws IOException {
return readByteArray(stream, length).toString();
}
public static byte[] readBinary(File file) throws IOException {
return readByteArray(new FileInputStream(file), (int)file.length()).toByteArray();
}
public static byte[] readBinary(InputStream stream) throws IOException {
return readByteArray(stream, stream.available()).toByteArray();
}
public static byte[] readBinary(InputStream stream, int length) throws IOException {
return readByteArray(stream, length).toByteArray();
}
private static ByteArrayOutputStream readByteArray(InputStream stream, int length) throws IOException {
ByteArrayOutputStream content = new ByteArrayOutputStream(length);
int c = stream.read();
while (c != -1)
@@ -41,13 +57,17 @@ public class FileUtils {
content.write((byte)c);
c = stream.read();
}
return content.toString();
return content;
}
public static void write(File outputFile, String contents) throws IOException {
write(outputFile, contents.getBytes());
}
public static void write(File outputFile, byte[] contents) throws IOException {
FileOutputStream outputStream = new FileOutputStream(outputFile);
try {
outputStream.write(contents.getBytes(), 0, contents.length());
outputStream.write(contents, 0, contents.length);
} finally {
outputStream.close();
}
@@ -29,6 +29,7 @@ import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import com.reecedunn.espeak.preference.ImportVoicePreference;
import com.reecedunn.espeak.preference.SeekBarPreference;
import com.reecedunn.espeak.preference.SpeakPunctuationPreference;
import com.reecedunn.espeak.preference.VoiceVariantPreference;
@@ -101,6 +102,17 @@ public class TtsSettingsActivity extends PreferenceActivity {
}
}
private static Preference createImportVoicePreference(Context context) {
final String title = context.getString(R.string.import_voice_title);
final ImportVoicePreference pref = new ImportVoicePreference(context);
pref.setTitle(title);
pref.setDialogTitle(title);
pref.setOnPreferenceChangeListener(mOnPreferenceChanged);
pref.setDescription(R.string.import_voice_description);
return pref;
}
private static Preference createVoiceVariantPreference(Context context, VoiceSettings settings, int titleRes) {
final String title = context.getString(titleRes);
@@ -172,6 +184,7 @@ public class TtsSettingsActivity extends PreferenceActivity {
SpeechSynthesis engine = new SpeechSynthesis(context, null);
VoiceSettings settings = new VoiceSettings(PreferenceManager.getDefaultSharedPreferences(context), engine);
group.addPreference(createImportVoicePreference(context));
group.addPreference(createVoiceVariantPreference(context, settings, R.string.espeak_variant));
group.addPreference(createSpeakPunctuationPreference(context, settings, R.string.espeak_speak_punctuation));
group.addPreference(createSeekBarPreference(context, engine.Rate, VoiceSettings.PREF_RATE, R.string.setting_default_rate));
@@ -0,0 +1,117 @@
/*
* Copyright (C) 2013 Reece H. Dunn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.reecedunn.espeak.preference;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Environment;
import android.preference.DialogPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Spinner;
import com.reecedunn.espeak.CheckVoiceData;
import com.reecedunn.espeak.DownloadVoiceData;
import com.reecedunn.espeak.FileListAdapter;
import com.reecedunn.espeak.FileUtils;
import com.reecedunn.espeak.R;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
public class ImportVoicePreference extends DialogPreference {
private File mRoot;
private Spinner mDictionaries;
public ImportVoicePreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setDialogLayoutResource(R.layout.import_voice_preference);
setLayoutResource(R.layout.information_view);
setPositiveButtonText(android.R.string.ok);
setNegativeButtonText(android.R.string.cancel);
mRoot = Environment.getExternalStorageDirectory();
}
public ImportVoicePreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ImportVoicePreference(Context context) {
this(context, null);
}
public void setDescription(int resId) {
callChangeListener(getContext().getString(resId));
}
@Override
protected View onCreateDialogView() {
View root = super.onCreateDialogView();
mDictionaries = (Spinner)root.findViewById(R.id.dictionaries);
return root;
}
@Override
protected void onBindDialogView(View view) {
super.onBindDialogView(view);
File[] dictionaries = mRoot.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return !file.isDirectory() && file.getName().endsWith("_dict");
}
});
Arrays.sort(dictionaries);
mDictionaries.setAdapter(new FileListAdapter((Activity)getContext(), dictionaries));
}
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
new AsyncTask<Object,Object,Object>() {
@Override
protected Object doInBackground(Object... objects) {
File source = (File)mDictionaries.getSelectedItem();
File destination = new File(CheckVoiceData.getDataPath(getContext()), source.getName());
try {
byte[] data = FileUtils.readBinary(source);
FileUtils.write(destination, data);
} catch (IOException e) {
}
return null;
}
@Override
protected void onPostExecute(Object object) {
final Intent intent = new Intent(DownloadVoiceData.BROADCAST_LANGUAGES_UPDATED);
getContext().sendBroadcast(intent);
}
}.execute();
break;
}
super.onClick(dialog, which);
}
}