diff options
author | Narayan Kamath <narayan@google.com> | 2011-11-29 17:02:06 +0000 |
---|---|---|
committer | Narayan Kamath <narayan@google.com> | 2011-11-30 10:42:03 +0000 |
commit | 492b7f0d51f53164aa6eb974cd7ab6a7889af677 (patch) | |
tree | 18f697ad229f9a1d9327cce34c1aa76ff78de17f | |
parent | 9a8246c8d1ea324b6704bf4fe0b77ade1c2f3639 (diff) | |
download | frameworks_base-492b7f0d51f53164aa6eb974cd7ab6a7889af677.zip frameworks_base-492b7f0d51f53164aa6eb974cd7ab6a7889af677.tar.gz frameworks_base-492b7f0d51f53164aa6eb974cd7ab6a7889af677.tar.bz2 |
Allow multiple TextToSpeech instances per calling app.
We now use an IBinder object as an identity token of the
caller instead of Context#getPackageName.
bug:5680696
Change-Id: I1ca29e7161f709d2a85218206f3f117dfa620282
11 files changed, 167 insertions, 131 deletions
diff --git a/core/java/android/speech/tts/AudioMessageParams.java b/core/java/android/speech/tts/AudioMessageParams.java index 29b4367..a2248a2 100644 --- a/core/java/android/speech/tts/AudioMessageParams.java +++ b/core/java/android/speech/tts/AudioMessageParams.java @@ -21,8 +21,8 @@ class AudioMessageParams extends MessageParams { private final BlockingMediaPlayer mPlayer; AudioMessageParams(UtteranceProgressDispatcher dispatcher, - String callingApp, BlockingMediaPlayer player) { - super(dispatcher, callingApp); + Object callerIdentity, BlockingMediaPlayer player) { + super(dispatcher, callerIdentity); mPlayer = player; } diff --git a/core/java/android/speech/tts/AudioPlaybackHandler.java b/core/java/android/speech/tts/AudioPlaybackHandler.java index fd00dce..d452b8e 100644 --- a/core/java/android/speech/tts/AudioPlaybackHandler.java +++ b/core/java/android/speech/tts/AudioPlaybackHandler.java @@ -110,19 +110,19 @@ class AudioPlaybackHandler { // synchronization). // ----------------------------------------------------- - synchronized public void removePlaybackItems(String callingApp) { - if (DBG_THREADING) Log.d(TAG, "Removing all callback items for : " + callingApp); - removeMessages(callingApp); + synchronized public void removePlaybackItems(Object callerIdentity) { + if (DBG_THREADING) Log.d(TAG, "Removing all callback items for : " + callerIdentity); + removeMessages(callerIdentity); final MessageParams current = getCurrentParams(); - if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) { + if (current != null && (current.getCallerIdentity() == callerIdentity)) { stop(current); } final MessageParams lastSynthesis = mLastSynthesisRequest; if (lastSynthesis != null && lastSynthesis != current && - TextUtils.equals(callingApp, lastSynthesis.getCallingApp())) { + (lastSynthesis.getCallerIdentity() == callerIdentity)) { stop(lastSynthesis); } } @@ -232,7 +232,7 @@ class AudioPlaybackHandler { /* * Remove all messages that originate from a given calling app. */ - synchronized private void removeMessages(String callingApp) { + synchronized private void removeMessages(Object callerIdentity) { Iterator<ListEntry> it = mQueue.iterator(); while (it.hasNext()) { @@ -240,7 +240,7 @@ class AudioPlaybackHandler { // The null check is to prevent us from removing control messages, // such as a shutdown message. if (current.mMessage != null && - callingApp.equals(current.mMessage.getCallingApp())) { + current.mMessage.getCallerIdentity() == callerIdentity) { it.remove(); } } diff --git a/core/java/android/speech/tts/EventLogTags.logtags b/core/java/android/speech/tts/EventLogTags.logtags index 1a9f5fe..f8654ad 100644 --- a/core/java/android/speech/tts/EventLogTags.logtags +++ b/core/java/android/speech/tts/EventLogTags.logtags @@ -2,5 +2,5 @@ option java_package android.speech.tts; -76001 tts_speak_success (engine|3),(caller|3),(length|1),(locale|3),(rate|1),(pitch|1),(engine_latency|2|3),(engine_total|2|3),(audio_latency|2|3) -76002 tts_speak_failure (engine|3),(caller|3),(length|1),(locale|3),(rate|1),(pitch|1) +76001 tts_speak_success (engine|3),(caller_uid|1),(caller_pid|1),(length|1),(locale|3),(rate|1),(pitch|1),(engine_latency|2|3),(engine_total|2|3),(audio_latency|2|3) +76002 tts_speak_failure (engine|3),(caller_uid|1),(caller_pid|1),(length|1),(locale|3),(rate|1),(pitch|1) diff --git a/core/java/android/speech/tts/EventLogger.java b/core/java/android/speech/tts/EventLogger.java index 63b954b..3c93e18 100644 --- a/core/java/android/speech/tts/EventLogger.java +++ b/core/java/android/speech/tts/EventLogger.java @@ -30,8 +30,9 @@ import android.text.TextUtils; */ class EventLogger { private final SynthesisRequest mRequest; - private final String mCallingApp; private final String mServiceApp; + private final int mCallerUid; + private final int mCallerPid; private final long mReceivedTime; private long mPlaybackStartTime = -1; private volatile long mRequestProcessingStartTime = -1; @@ -42,10 +43,10 @@ class EventLogger { private volatile boolean mStopped = false; private boolean mLogWritten = false; - EventLogger(SynthesisRequest request, String callingApp, - String serviceApp) { + EventLogger(SynthesisRequest request, int callerUid, int callerPid, String serviceApp) { mRequest = request; - mCallingApp = callingApp; + mCallerUid = callerUid; + mCallerPid = callerPid; mServiceApp = serviceApp; mReceivedTime = SystemClock.elapsedRealtime(); } @@ -122,7 +123,7 @@ class EventLogger { // onPlaybackStart() should normally always be called if an // error does not occur. if (mError || mPlaybackStartTime == -1 || mEngineCompleteTime == -1) { - EventLogTags.writeTtsSpeakFailure(mServiceApp, mCallingApp, + EventLogTags.writeTtsSpeakFailure(mServiceApp, mCallerUid, mCallerPid, getUtteranceLength(), getLocaleString(), mRequest.getSpeechRate(), mRequest.getPitch()); return; @@ -138,7 +139,7 @@ class EventLogger { final long audioLatency = mPlaybackStartTime - mReceivedTime; final long engineLatency = mEngineStartTime - mRequestProcessingStartTime; final long engineTotal = mEngineCompleteTime - mRequestProcessingStartTime; - EventLogTags.writeTtsSpeakSuccess(mServiceApp, mCallingApp, + EventLogTags.writeTtsSpeakSuccess(mServiceApp, mCallerUid, mCallerPid, getUtteranceLength(), getLocaleString(), mRequest.getSpeechRate(), mRequest.getPitch(), engineLatency, engineTotal, audioLatency); diff --git a/core/java/android/speech/tts/ITextToSpeechService.aidl b/core/java/android/speech/tts/ITextToSpeechService.aidl index 1a8c1fb..ab63187 100644 --- a/core/java/android/speech/tts/ITextToSpeechService.aidl +++ b/core/java/android/speech/tts/ITextToSpeechService.aidl @@ -30,47 +30,47 @@ interface ITextToSpeechService { /** * Tells the engine to synthesize some speech and play it back. * - * @param callingApp The package name of the calling app. Used to connect requests - * callbacks and to clear requests when the calling app is stopping. + * @param callingInstance a binder representing the identity of the calling + * TextToSpeech object. * @param text The text to synthesize. * @param queueMode Determines what to do to requests already in the queue. * @param param Request parameters. */ - int speak(in String callingApp, in String text, in int queueMode, in Bundle params); + int speak(in IBinder callingInstance, in String text, in int queueMode, in Bundle params); /** * Tells the engine to synthesize some speech and write it to a file. * - * @param callingApp The package name of the calling app. Used to connect requests - * callbacks and to clear requests when the calling app is stopping. + * @param callingInstance a binder representing the identity of the calling + * TextToSpeech object. * @param text The text to synthesize. * @param filename The file to write the synthesized audio to. * @param param Request parameters. */ - int synthesizeToFile(in String callingApp, in String text, + int synthesizeToFile(in IBinder callingInstance, in String text, in String filename, in Bundle params); /** * Plays an existing audio resource. * - * @param callingApp The package name of the calling app. Used to connect requests - * callbacks and to clear requests when the calling app is stopping. + * @param callingInstance a binder representing the identity of the calling + * TextToSpeech object. * @param audioUri URI for the audio resource (a file or android.resource URI) * @param queueMode Determines what to do to requests already in the queue. * @param param Request parameters. */ - int playAudio(in String callingApp, in Uri audioUri, in int queueMode, in Bundle params); + int playAudio(in IBinder callingInstance, in Uri audioUri, in int queueMode, in Bundle params); /** * Plays silence. * - * @param callingApp The package name of the calling app. Used to connect requests - * callbacks and to clear requests when the calling app is stopping. + * @param callingInstance a binder representing the identity of the calling + * TextToSpeech object. * @param duration Number of milliseconds of silence to play. * @param queueMode Determines what to do to requests already in the queue. * @param param Request parameters. */ - int playSilence(in String callingApp, in long duration, in int queueMode, in Bundle params); + int playSilence(in IBinder callingInstance, in long duration, in int queueMode, in Bundle params); /** * Checks whether the service is currently playing some audio. @@ -81,10 +81,10 @@ interface ITextToSpeechService { * Interrupts the current utterance (if from the given app) and removes any utterances * in the queue that are from the given app. * - * @param callingApp Package name of the app whose utterances - * should be interrupted and cleared. + * @param callingInstance a binder representing the identity of the calling + * TextToSpeech object. */ - int stop(in String callingApp); + int stop(in IBinder callingInstance); /** * Returns the language, country and variant currently being used by the TTS engine. @@ -150,6 +150,6 @@ interface ITextToSpeechService { * @param callingApp Package name for the app whose utterance the callback will handle. * @param cb The callback. */ - void setCallback(in String callingApp, ITextToSpeechCallback cb); + void setCallback(in IBinder caller, ITextToSpeechCallback cb); } diff --git a/core/java/android/speech/tts/MessageParams.java b/core/java/android/speech/tts/MessageParams.java index de9cc07..f83b793 100644 --- a/core/java/android/speech/tts/MessageParams.java +++ b/core/java/android/speech/tts/MessageParams.java @@ -23,19 +23,19 @@ abstract class MessageParams { static final int TYPE_SILENCE = 3; private final UtteranceProgressDispatcher mDispatcher; - private final String mCallingApp; + private final Object mCallerIdentity; - MessageParams(UtteranceProgressDispatcher dispatcher, String callingApp) { + MessageParams(UtteranceProgressDispatcher dispatcher, Object callerIdentity) { mDispatcher = dispatcher; - mCallingApp = callingApp; + mCallerIdentity = callerIdentity; } UtteranceProgressDispatcher getDispatcher() { return mDispatcher; } - String getCallingApp() { - return mCallingApp; + Object getCallerIdentity() { + return mCallerIdentity; } @Override diff --git a/core/java/android/speech/tts/PlaybackSynthesisCallback.java b/core/java/android/speech/tts/PlaybackSynthesisCallback.java index 91a3452..8634506 100644 --- a/core/java/android/speech/tts/PlaybackSynthesisCallback.java +++ b/core/java/android/speech/tts/PlaybackSynthesisCallback.java @@ -63,18 +63,18 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { private volatile boolean mDone = false; private final UtteranceProgressDispatcher mDispatcher; - private final String mCallingApp; + private final Object mCallerIdentity; private final EventLogger mLogger; PlaybackSynthesisCallback(int streamType, float volume, float pan, AudioPlaybackHandler audioTrackHandler, UtteranceProgressDispatcher dispatcher, - String callingApp, EventLogger logger) { + Object callerIdentity, EventLogger logger) { mStreamType = streamType; mVolume = volume; mPan = pan; mAudioTrackHandler = audioTrackHandler; mDispatcher = dispatcher; - mCallingApp = callingApp; + mCallerIdentity = callerIdentity; mLogger = logger; } @@ -158,7 +158,7 @@ class PlaybackSynthesisCallback extends AbstractSynthesisCallback { } SynthesisMessageParams params = new SynthesisMessageParams( mStreamType, sampleRateInHz, audioFormat, channelCount, mVolume, mPan, - mDispatcher, mCallingApp, mLogger); + mDispatcher, mCallerIdentity, mLogger); mAudioTrackHandler.enqueueSynthesisStart(params); mToken = params; diff --git a/core/java/android/speech/tts/SilenceMessageParams.java b/core/java/android/speech/tts/SilenceMessageParams.java index 9909126..2431808 100644 --- a/core/java/android/speech/tts/SilenceMessageParams.java +++ b/core/java/android/speech/tts/SilenceMessageParams.java @@ -23,8 +23,8 @@ class SilenceMessageParams extends MessageParams { private final long mSilenceDurationMs; SilenceMessageParams(UtteranceProgressDispatcher dispatcher, - String callingApp, long silenceDurationMs) { - super(dispatcher, callingApp); + Object callerIdentity, long silenceDurationMs) { + super(dispatcher, callerIdentity); mSilenceDurationMs = silenceDurationMs; } diff --git a/core/java/android/speech/tts/SynthesisMessageParams.java b/core/java/android/speech/tts/SynthesisMessageParams.java index ed66420..ef73d30 100644 --- a/core/java/android/speech/tts/SynthesisMessageParams.java +++ b/core/java/android/speech/tts/SynthesisMessageParams.java @@ -58,8 +58,8 @@ final class SynthesisMessageParams extends MessageParams { SynthesisMessageParams(int streamType, int sampleRate, int audioFormat, int channelCount, float volume, float pan, UtteranceProgressDispatcher dispatcher, - String callingApp, EventLogger logger) { - super(dispatcher, callingApp); + Object callerIdentity, EventLogger logger) { + super(dispatcher, callerIdentity); mStreamType = streamType; mSampleRateInHz = sampleRate; diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index a220615..cd065ec 100755 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -547,10 +547,6 @@ public class TextToSpeech { initTts(); } - private String getPackageName() { - return mPackageName; - } - private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method) { return runAction(action, errorResult, method, false); } @@ -630,6 +626,10 @@ public class TextToSpeech { } } + private IBinder getCallerIdentity() { + return mServiceConnection.getCallerIdentity(); + } + /** * Releases the resources used by the TextToSpeech engine. * It is good practice for instance to call this method in the onDestroy() method of an Activity @@ -639,8 +639,8 @@ public class TextToSpeech { runActionNoReconnect(new Action<Void>() { @Override public Void run(ITextToSpeechService service) throws RemoteException { - service.setCallback(getPackageName(), null); - service.stop(getPackageName()); + service.setCallback(getCallerIdentity(), null); + service.stop(getCallerIdentity()); mServiceConnection.disconnect(); // Context#unbindService does not result in a call to // ServiceConnection#onServiceDisconnected. As a result, the @@ -800,10 +800,10 @@ public class TextToSpeech { public Integer run(ITextToSpeechService service) throws RemoteException { Uri utteranceUri = mUtterances.get(text); if (utteranceUri != null) { - return service.playAudio(getPackageName(), utteranceUri, queueMode, + return service.playAudio(getCallerIdentity(), utteranceUri, queueMode, getParams(params)); } else { - return service.speak(getPackageName(), text, queueMode, getParams(params)); + return service.speak(getCallerIdentity(), text, queueMode, getParams(params)); } } }, ERROR, "speak"); @@ -836,7 +836,7 @@ public class TextToSpeech { if (earconUri == null) { return ERROR; } - return service.playAudio(getPackageName(), earconUri, queueMode, + return service.playAudio(getCallerIdentity(), earconUri, queueMode, getParams(params)); } }, ERROR, "playEarcon"); @@ -863,7 +863,7 @@ public class TextToSpeech { return runAction(new Action<Integer>() { @Override public Integer run(ITextToSpeechService service) throws RemoteException { - return service.playSilence(getPackageName(), durationInMs, queueMode, + return service.playSilence(getCallerIdentity(), durationInMs, queueMode, getParams(params)); } }, ERROR, "playSilence"); @@ -926,7 +926,7 @@ public class TextToSpeech { return runAction(new Action<Integer>() { @Override public Integer run(ITextToSpeechService service) throws RemoteException { - return service.stop(getPackageName()); + return service.stop(getCallerIdentity()); } }, ERROR, "stop"); } @@ -1091,7 +1091,7 @@ public class TextToSpeech { return runAction(new Action<Integer>() { @Override public Integer run(ITextToSpeechService service) throws RemoteException { - return service.synthesizeToFile(getPackageName(), text, filename, + return service.synthesizeToFile(getCallerIdentity(), text, filename, getParams(params)); } }, ERROR, "synthesizeToFile"); @@ -1275,7 +1275,7 @@ public class TextToSpeech { mServiceConnection = this; mService = ITextToSpeechService.Stub.asInterface(service); try { - mService.setCallback(getPackageName(), mCallback); + mService.setCallback(getCallerIdentity(), mCallback); dispatchOnInit(SUCCESS); } catch (RemoteException re) { Log.e(TAG, "Error connecting to service, setCallback() failed"); @@ -1284,6 +1284,10 @@ public class TextToSpeech { } } + public IBinder getCallerIdentity() { + return mCallback; + } + public void onServiceDisconnected(ComponentName name) { synchronized(mStartLock) { mService = null; diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java index aee678a..2f62d39 100644 --- a/core/java/android/speech/tts/TextToSpeechService.java +++ b/core/java/android/speech/tts/TextToSpeechService.java @@ -18,6 +18,7 @@ package android.speech.tts; import android.app.Service; import android.content.Intent; import android.net.Uri; +import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -272,9 +273,9 @@ public abstract class TextToSpeechService extends Service { return old; } - private synchronized SpeechItem maybeRemoveCurrentSpeechItem(String callingApp) { + private synchronized SpeechItem maybeRemoveCurrentSpeechItem(Object callerIdentity) { if (mCurrentSpeechItem != null && - TextUtils.equals(mCurrentSpeechItem.getCallingApp(), callingApp)) { + mCurrentSpeechItem.getCallerIdentity() == callerIdentity) { SpeechItem current = mCurrentSpeechItem; mCurrentSpeechItem = null; return current; @@ -311,7 +312,7 @@ public abstract class TextToSpeechService extends Service { } if (queueMode == TextToSpeech.QUEUE_FLUSH) { - stopForApp(speechItem.getCallingApp()); + stopForApp(speechItem.getCallerIdentity()); } else if (queueMode == TextToSpeech.QUEUE_DESTROY) { stopAll(); } @@ -328,7 +329,7 @@ public abstract class TextToSpeechService extends Service { // stopForApp(String). // // Note that this string is interned, so the == comparison works. - msg.obj = speechItem.getCallingApp(); + msg.obj = speechItem.getCallerIdentity(); if (sendMessage(msg)) { return TextToSpeech.SUCCESS; } else { @@ -344,12 +345,12 @@ public abstract class TextToSpeechService extends Service { * * Called on a service binder thread. */ - public int stopForApp(String callingApp) { - if (TextUtils.isEmpty(callingApp)) { + public int stopForApp(Object callerIdentity) { + if (callerIdentity == null) { return TextToSpeech.ERROR; } - removeCallbacksAndMessages(callingApp); + removeCallbacksAndMessages(callerIdentity); // This stops writing data to the file / or publishing // items to the audio playback handler. // @@ -357,13 +358,13 @@ public abstract class TextToSpeechService extends Service { // belongs to the callingApp, else the item will be "orphaned" and // not stopped correctly if a stop request comes along for the item // from the app it belongs to. - SpeechItem current = maybeRemoveCurrentSpeechItem(callingApp); + SpeechItem current = maybeRemoveCurrentSpeechItem(callerIdentity); if (current != null) { current.stop(); } // Remove any enqueued audio too. - mAudioPlaybackHandler.removePlaybackItems(callingApp); + mAudioPlaybackHandler.removePlaybackItems(callerIdentity); return TextToSpeech.SUCCESS; } @@ -393,18 +394,22 @@ public abstract class TextToSpeechService extends Service { * An item in the synth thread queue. */ private abstract class SpeechItem implements UtteranceProgressDispatcher { - private final String mCallingApp; + private final Object mCallerIdentity; protected final Bundle mParams; + private final int mCallerUid; + private final int mCallerPid; private boolean mStarted = false; private boolean mStopped = false; - public SpeechItem(String callingApp, Bundle params) { - mCallingApp = callingApp; + public SpeechItem(Object caller, int callerUid, int callerPid, Bundle params) { + mCallerIdentity = caller; mParams = params; + mCallerUid = callerUid; + mCallerPid = callerPid; } - public String getCallingApp() { - return mCallingApp; + public Object getCallerIdentity() { + return mCallerIdentity; } /** @@ -451,7 +456,7 @@ public abstract class TextToSpeechService extends Service { public void dispatchOnDone() { final String utteranceId = getUtteranceId(); if (utteranceId != null) { - mCallbacks.dispatchOnDone(getCallingApp(), utteranceId); + mCallbacks.dispatchOnDone(getCallerIdentity(), utteranceId); } } @@ -459,7 +464,7 @@ public abstract class TextToSpeechService extends Service { public void dispatchOnStart() { final String utteranceId = getUtteranceId(); if (utteranceId != null) { - mCallbacks.dispatchOnStart(getCallingApp(), utteranceId); + mCallbacks.dispatchOnStart(getCallerIdentity(), utteranceId); } } @@ -467,10 +472,18 @@ public abstract class TextToSpeechService extends Service { public void dispatchOnError() { final String utteranceId = getUtteranceId(); if (utteranceId != null) { - mCallbacks.dispatchOnError(getCallingApp(), utteranceId); + mCallbacks.dispatchOnError(getCallerIdentity(), utteranceId); } } + public int getCallerUid() { + return mCallerUid; + } + + public int getCallerPid() { + return mCallerPid; + } + protected synchronized boolean isStopped() { return mStopped; } @@ -518,13 +531,15 @@ public abstract class TextToSpeechService extends Service { private AbstractSynthesisCallback mSynthesisCallback; private final EventLogger mEventLogger; - public SynthesisSpeechItem(String callingApp, Bundle params, String text) { - super(callingApp, params); + public SynthesisSpeechItem(Object callerIdentity, int callerUid, int callerPid, + Bundle params, String text) { + super(callerIdentity, callerUid, callerPid, params); mText = text; mSynthesisRequest = new SynthesisRequest(mText, mParams); mDefaultLocale = getSettingsLocale(); setRequestParams(mSynthesisRequest); - mEventLogger = new EventLogger(mSynthesisRequest, getCallingApp(), mPackageName); + mEventLogger = new EventLogger(mSynthesisRequest, callerUid, callerPid, + mPackageName); } public String getText() { @@ -563,7 +578,7 @@ public abstract class TextToSpeechService extends Service { protected AbstractSynthesisCallback createSynthesisCallback() { return new PlaybackSynthesisCallback(getStreamType(), getVolume(), getPan(), - mAudioPlaybackHandler, this, getCallingApp(), mEventLogger); + mAudioPlaybackHandler, this, getCallerIdentity(), mEventLogger); } private void setRequestParams(SynthesisRequest request) { @@ -618,9 +633,10 @@ public abstract class TextToSpeechService extends Service { private class SynthesisToFileSpeechItem extends SynthesisSpeechItem { private final File mFile; - public SynthesisToFileSpeechItem(String callingApp, Bundle params, String text, + public SynthesisToFileSpeechItem(Object callerIdentity, int callerUid, int callerPid, + Bundle params, String text, File file) { - super(callingApp, params, text); + super(callerIdentity, callerUid, callerPid, params, text); mFile = file; } @@ -682,8 +698,9 @@ public abstract class TextToSpeechService extends Service { private final BlockingMediaPlayer mPlayer; private AudioMessageParams mToken; - public AudioSpeechItem(String callingApp, Bundle params, Uri uri) { - super(callingApp, params); + public AudioSpeechItem(Object callerIdentity, int callerUid, int callerPid, + Bundle params, Uri uri) { + super(callerIdentity, callerUid, callerPid, params); mPlayer = new BlockingMediaPlayer(TextToSpeechService.this, uri, getStreamType()); } @@ -694,7 +711,7 @@ public abstract class TextToSpeechService extends Service { @Override protected int playImpl() { - mToken = new AudioMessageParams(this, getCallingApp(), mPlayer); + mToken = new AudioMessageParams(this, getCallerIdentity(), mPlayer); mAudioPlaybackHandler.enqueueAudio(mToken); return TextToSpeech.SUCCESS; } @@ -709,8 +726,9 @@ public abstract class TextToSpeechService extends Service { private final long mDuration; private SilenceMessageParams mToken; - public SilenceSpeechItem(String callingApp, Bundle params, long duration) { - super(callingApp, params); + public SilenceSpeechItem(Object callerIdentity, int callerUid, int callerPid, + Bundle params, long duration) { + super(callerIdentity, callerUid, callerPid, params); mDuration = duration; } @@ -721,7 +739,7 @@ public abstract class TextToSpeechService extends Service { @Override protected int playImpl() { - mToken = new SilenceMessageParams(this, getCallingApp(), mDuration); + mToken = new SilenceMessageParams(this, getCallerIdentity(), mDuration); mAudioPlaybackHandler.enqueueSilence(mToken); return TextToSpeech.SUCCESS; } @@ -747,58 +765,67 @@ public abstract class TextToSpeechService extends Service { // NOTE: All calls that are passed in a calling app are interned so that // they can be used as message objects (which are tested for equality using ==). private final ITextToSpeechService.Stub mBinder = new ITextToSpeechService.Stub() { - - public int speak(String callingApp, String text, int queueMode, Bundle params) { - if (!checkNonNull(callingApp, text, params)) { + @Override + public int speak(IBinder caller, String text, int queueMode, Bundle params) { + if (!checkNonNull(caller, text, params)) { return TextToSpeech.ERROR; } - SpeechItem item = new SynthesisSpeechItem(intern(callingApp), params, text); + SpeechItem item = new SynthesisSpeechItem(caller, + Binder.getCallingUid(), Binder.getCallingPid(), params, text); return mSynthHandler.enqueueSpeechItem(queueMode, item); } - public int synthesizeToFile(String callingApp, String text, String filename, + @Override + public int synthesizeToFile(IBinder caller, String text, String filename, Bundle params) { - if (!checkNonNull(callingApp, text, filename, params)) { + if (!checkNonNull(caller, text, filename, params)) { return TextToSpeech.ERROR; } File file = new File(filename); - SpeechItem item = new SynthesisToFileSpeechItem(intern(callingApp), - params, text, file); + SpeechItem item = new SynthesisToFileSpeechItem(caller, Binder.getCallingUid(), + Binder.getCallingPid(), params, text, file); return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item); } - public int playAudio(String callingApp, Uri audioUri, int queueMode, Bundle params) { - if (!checkNonNull(callingApp, audioUri, params)) { + @Override + public int playAudio(IBinder caller, Uri audioUri, int queueMode, Bundle params) { + if (!checkNonNull(caller, audioUri, params)) { return TextToSpeech.ERROR; } - SpeechItem item = new AudioSpeechItem(intern(callingApp), params, audioUri); + SpeechItem item = new AudioSpeechItem(caller, + Binder.getCallingUid(), Binder.getCallingPid(), params, audioUri); return mSynthHandler.enqueueSpeechItem(queueMode, item); } - public int playSilence(String callingApp, long duration, int queueMode, Bundle params) { - if (!checkNonNull(callingApp, params)) { + @Override + public int playSilence(IBinder caller, long duration, int queueMode, Bundle params) { + if (!checkNonNull(caller, params)) { return TextToSpeech.ERROR; } - SpeechItem item = new SilenceSpeechItem(intern(callingApp), params, duration); + SpeechItem item = new SilenceSpeechItem(caller, + Binder.getCallingUid(), Binder.getCallingPid(), params, duration); return mSynthHandler.enqueueSpeechItem(queueMode, item); } + @Override public boolean isSpeaking() { return mSynthHandler.isSpeaking() || mAudioPlaybackHandler.isSpeaking(); } - public int stop(String callingApp) { - if (!checkNonNull(callingApp)) { + @Override + public int stop(IBinder caller) { + if (!checkNonNull(caller)) { return TextToSpeech.ERROR; } - return mSynthHandler.stopForApp(intern(callingApp)); + return mSynthHandler.stopForApp(caller); } + @Override public String[] getLanguage() { return onGetLanguage(); } @@ -807,6 +834,7 @@ public abstract class TextToSpeechService extends Service { * If defaults are enforced, then no language is "available" except * perhaps the default language selected by the user. */ + @Override public int isLanguageAvailable(String lang, String country, String variant) { if (!checkNonNull(lang)) { return TextToSpeech.ERROR; @@ -815,6 +843,7 @@ public abstract class TextToSpeechService extends Service { return onIsLanguageAvailable(lang, country, variant); } + @Override public String[] getFeaturesForLanguage(String lang, String country, String variant) { Set<String> features = onGetFeaturesForLanguage(lang, country, variant); String[] featuresArray = null; @@ -831,6 +860,7 @@ public abstract class TextToSpeechService extends Service { * There is no point loading a non default language if defaults * are enforced. */ + @Override public int loadLanguage(String lang, String country, String variant) { if (!checkNonNull(lang)) { return TextToSpeech.ERROR; @@ -839,13 +869,14 @@ public abstract class TextToSpeechService extends Service { return onLoadLanguage(lang, country, variant); } - public void setCallback(String packageName, ITextToSpeechCallback cb) { + @Override + public void setCallback(IBinder caller, ITextToSpeechCallback cb) { // Note that passing in a null callback is a valid use case. - if (!checkNonNull(packageName)) { + if (!checkNonNull(caller)) { return; } - mCallbacks.setCallback(packageName, cb); + mCallbacks.setCallback(caller, cb); } private String intern(String in) { @@ -862,18 +893,17 @@ public abstract class TextToSpeechService extends Service { }; private class CallbackMap extends RemoteCallbackList<ITextToSpeechCallback> { + private final HashMap<IBinder, ITextToSpeechCallback> mCallerToCallback + = new HashMap<IBinder, ITextToSpeechCallback>(); - private final HashMap<String, ITextToSpeechCallback> mAppToCallback - = new HashMap<String, ITextToSpeechCallback>(); - - public void setCallback(String packageName, ITextToSpeechCallback cb) { - synchronized (mAppToCallback) { + public void setCallback(IBinder caller, ITextToSpeechCallback cb) { + synchronized (mCallerToCallback) { ITextToSpeechCallback old; if (cb != null) { - register(cb, packageName); - old = mAppToCallback.put(packageName, cb); + register(cb, caller); + old = mCallerToCallback.put(caller, cb); } else { - old = mAppToCallback.remove(packageName); + old = mCallerToCallback.remove(caller); } if (old != null && old != cb) { unregister(old); @@ -881,8 +911,8 @@ public abstract class TextToSpeechService extends Service { } } - public void dispatchOnDone(String packageName, String utteranceId) { - ITextToSpeechCallback cb = getCallbackFor(packageName); + public void dispatchOnDone(Object callerIdentity, String utteranceId) { + ITextToSpeechCallback cb = getCallbackFor(callerIdentity); if (cb == null) return; try { cb.onDone(utteranceId); @@ -891,8 +921,8 @@ public abstract class TextToSpeechService extends Service { } } - public void dispatchOnStart(String packageName, String utteranceId) { - ITextToSpeechCallback cb = getCallbackFor(packageName); + public void dispatchOnStart(Object callerIdentity, String utteranceId) { + ITextToSpeechCallback cb = getCallbackFor(callerIdentity); if (cb == null) return; try { cb.onStart(utteranceId); @@ -902,8 +932,8 @@ public abstract class TextToSpeechService extends Service { } - public void dispatchOnError(String packageName, String utteranceId) { - ITextToSpeechCallback cb = getCallbackFor(packageName); + public void dispatchOnError(Object callerIdentity, String utteranceId) { + ITextToSpeechCallback cb = getCallbackFor(callerIdentity); if (cb == null) return; try { cb.onError(utteranceId); @@ -914,25 +944,26 @@ public abstract class TextToSpeechService extends Service { @Override public void onCallbackDied(ITextToSpeechCallback callback, Object cookie) { - String packageName = (String) cookie; - synchronized (mAppToCallback) { - mAppToCallback.remove(packageName); + IBinder caller = (IBinder) cookie; + synchronized (mCallerToCallback) { + mCallerToCallback.remove(caller); } - mSynthHandler.stopForApp(packageName); + mSynthHandler.stopForApp(caller); } @Override public void kill() { - synchronized (mAppToCallback) { - mAppToCallback.clear(); + synchronized (mCallerToCallback) { + mCallerToCallback.clear(); super.kill(); } } - private ITextToSpeechCallback getCallbackFor(String packageName) { + private ITextToSpeechCallback getCallbackFor(Object caller) { ITextToSpeechCallback cb; - synchronized (mAppToCallback) { - cb = mAppToCallback.get(packageName); + IBinder asBinder = (IBinder) caller; + synchronized (mCallerToCallback) { + cb = mCallerToCallback.get(asBinder); } return cb; |