Skip to content

Commit

Permalink
Merge pull request #6146 from robolectric/piper_350776217
Browse files Browse the repository at this point in the history
Fix how the OnInitListener is invoked in ShadowTextToSpeech
  • Loading branch information
hoisie committed Jan 16, 2021
2 parents 232c4ce + 1d93497 commit ba1331d
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

import android.app.Activity;
import android.os.Bundle;
import android.os.Looper;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.Engine;
import android.speech.tts.UtteranceProgressListener;
Expand All @@ -19,10 +20,12 @@
import java.io.File;
import java.util.HashMap;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.Shadows;
import org.robolectric.annotation.Config;

@RunWith(AndroidJUnit4.class)
Expand All @@ -41,6 +44,26 @@ public void shouldNotBeNull() {
assertThat(shadowOf(textToSpeech)).isNotNull();
}

@Test
public void onInitListener_success_getsCalledAsynchronously() {
AtomicReference<Integer> onInitCalled = new AtomicReference<>();
TextToSpeech.OnInitListener listener = onInitCalled::set;
TextToSpeech textToSpeech = new TextToSpeech(activity, listener);
assertThat(textToSpeech).isNotNull();
Shadows.shadowOf(Looper.getMainLooper()).idle();
assertThat(onInitCalled.get()).isEqualTo(TextToSpeech.SUCCESS);
}

@Test
public void onInitListener_error_getsCalledSynchronously() {
AtomicReference<Integer> onInitCalled = new AtomicReference<>();
ShadowTextToSpeech.setOnInitStatus(TextToSpeech.ERROR);
TextToSpeech.OnInitListener listener = onInitCalled::set;
TextToSpeech textToSpeech = new TextToSpeech(activity, listener);
assertThat(textToSpeech).isNotNull();
assertThat(onInitCalled.get()).isEqualTo(TextToSpeech.ERROR);
}

@Test
public void getContext_shouldReturnContext() {
TextToSpeech textToSpeech = new TextToSpeech(activity, result -> {});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
import org.robolectric.annotation.Resetter;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.util.ReflectionHelpers;
import org.robolectric.util.ReflectionHelpers.ClassParameter;

@Implements(TextToSpeech.class)
public class ShadowTextToSpeech {

private static final Set<Locale> languageAvailabilities = new HashSet<>();
private static final Set<Voice> voices = new HashSet<>();
private static TextToSpeech lastTextToSpeechInstance;
private static int onInitStatus = TextToSpeech.SUCCESS;

@RealObject private TextToSpeech tts;

Expand All @@ -49,10 +51,45 @@ public class ShadowTextToSpeech {
private final List<String> spokenTextList = new ArrayList<>();

@Implementation
protected void __constructor__(Context context, TextToSpeech.OnInitListener listener) {
protected void __constructor__(
Context context,
TextToSpeech.OnInitListener listener,
String engine,
String packageName,
boolean useFallback) {
this.context = context;
this.listener = listener;
lastTextToSpeechInstance = tts;
Shadow.invokeConstructor(
TextToSpeech.class,
tts,
ClassParameter.from(Context.class, context),
ClassParameter.from(TextToSpeech.OnInitListener.class, listener),
ClassParameter.from(String.class, engine),
ClassParameter.from(String.class, packageName),
ClassParameter.from(boolean.class, useFallback));
}

@Implementation
protected int initTts() {
// Attempt to be model real Android code, where success callbacks occur asynchronously, but
// error callbacks occur immediately.
if (listener != null) {
if (onInitStatus == TextToSpeech.SUCCESS) {
new Handler(Looper.getMainLooper()).post(() -> listener.onInit(onInitStatus));
} else {
listener.onInit(onInitStatus);
}
}
return onInitStatus;
}

/**
* Sets the code used by the {@link android.speech.tts.TextToSpeech.OnInitListener} callback
* during initialization. This can test cases where {@link TextToSpeech.ERROR} is used.
*/
public static void setOnInitStatus(int status) {
onInitStatus = status;
}

/**
Expand Down Expand Up @@ -163,7 +200,7 @@ protected Set<Voice> getVoices() {
return voices;
}

private UtteranceProgressListener getUtteranceProgressListener() {
public UtteranceProgressListener getUtteranceProgressListener() {
return ReflectionHelpers.getField(tts, "mUtteranceProgressListener");
}

Expand Down Expand Up @@ -245,5 +282,6 @@ public static void reset() {
languageAvailabilities.clear();
voices.clear();
lastTextToSpeechInstance = null;
onInitStatus = TextToSpeech.SUCCESS;
}
}

0 comments on commit ba1331d

Please sign in to comment.