Fix race condition with calling stop() before run()

The code assumed that when stop() is called before run(), it's not
neccessary to signal mNotFull, but in rare cases the synthesizer may
already have filled the buffer before run() is called.

Test: manual

Bug: 70887227
Change-Id: I83117f3541d37830b344bc9eda34e1f380b58e76
(cherry picked from commit 32011ea4f144b46b5ab64577465983caf6303f2d)
diff --git a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
index 704a1da..2ed618b 100644
--- a/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/SynthesisPlaybackQueueItem.java
@@ -15,17 +15,17 @@
  */
 package android.speech.tts;
 
+import android.media.AudioTrack;
 import android.speech.tts.TextToSpeechService.AudioOutputParams;
 import android.speech.tts.TextToSpeechService.UtteranceProgressDispatcher;
-import android.media.AudioTrack;
 import android.util.Log;
 
 import java.util.LinkedList;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.Condition;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.ConcurrentLinkedQueue;
 
 /**
  * Manages the playback of a list of byte arrays representing audio data that are queued by the
@@ -157,9 +157,16 @@
             mStopped = true;
             mStatusCode = statusCode;
 
+            // Wake up the synthesis thread if it was waiting on put(). Its
+            // buffers will no longer be copied since mStopped is true. The
+            // PlaybackSynthesisCallback that this synthesis corresponds to
+            // would also have been stopped, and so all calls to
+            // Callback.onDataAvailable( ) will return errors too.
+            mNotFull.signal();
+
             if (mRunState.getAndSet(STOP_CALLED) == NOT_RUN) {
-                // Dispatch the status code and just finish without signaling
-                // if run() has not even started.
+                // Dispatch the status code and just finish. Signaling audio
+                // playback is not necessary because run() hasn't started.
                 dispatchEndStatus();
                 return;
             }
@@ -168,13 +175,6 @@
             // take() will return null since mStopped was true, and will then
             // break out of the data write loop.
             mReadReady.signal();
-
-            // Wake up the synthesis thread if it was waiting on put(). Its
-            // buffers will no longer be copied since mStopped is true. The
-            // PlaybackSynthesisCallback that this synthesis corresponds to
-            // would also have been stopped, and so all calls to
-            // Callback.onDataAvailable( ) will return errors too.
-            mNotFull.signal();
         } finally {
             mListLock.unlock();
         }