Skip to content
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
23 changes: 23 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,36 @@
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

<application
android:name=".GlanceApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/Dark" >

<service
android:name=".tts.GlanceTtsService"

android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.TTS_SERVICE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data
android:name="android.speech.tts"
android:resource="@xml/tts_engine" />
</service>

<activity android:name=".tts.CheckVoiceData"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.speech.tts.engine.CHECK_TTS_DATA" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>

<activity android:name=".activities.MainActivity"
android:theme="@style/Dark.Spritzer">
<intent-filter>
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/java/pro/dbro/glance/AppSpritzer.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public AppSpritzer(Bus bus, TextView target) {
restoreState(true);
}

public AppSpritzer(TextView target) {
super(target);
context = target.getContext().getApplicationContext();
}

public AppSpritzer(Bus bus, TextView target, Uri mediaUri) {
super(target);
context = target.getContext().getApplicationContext();
Expand Down
164 changes: 164 additions & 0 deletions app/src/main/java/pro/dbro/glance/tts/CheckVoiceData.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package pro.dbro.glance.tts;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.text.TextUtils;
import android.util.Log;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

/**
* Created by george on 11/18/15.
*/
public class CheckVoiceData extends Activity {
private static final String TAG = "CheckVoiceData";

private String[] SUPPORTED_LANGUAGES = null;
// {
// "uzbek", "eng-GBR", "eng-USA" ,"pt-BR" ,"por" ,"eng","pt","por","por-BRA"
// };

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

generateLanguageList();

Intent intent = getIntent();
List<String> checkLanguages = getCheckVoiceDataFor(intent);

// If the call didn't specify which languages to check, check
// for all the supported ones.
if (checkLanguages.isEmpty()) {
checkLanguages = Arrays.asList(SUPPORTED_LANGUAGES);
}

ArrayList<String> available = new ArrayList<String>();
ArrayList<String> unavailable = new ArrayList<String>();

for (String lang : checkLanguages) {
// This check is required because checkLanguages might contain
// an arbitrary list of languages if the intent specified them
// {@link #getCheckVoiceDataFor}.
available.add(lang);
// if (isLanguageSupported(lang)) {
// if (isDataInstalled(lang)) {
// available.add(lang);
// } else {
// unavailable.add(lang);
// }
// }
}

int result;
if (!checkLanguages.isEmpty() && available.isEmpty()) {
// No voices available at all.
result = TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL;
} else if (!unavailable.isEmpty()) {
// Some voices are available, but some have missing
// data.
result = TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL;
} else {
// All voices are available.
result = TextToSpeech.Engine.CHECK_VOICE_DATA_PASS;
}

// We now return the list of available and unavailable voices
// as well as the return code.
Intent returnData = new Intent();
returnData.putStringArrayListExtra(
TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES, available);
returnData.putStringArrayListExtra(
TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES, unavailable);
setResult(result, returnData);
finish();
}

private void generateLanguageList() {
if ( SUPPORTED_LANGUAGES != null )return;
List<String> ss = new ArrayList<String>();
for (Locale locale : Locale.getAvailableLocales()) {
try {
if ("".equals(locale.getCountry())) {
ss.add(locale.getISO3Language());
}
else {
ss.add(locale.getISO3Language()+ "-" + locale.getISO3Country());
}
} catch (Exception e) {
}

}
SUPPORTED_LANGUAGES=ss.toArray(new String[]{});
}

/**
* The intent that launches this activity can contain an intent extra
* {@link TextToSpeech.Engine.EXTRA_CHECK_VOICE_DATA_FOR} that might specify
* a given language to check voice data for. If the intent does not contain
* this extra, we assume that a voice check for all supported languages
* was requested.
*/
private List<String> getCheckVoiceDataFor(Intent intent) {
ArrayList<String> list = intent.getStringArrayListExtra(
TextToSpeech.Engine.EXTRA_CHECK_VOICE_DATA_FOR);
ArrayList<String> ret = new ArrayList<String>();
if (list != null) {
for (String lang : list) {
if (!TextUtils.isEmpty(lang)) {
ret.add(lang);
}
}
}

return ret;
}

/**
* Checks whether a given language is in the list of supported languages.
*/
private boolean isLanguageSupported(String input) {
generateLanguageList();
for (String lang : SUPPORTED_LANGUAGES) {
if (lang.equals(input)) {
return true;
}
}

return false;
}

/*
* Note that in our example, all data is packaged in our APK as
* assets (it could be a raw resource as well). This check is unnecessary
* because it will always succeed.
*
* If for example, engine data was downloaded or installed on external storage,
* this check would make much more sense.
*/
private boolean isDataInstalled(String lang) {
try {
InputStream is = getAssets().open(lang + ".freq");

if (is != null) {
is.close();
} else {
return false;
}
} catch (IOException e) {
Log.w(TAG, "Unable to find data for: " + lang + ", exception: " + e);
return false;
}

// The asset InputStream was non null, and therefore this
// data file is available.
return true;
}

}
174 changes: 174 additions & 0 deletions app/src/main/java/pro/dbro/glance/tts/GlanceTtsService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@

