1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16package com.android.tts.compat; 17 18import android.database.Cursor; 19import android.net.Uri; 20import android.speech.tts.SynthesisCallback; 21import android.speech.tts.SynthesisRequest; 22import android.speech.tts.TextToSpeech; 23import android.speech.tts.TextToSpeechService; 24import android.util.Log; 25 26import java.io.File; 27 28public abstract class CompatTtsService extends TextToSpeechService { 29 30 private static final boolean DBG = false; 31 private static final String TAG = "CompatTtsService"; 32 33 private SynthProxy mNativeSynth = null; 34 35 protected abstract String getSoFilename(); 36 37 @Override 38 public void onCreate() { 39 if (DBG) Log.d(TAG, "onCreate()"); 40 41 String soFilename = getSoFilename(); 42 43 if (mNativeSynth != null) { 44 mNativeSynth.stopSync(); 45 mNativeSynth.shutdown(); 46 mNativeSynth = null; 47 } 48 49 // Load the engineConfig from the plugin if it has any special configuration 50 // to be loaded. By convention, if an engine wants the TTS framework to pass 51 // in any configuration, it must put it into its content provider which has the URI: 52 // content://<packageName>.providers.SettingsProvider 53 // That content provider must provide a Cursor which returns the String that 54 // is to be passed back to the native .so file for the plugin when getString(0) is 55 // called on it. 56 // Note that the TTS framework does not care what this String data is: it is something 57 // that comes from the engine plugin and is consumed only by the engine plugin itself. 58 String engineConfig = ""; 59 Cursor c = getContentResolver().query(Uri.parse("content://" + getPackageName() 60 + ".providers.SettingsProvider"), null, null, null, null); 61 if (c != null){ 62 c.moveToFirst(); 63 engineConfig = c.getString(0); 64 c.close(); 65 } 66 mNativeSynth = new SynthProxy(soFilename, engineConfig); 67 68 // mNativeSynth is used by TextToSpeechService#onCreate so it must be set prior 69 // to that call. 70 // getContentResolver() is also moved prior to super.onCreate(), and it works 71 // because the super method don't sets a field or value that affects getContentResolver(); 72 // (including the content resolver itself). 73 super.onCreate(); 74 } 75 76 @Override 77 public void onDestroy() { 78 if (DBG) Log.d(TAG, "onDestroy()"); 79 super.onDestroy(); 80 81 if (mNativeSynth != null) { 82 mNativeSynth.shutdown(); 83 } 84 mNativeSynth = null; 85 } 86 87 @Override 88 protected String[] onGetLanguage() { 89 if (mNativeSynth == null) return null; 90 return mNativeSynth.getLanguage(); 91 } 92 93 @Override 94 protected int onIsLanguageAvailable(String lang, String country, String variant) { 95 if (DBG) Log.d(TAG, "onIsLanguageAvailable(" + lang + "," + country + "," + variant + ")"); 96 if (mNativeSynth == null) return TextToSpeech.ERROR; 97 return mNativeSynth.isLanguageAvailable(lang, country, variant); 98 } 99 100 @Override 101 protected int onLoadLanguage(String lang, String country, String variant) { 102 if (DBG) Log.d(TAG, "onLoadLanguage(" + lang + "," + country + "," + variant + ")"); 103 int result = onIsLanguageAvailable(lang, country, variant); 104 if (result >= TextToSpeech.LANG_AVAILABLE) { 105 mNativeSynth.setLanguage(lang, country, variant); 106 } 107 108 return result; 109 } 110 111 @Override 112 protected void onSynthesizeText(SynthesisRequest request, SynthesisCallback callback) { 113 if (mNativeSynth == null) { 114 callback.error(); 115 return; 116 } 117 118 // Set language 119 String lang = request.getLanguage(); 120 String country = request.getCountry(); 121 String variant = request.getVariant(); 122 if (mNativeSynth.setLanguage(lang, country, variant) != TextToSpeech.SUCCESS) { 123 Log.e(TAG, "setLanguage(" + lang + "," + country + "," + variant + ") failed"); 124 callback.error(); 125 return; 126 } 127 128 // Set speech rate 129 int speechRate = request.getSpeechRate(); 130 if (mNativeSynth.setSpeechRate(speechRate) != TextToSpeech.SUCCESS) { 131 Log.e(TAG, "setSpeechRate(" + speechRate + ") failed"); 132 callback.error(); 133 return; 134 } 135 136 // Set speech 137 int pitch = request.getPitch(); 138 if (mNativeSynth.setPitch(pitch) != TextToSpeech.SUCCESS) { 139 Log.e(TAG, "setPitch(" + pitch + ") failed"); 140 callback.error(); 141 return; 142 } 143 144 // Synthesize 145 if (mNativeSynth.speak(request, callback) != TextToSpeech.SUCCESS) { 146 callback.error(); 147 return; 148 } 149 } 150 151 @Override 152 protected void onStop() { 153 if (DBG) Log.d(TAG, "onStop()"); 154 if (mNativeSynth == null) return; 155 mNativeSynth.stop(); 156 } 157 158} 159