@@ -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> |
@@ -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); | |||
} | |||
} |