TtsEngines.java revision 0e20fe5bab7dc3aff488d133961acfe0239f5240
1/* 2 * Copyright (C) 2011 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 android.speech.tts; 17 18import android.content.Context; 19import android.content.Intent; 20import android.content.pm.ApplicationInfo; 21import android.content.pm.PackageManager; 22import android.content.pm.ResolveInfo; 23import android.content.pm.ServiceInfo; 24import android.provider.Settings; 25import android.speech.tts.TextToSpeech.Engine; 26import android.speech.tts.TextToSpeech.EngineInfo; 27import android.text.TextUtils; 28 29import java.util.ArrayList; 30import java.util.Collections; 31import java.util.Comparator; 32import java.util.List; 33 34/** 35 * Support class for querying the list of available engines 36 * on the device and deciding which one to use etc. 37 * 38 * Comments in this class the use the shorthand "system engines" for engines that 39 * are a part of the system image. 40 * 41 * @hide 42 */ 43public class TtsEngines { 44 private final Context mContext; 45 46 public TtsEngines(Context ctx) { 47 mContext = ctx; 48 } 49 50 /** 51 * @return the default TTS engine. If the user has set a default, and the engine 52 * is available on the device, the default is returned. Otherwise, 53 * the highest ranked engine is returned as per {@link EngineInfoComparator}. 54 */ 55 public String getDefaultEngine() { 56 String engine = Settings.Secure.getString(mContext.getContentResolver(), 57 Settings.Secure.TTS_DEFAULT_SYNTH); 58 return isEngineInstalled(engine) ? engine : getHighestRankedEngineName(); 59 } 60 61 /** 62 * @return the package name of the highest ranked system engine, {@code null} 63 * if no TTS engines were present in the system image. 64 */ 65 public String getHighestRankedEngineName() { 66 final List<EngineInfo> engines = getEngines(); 67 68 if (engines.size() > 0 && engines.get(0).system) { 69 return engines.get(0).name; 70 } 71 72 return null; 73 } 74 75 /** 76 * Returns the engine info for a given engine name. Note that engines are 77 * identified by their package name. 78 */ 79 public EngineInfo getEngineInfo(String packageName) { 80 PackageManager pm = mContext.getPackageManager(); 81 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE); 82 intent.setPackage(packageName); 83 List<ResolveInfo> resolveInfos = pm.queryIntentServices(intent, 84 PackageManager.MATCH_DEFAULT_ONLY); 85 // Note that the current API allows only one engine per 86 // package name. Since the "engine name" is the same as 87 // the package name. 88 if (resolveInfos != null && resolveInfos.size() == 1) { 89 return getEngineInfo(resolveInfos.get(0), pm); 90 } 91 92 return null; 93 } 94 95 /** 96 * Gets a list of all installed TTS engines. 97 * 98 * @return A list of engine info objects. The list can be empty, but never {@code null}. 99 */ 100 public List<EngineInfo> getEngines() { 101 PackageManager pm = mContext.getPackageManager(); 102 Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE); 103 List<ResolveInfo> resolveInfos = 104 pm.queryIntentServices(intent, PackageManager.MATCH_DEFAULT_ONLY); 105 if (resolveInfos == null) return Collections.emptyList(); 106 107 List<EngineInfo> engines = new ArrayList<EngineInfo>(resolveInfos.size()); 108 109 for (ResolveInfo resolveInfo : resolveInfos) { 110 EngineInfo engine = getEngineInfo(resolveInfo, pm); 111 if (engine != null) { 112 engines.add(engine); 113 } 114 } 115 Collections.sort(engines, EngineInfoComparator.INSTANCE); 116 117 return engines; 118 } 119 120 /** 121 * Checks whether a given engine is enabled or not. Note that all system 122 * engines are enabled by default. 123 */ 124 public boolean isEngineEnabled(String engine) { 125 // System engines are enabled by default always. 126 EngineInfo info = getEngineInfo(engine); 127 if (info == null) { 128 // The engine is not installed, and therefore cannot 129 // be enabled. 130 return false; 131 } 132 133 if (info.system) { 134 // All system engines are enabled by default. 135 return true; 136 } 137 138 for (String enabled : getUserEnabledEngines()) { 139 if (engine.equals(enabled)) { 140 return true; 141 } 142 } 143 return false; 144 } 145 146 private boolean isSystemEngine(ServiceInfo info) { 147 final ApplicationInfo appInfo = info.applicationInfo; 148 return appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; 149 } 150 151 /** 152 * @return true if a given engine is installed on the system. Useful to deal 153 * with cases where an engine has been uninstalled by the user or removed 154 * for any other reason. 155 */ 156 private boolean isEngineInstalled(String engine) { 157 if (engine == null) { 158 return false; 159 } 160 161 for (EngineInfo info : getEngines()) { 162 if (engine.equals(info.name)) { 163 return true; 164 } 165 } 166 167 return false; 168 } 169 170 private EngineInfo getEngineInfo(ResolveInfo resolve, PackageManager pm) { 171 ServiceInfo service = resolve.serviceInfo; 172 if (service != null) { 173 EngineInfo engine = new EngineInfo(); 174 // Using just the package name isn't great, since it disallows having 175 // multiple engines in the same package, but that's what the existing API does. 176 engine.name = service.packageName; 177 CharSequence label = service.loadLabel(pm); 178 engine.label = TextUtils.isEmpty(label) ? engine.name : label.toString(); 179 engine.icon = service.getIconResource(); 180 engine.priority = resolve.priority; 181 engine.system = isSystemEngine(service); 182 return engine; 183 } 184 185 return null; 186 } 187 188 // Note that in addition to this list, all engines that are a part 189 // of the system are enabled by default. 190 private String[] getUserEnabledEngines() { 191 String str = Settings.Secure.getString(mContext.getContentResolver(), 192 Settings.Secure.TTS_ENABLED_PLUGINS); 193 if (TextUtils.isEmpty(str)) { 194 return new String[0]; 195 } 196 return str.split(" "); 197 } 198 199 private static class EngineInfoComparator implements Comparator<EngineInfo> { 200 private EngineInfoComparator() { } 201 202 static EngineInfoComparator INSTANCE = new EngineInfoComparator(); 203 204 /** 205 * Engines that are a part of the system image are always lesser 206 * than those that are not. Within system engines / non system engines 207 * the engines are sorted in order of their declared priority. 208 */ 209 @Override 210 public int compare(EngineInfo lhs, EngineInfo rhs) { 211 if (lhs.system && !rhs.system) { 212 return -1; 213 } else if (rhs.system && !lhs.system) { 214 return 1; 215 } else { 216 // Either both system engines, or both non system 217 // engines. 218 // 219 // Note, this isn't a typo. Higher priority numbers imply 220 // higher priority, but are "lower" in the sort order. 221 return rhs.priority - lhs.priority; 222 } 223 } 224 } 225 226} 227