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

Commit 28d79c4c authored by Automerger Merge Worker's avatar Automerger Merge Worker
Browse files

Merge "Retry TTS speaking for a11y shortcut warning dialog" into rvc-dev am: 67c02e6c

Change-Id: I3271aba62a790c04366b13fcd682b6fbe6fd7c58
parents fc107dee 67c02e6c
Loading
Loading
Loading
Loading
+41 −17
Original line number Original line Diff line number Diff line
@@ -412,8 +412,13 @@ public class AccessibilityShortcutController {
     * Class to wrap TextToSpeech for shortcut dialog spoken feedback.
     * Class to wrap TextToSpeech for shortcut dialog spoken feedback.
     */
     */
    private class TtsPrompt implements TextToSpeech.OnInitListener {
    private class TtsPrompt implements TextToSpeech.OnInitListener {
        private static final int RETRY_MILLIS = 1000;

        private final CharSequence mText;
        private final CharSequence mText;

        private int mRetryCount = 3;
        private boolean mDismiss;
        private boolean mDismiss;
        private boolean mLanguageReady = false;
        private TextToSpeech mTts;
        private TextToSpeech mTts;


        TtsPrompt(String serviceName) {
        TtsPrompt(String serviceName) {
@@ -437,17 +442,15 @@ public class AccessibilityShortcutController {
                playNotificationTone();
                playNotificationTone();
                return;
                return;
            }
            }
            mHandler.sendMessage(PooledLambda.obtainMessage(TtsPrompt::play, this));
            mHandler.sendMessage(PooledLambda.obtainMessage(
                    TtsPrompt::waitForTtsReady, this));
        }
        }


        private void play() {
        private void play() {
            if (mDismiss) {
            if (mDismiss) {
                return;
                return;
            }
            }
            int status = TextToSpeech.ERROR;
            final int status = mTts.speak(mText, TextToSpeech.QUEUE_FLUSH, null, null);
            if (setLanguage(Locale.getDefault())) {
                status = mTts.speak(mText, TextToSpeech.QUEUE_FLUSH, null, null);
            }
            if (status != TextToSpeech.SUCCESS) {
            if (status != TextToSpeech.SUCCESS) {
                Slog.d(TAG, "Tts play fail");
                Slog.d(TAG, "Tts play fail");
                playNotificationTone();
                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) {
        private void waitForTtsReady() {
            int status = mTts.isLanguageAvailable(locale);
            if (mDismiss) {
            if (status == TextToSpeech.LANG_MISSING_DATA
                return;
                    || status == TextToSpeech.LANG_NOT_SUPPORTED) {
                return false;
            }
            }
            mTts.setLanguage(locale);
            if (!mLanguageReady) {
            Voice voice = mTts.getVoice();
                final int status = mTts.setLanguage(Locale.getDefault());
            if (voice == null || (voice.getFeatures() != null && voice.getFeatures()
                // True if language is available and TTS#loadVoice has called once
                    .contains(TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED))) {
                // that trigger TTS service to start initialization.
                return false;
                mLanguageReady = status != TextToSpeech.LANG_MISSING_DATA
                    && status != TextToSpeech.LANG_NOT_SUPPORTED;
            }
            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;
                }
                }
            return true;
            }

            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);
        }
        }
    }
    }


+33 −0
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@ import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verify;
@@ -85,7 +86,9 @@ import org.mockito.invocation.InvocationOnMock;


import java.lang.reflect.Field;
import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Map;
import java.util.Set;




@RunWith(AndroidJUnit4.class)
@RunWith(AndroidJUnit4.class)
@@ -534,6 +537,36 @@ public class AccessibilityShortcutControllerTest {
        verify(mRingtone).play();
        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 {
    private void configureNoShortcutService() throws Exception {
        when(mAccessibilityManagerService
        when(mAccessibilityManagerService
                .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))
                .getAccessibilityShortcutTargets(ACCESSIBILITY_SHORTCUT_KEY))