package pro.dbro.glance.tts;

import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.HandlerThread;
import android.speech.tts.SynthesisCallback;
import android.speech.tts.SynthesisRequest;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeechService;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import pro.dbro.glance.lib.Spritzer;
import pro.dbro.glance.lib.SpritzerTextView;

import java.util.concurrent.Semaphore;

/**
* Implements the Flite Engine as a TextToSpeechService
*
*/

@TargetApi(14)
public class GlanceTtsService extends TextToSpeechService {
private final static String LOG_TAG = "Flite_Java_" + GlanceTtsService.class.getSimpleName();

private static final String DEFAULT_LANGUAGE = "eng";
private static final String DEFAULT_COUNTRY = "";
private static final String DEFAULT_VARIANT = "";

private String mCountry = DEFAULT_COUNTRY;
private String mLanguage = DEFAULT_LANGUAGE;
private String mVariant = DEFAULT_VARIANT;
private Semaphore sem = new Semaphore(0);
private Object mAvailableVoices;
private SynthesisCallback mCallback;

private Util util = new Util();

private HandlerThread ht = new HandlerThread("HELPER");

private Spritzer.SpritzerCallback mSplitzerCallback = new Spritzer.SpritzerCallback() {
@Override
public void onSpritzerFinished() {
finish(false);
}
};

@Override
public void onCreate() {
initializeFliteEngine();

ht.start();

// This calls onIsLanguageAvailable() and must run after Initialization
super.onCreate();

IntentFilter receiveFilter = new IntentFilter("finishTTS");

LocalBroadcastManager.getInstance(this).
registerReceiver(mBroadcastReceiver, receiveFilter);

}

private void initializeFliteEngine() {
}

@Override
protected String[] onGetLanguage() {
Log.v(LOG_TAG, "onGetLanguage");
return new String[] {
mLanguage, mCountry, mVariant
};
}

@Override
protected int onIsLanguageAvailable(String language, String country, String variant) {
Log.v(LOG_TAG, "onIsLanguageAvailable"+language+country+variant);
return TextToSpeech.LANG_AVAILABLE;//mEngine.isLanguageAvailable(language, country, variant);
}

@Override
protected int onLoadLanguage(String language, String country, String variant) {
Log.v(LOG_TAG, "onLoadLanguage"+language+country+variant);
return TextToSpeech.LANG_AVAILABLE;//mEngine.isLanguageAvailable(language, country, variant);
}

@Override
protected void onStop() {

Log.v(LOG_TAG, "onStop");
}

@Override
protected synchronized void onSynthesizeText(
SynthesisRequest request, SynthesisCallback callback) {
Log.v(LOG_TAG, "onSynthesize");

String language = request.getLanguage();
String country = request.getCountry();
String variant = request.getVariant();
final String text = request.getText();
Integer speechrate = request.getSpeechRate();

Log.v(LOG_TAG, text);

boolean result = true;

if (! ((mLanguage == language) &&
(mCountry == country) &&
(mVariant == variant ))) {
//result = mEngine.setLanguage(language, country, variant);
mLanguage = language;
mCountry = country;
mVariant = variant;
}

if (!result) {
Log.e(LOG_TAG, "Could not set language for synthesis");
return;
}

mCallback = callback;

Handler hd = new Handler(ht.getLooper());

hd.post(new Runnable() {
@Override
public void run() {

SpritzerTextView spritzerTextView = (SpritzerTextView) util.generateView(GlanceTtsService.this);
spritzerTextView.getSpritzer().setTextAndStart(text, mSplitzerCallback, true);


}
});

sem = new Semaphore(0);

try {
sem.acquire();
} catch (InterruptedException e) {
}
mCallback.done();
}

/**
* Listens for language update broadcasts and initializes the flite engine.
*/
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Handler hd = new Handler(ht.getLooper());
hd.post(new Runnable() {
@Override
public void run() {
finish(true);
}
});
}
};

private void finish(boolean b) {
if ( mCallback != null ) {
util.removeView(this);
sem.release();
}
}
}
Loading