Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b73867a authored by Przemyslaw Szczepaniak's avatar Przemyslaw Szczepaniak
Browse files

Add UtteranceProgressListener#onStop callback

New UtteranceProgressListener callback that allows
to detect a call to TextToSpeech#stop() (or QUEUE_FLUSH usage)
from the same client, or a QUEUE_DESTROY usage from any other
client (Talkback uses it to preempt other users of TextToSpeech
queue). This change is required for seamless Books read aloud
feature+Talkback usage.

+ Fixes for broken tests/TtsTests

Bug: 17901521

Change-Id: I30d2f297bb7c8d05cbeb16f63e85c1be0cca5c84
parent ae13230b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27752,6 +27752,7 @@ package android.speech.tts {
    method public abstract deprecated void onError(java.lang.String);
    method public void onError(java.lang.String, int);
    method public abstract void onStart(java.lang.String);
    method public void onStop(java.lang.String, boolean);
  }
  public class Voice implements android.os.Parcelable {
+1 −1
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@ oneway interface ITextToSpeechCallback {
     *
     * @param utteranceId Unique id identifying synthesis request.
     */
    void onStop(String utteranceId);
    void onStop(String utteranceId, boolean isStarted);

    /**
     * Tells the client that the synthesis has failed.
+2 −2
Original line number Diff line number Diff line
@@ -2066,10 +2066,10 @@ public class TextToSpeech {
        private boolean mEstablished;

        private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
            public void onStop(String utteranceId) throws RemoteException {
            public void onStop(String utteranceId, boolean isStarted) throws RemoteException {
                UtteranceProgressListener listener = mUtteranceProgressListener;
                if (listener != null) {
                    listener.onDone(utteranceId);
                    listener.onStop(utteranceId, isStarted);
                }
            };

+68 −11
Original line number Diff line number Diff line
@@ -455,10 +455,37 @@ public abstract class TextToSpeechService extends Service {
    private class SynthHandler extends Handler {
        private SpeechItem mCurrentSpeechItem = null;

        private ArrayList<Object> mFlushedObjects = new ArrayList<Object>();
        private boolean mFlushAll;

        public SynthHandler(Looper looper) {
            super(looper);
        }

        private void startFlushingSpeechItems(Object callerIdentity) {
            synchronized (mFlushedObjects) {
                if (callerIdentity == null) {
                    mFlushAll = true;
                } else {
                    mFlushedObjects.add(callerIdentity);
                }
            }
        }
        private void endFlushingSpeechItems(Object callerIdentity) {
            synchronized (mFlushedObjects) {
                if (callerIdentity == null) {
                    mFlushAll = false;
                } else {
                    mFlushedObjects.remove(callerIdentity);
                }
            }
        }
        private boolean isFlushed(SpeechItem speechItem) {
            synchronized (mFlushedObjects) {
                return mFlushAll || mFlushedObjects.contains(speechItem.getCallerIdentity());
            }
        }

        private synchronized SpeechItem getCurrentSpeechItem() {
            return mCurrentSpeechItem;
        }
@@ -522,10 +549,14 @@ public abstract class TextToSpeechService extends Service {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    if (isFlushed(speechItem)) {
                        speechItem.stop();
                    } else {
                        setCurrentSpeechItem(speechItem);
                        speechItem.play();
                        setCurrentSpeechItem(null);
                    }
                }
            };
            Message msg = Message.obtain(this, runnable);

@@ -552,12 +583,14 @@ public abstract class TextToSpeechService extends Service {
         *
         * Called on a service binder thread.
         */
        public int stopForApp(Object callerIdentity) {
        public int stopForApp(final Object callerIdentity) {
            if (callerIdentity == null) {
                return TextToSpeech.ERROR;
            }

            removeCallbacksAndMessages(callerIdentity);
            // Flush pending messages from callerIdentity
            startFlushingSpeechItems(callerIdentity);

            // This stops writing data to the file / or publishing
            // items to the audio playback handler.
            //
@@ -573,20 +606,39 @@ public abstract class TextToSpeechService extends Service {
            // Remove any enqueued audio too.
            mAudioPlaybackHandler.stopForApp(callerIdentity);

            // Stop flushing pending messages
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    endFlushingSpeechItems(callerIdentity);
                }
            };
            sendMessage(Message.obtain(this, runnable));
            return TextToSpeech.SUCCESS;
        }

        public int stopAll() {
            // Order to flush pending messages
            startFlushingSpeechItems(null);

            // Stop the current speech item unconditionally .
            SpeechItem current = setCurrentSpeechItem(null);
            if (current != null) {
                current.stop();
            }
            // Remove all other items from the queue.
            removeCallbacksAndMessages(null);
            // Remove all pending playback as well.
            mAudioPlaybackHandler.stop();

            // Message to stop flushing pending messages
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    endFlushingSpeechItems(null);
                }
            };
            sendMessage(Message.obtain(this, runnable));


            return TextToSpeech.SUCCESS;
        }
    }
