Merge "Retry TTS speaking for a11y shortcut warning dialog" into rvc-dev am: 67c02e6cb0
Change-Id: Id9ecfe73a5a2fae9ae16044459ff9236f6f0d0df
This commit is contained in:
@@ -412,8 +412,13 @@ public class AccessibilityShortcutController {
|
||||
* Class to wrap TextToSpeech for shortcut dialog spoken feedback.
|
||||
*/
|
||||
private class TtsPrompt implements TextToSpeech.OnInitListener {
|
||||
private static final int RETRY_MILLIS = 1000;
|
||||
|
||||
private final CharSequence mText;
|
||||
|
||||
private int mRetryCount = 3;
|
||||
private boolean mDismiss;
|
||||
private boolean mLanguageReady = false;
|
||||
private TextToSpeech mTts;
|
||||
|
||||
TtsPrompt(String serviceName) {
|
||||
@@ -437,17 +442,15 @@ public class AccessibilityShortcutController {
|
||||
playNotificationTone();
|
||||
return;
|
||||
}
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(TtsPrompt::play, this));
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||
TtsPrompt::waitForTtsReady, this));
|
||||
}
|
||||
|
||||
private void play() {
|
||||
if (mDismiss) {
|
||||
return;
|
||||
}
|
||||
int status = TextToSpeech.ERROR;
|
||||
if (setLanguage(Locale.getDefault())) {
|
||||
status = mTts.speak(mText, TextToSpeech.QUEUE_FLUSH, null, null);
|
||||
}
|
||||
final int status = mTts.speak(mText, TextToSpeech.QUEUE_FLUSH, null, null);
|
||||
if (status != TextToSpeech.SUCCESS) {
|
||||
Slog.d(TAG, "Tts play fail");
|
||||
playNotificationTone();
|
||||
@@ -455,21 +458,42 @@ public class AccessibilityShortcutController {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false if tts language is not available
|
||||
* Waiting for tts is ready to speak. Trying again if tts language pack is not available
|
||||
* or tts voice data is not installed yet.
|
||||
*/
|
||||
private boolean setLanguage(final Locale locale) {
|
||||
int status = mTts.isLanguageAvailable(locale);
|
||||
if (status == TextToSpeech.LANG_MISSING_DATA
|
||||
|| status == TextToSpeech.LANG_NOT_SUPPORTED) {
|
||||
return false;
|
||||
private void waitForTtsReady() {
|
||||
if (mDismiss) {
|
||||
return;
|
||||
}
|
||||
mTts.setLanguage(locale);
|
||||
Voice voice = mTts.getVoice();
|
||||
if (voice == null || (voice.getFeatures() != null && voice.getFeatures()
|
||||
.contains(TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED))) {
|
||||
return false;
|
||||
if (!mLanguageReady) {
|
||||
final int status = mTts.setLanguage(Locale.getDefault());
|
||||
// True if language is available and TTS#loadVoice has called once
|
||||
// that trigger TTS service to start initialization.
|
||||
mLanguageReady = status != TextToSpeech.LANG_MISSING_DATA
|
||||
&& status != TextToSpeech.LANG_NOT_SUPPORTED;
|
||||
}
|
||||
return true;
|
||||
if (mLanguageReady) {
|
||||
final Voice voice = mTts.getVoice();
|
||||
final boolean voiceDataInstalled = voice != null
|
||||
&& voice.getFeatures() != null
|
||||
&& !voice.getFeatures().contains(
|
||||
TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED);
|
||||
if (voiceDataInstalled) {
|
||||
mHandler.sendMessage(PooledLambda.obtainMessage(
|
||||
TtsPrompt::play, this));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mRetryCount == 0) {
|
||||
Slog.d(TAG, "Tts not ready to speak.");
|
||||
playNotificationTone();
|
||||
return;
|
||||
}
|
||||
// Retry if TTS service not ready yet.
|
||||
mRetryCount -= 1;
|
||||
mHandler.sendMessageDelayed(PooledLambda.obtainMessage(
|
||||
TtsPrompt::waitForTtsReady, this), RETRY_MILLIS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -85,7 +86,9 @@ import org.mockito.invocation.InvocationOnMock;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -534,6 +537,36 @@ public class AccessibilityShortcutControllerTest {
|
||||
verify(mRingtone).play();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnAccessibilityShortcut_showsWarningDialog_ttsLongTimeInit_retrySpoken()
|
||||
throws Exception {
|
||||
configureShortcutEnabled(ENABLED_EXCEPT_LOCK_SCREEN);
|
||||
configureValidShortcutService();
|
||||
configureTtsSpokenPromptEnabled();
|
||||
configureHandlerCallbackInvocation();
|
||||
AccessibilityShortcutController accessibilityShortcutController = getController();
|
||||
Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
|
||||
Set<String> features = new HashSet<>();
|
||||
features.add(TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED);
|
||||
doReturn(features, Collections.emptySet()).when(mVoice).getFeatures();
|
||||
doReturn(TextToSpeech.LANG_NOT_SUPPORTED, TextToSpeech.LANG_AVAILABLE)
|
||||
.when(mTextToSpeech).setLanguage(any());
|
||||
accessibilityShortcutController.performAccessibilityShortcut();
|
||||
|
||||
verify(mAlertDialog).show();
|
||||
ArgumentCaptor<TextToSpeech.OnInitListener> onInitCap = ArgumentCaptor.forClass(
|
||||
TextToSpeech.OnInitListener.class);
|
||||
verify(mFrameworkObjectProvider).getTextToSpeech(any(), onInitCap.capture());
|
||||
onInitCap.getValue().onInit(TextToSpeech.SUCCESS);
|
||||
verify(mTextToSpeech).speak(any(), eq(TextToSpeech.QUEUE_FLUSH), any(), any());
|
||||
ArgumentCaptor<DialogInterface.OnDismissListener> onDismissCap = ArgumentCaptor.forClass(
|
||||
DialogInterface.OnDismissListener.class);
|
||||
verify(mAlertDialog).setOnDismissListener(onDismissCap.capture());
|
||||
onDismissCap.getValue().onDismiss(mAlertDialog);
|
||||
verify(mTextToSpeech).shutdown();
|
||||
verify(mRingtone, times(0)).play();
|
||||
}
|
||||
|
||||
private void configureNoShortcutService() throws Exception {
|
||||
when(mAccessibilityManagerService
|
||||
.getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
|
||||
|
||||
Reference in New Issue
Block a user