@@ -698,7 +750,6 @@ public abstract class TextToSpeechService extends Service {
            return mCallerIdentity;
        }


        public int getCallerUid() {
            return mCallerUid;
        }
@@ -752,6 +803,10 @@ public abstract class TextToSpeechService extends Service {
        protected synchronized boolean isStopped() {
             return mStopped;
        }

        protected synchronized boolean isStarted() {
            return mStarted;
       }
    }

    /**
@@ -777,7 +832,7 @@ public abstract class TextToSpeechService extends Service {
        public void dispatchOnStop() {
            final String utteranceId = getUtteranceId();
            if (utteranceId != null) {
                mCallbacks.dispatchOnStop(getCallerIdentity(), utteranceId);
                mCallbacks.dispatchOnStop(getCallerIdentity(), utteranceId, isStarted());
            }
        }

@@ -940,6 +995,8 @@ public abstract class TextToSpeechService extends Service {
                // turn implies that synthesis would not have started.
                synthesisCallback.stop();
                TextToSpeechService.this.onStop();
            } else {
                dispatchOnStop();
            }
        }

@@ -1345,11 +1402,11 @@ public abstract class TextToSpeechService extends Service {
            }
        }

        public void dispatchOnStop(Object callerIdentity, String utteranceId) {
        public void dispatchOnStop(Object callerIdentity, String utteranceId, boolean started) {
            ITextToSpeechCallback cb = getCallbackFor(callerIdentity);
            if (cb == null) return;
            try {
                cb.onStop(utteranceId);
                cb.onStop(utteranceId, started);
            } catch (RemoteException e) {
                Log.e(TAG, "Callback onStop failed: " + e);
            }
+19 −0
Original line number Diff line number Diff line
@@ -59,6 +59,20 @@ public abstract class UtteranceProgressListener {
        onError(utteranceId);
    }

    /**
     * Called when an utterance has been stopped while in progress or flushed from the
     * synthesis queue. This can happen if client calls {@link TextToSpeech#stop()}
     * or use {@link TextToSpeech#QUEUE_FLUSH} as an argument in
     * {@link TextToSpeech#speak} or {@link TextToSpeech#synthesizeToFile} methods.
     *
     * @param utteranceId the utterance ID of the utterance.
     * @param isStarted If true, then utterance was interrupted while being synthesized
     *        and it's output is incomplete. If it's false, then utterance was flushed
     *        before the synthesis started.
     */
    public void onStop(String utteranceId, boolean isStarted) {
    }

    /**
     * Wraps an old deprecated OnUtteranceCompletedListener with a shiny new
     * progress listener.
@@ -83,6 +97,11 @@ public abstract class UtteranceProgressListener {
                // Left unimplemented, has no equivalent in the old
                // API.
            }

            @Override
            public void onStop(String utteranceId, boolean isStarted) {
                listener.onUtteranceCompleted(utteranceId);
            }
        };
    }
}
Loading