Commit 427d0afb authored by Dominic Mazzoni's avatar Dominic Mazzoni Committed by Commit Bot

Don't play synthesized speech from web pages when Chrome is in the background.

Fixes two issues:
1. If a web page starts talking and you switch out of Chrome, it will stop
   speech now.
2. If a web page tries to start speaking after a setTimeout delay, it won't
   speak if Chrome doesn't have a visible window at the time it would speak.

This doesn't necessarily address the issue of a background tab trying to speak,
that would require plumbing through a lot of information that's not
available now. Let's see if this is good enough, and revisit if we also
need to keep track of tabs?

Bug: 998328
Change-Id: I5f4d2dbeb033b9868eee0faf242522f1f0796a6e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1779172Reviewed-by: default avatarJinsuk Kim <jinsukkim@chromium.org>
Commit-Queue: Dominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#693001}
parent 248662b1
...@@ -109,6 +109,11 @@ void TtsPlatformImplAndroid::GetVoices(std::vector<VoiceData>* out_voices) { ...@@ -109,6 +109,11 @@ void TtsPlatformImplAndroid::GetVoices(std::vector<VoiceData>* out_voices) {
} }
} }
void TtsPlatformImplAndroid::RequestTtsStop(JNIEnv* env,
const JavaParamRef<jobject>& obj) {
TtsController::GetInstance()->Stop();
}
void TtsPlatformImplAndroid::VoicesChanged(JNIEnv* env, void TtsPlatformImplAndroid::VoicesChanged(JNIEnv* env,
const JavaParamRef<jobject>& obj) { const JavaParamRef<jobject>& obj) {
TtsController::GetInstance()->VoicesChanged(); TtsController::GetInstance()->VoicesChanged();
......
...@@ -28,6 +28,8 @@ class TtsPlatformImplAndroid : public TtsPlatformImpl { ...@@ -28,6 +28,8 @@ class TtsPlatformImplAndroid : public TtsPlatformImpl {
void GetVoices(std::vector<VoiceData>* out_voices) override; void GetVoices(std::vector<VoiceData>* out_voices) override;
// Methods called from Java via JNI. // Methods called from Java via JNI.
void RequestTtsStop(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
void VoicesChanged(JNIEnv* env, void VoicesChanged(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj); const base::android::JavaParamRef<jobject>& obj);
void OnEndEvent(JNIEnv* env, void OnEndEvent(JNIEnv* env,
......
...@@ -4,10 +4,14 @@ ...@@ -4,10 +4,14 @@
package org.chromium.content.browser; package org.chromium.content.browser;
import android.app.Activity;
import android.os.Build; import android.os.Build;
import android.speech.tts.TextToSpeech; import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener; import android.speech.tts.UtteranceProgressListener;
import org.chromium.base.ActivityState;
import org.chromium.base.ApplicationStatus;
import org.chromium.base.ApplicationStatus.ActivityStateListener;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.base.TraceEvent; import org.chromium.base.TraceEvent;
import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNative;
...@@ -32,7 +36,7 @@ import java.util.Locale; ...@@ -32,7 +36,7 @@ import java.util.Locale;
* use PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, ...) when calling back to C++. * use PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, ...) when calling back to C++.
*/ */
@JNINamespace("content") @JNINamespace("content")
class TtsPlatformImpl { class TtsPlatformImpl implements ActivityStateListener {
private static class TtsVoice { private static class TtsVoice {
private TtsVoice(String name, String language) { private TtsVoice(String name, String language) {
mName = name; mName = name;
...@@ -83,6 +87,8 @@ class TtsPlatformImpl { ...@@ -83,6 +87,8 @@ class TtsPlatformImpl {
} }
}); });
addOnUtteranceProgressListener(); addOnUtteranceProgressListener();
ApplicationStatus.registerStateListenerForAllActivities(this);
} }
/** /**
...@@ -106,6 +112,7 @@ class TtsPlatformImpl { ...@@ -106,6 +112,7 @@ class TtsPlatformImpl {
*/ */
@CalledByNative @CalledByNative
private void destroy() { private void destroy() {
ApplicationStatus.unregisterActivityStateListener(this);
mNativeTtsPlatformImplAndroid = 0; mNativeTtsPlatformImplAndroid = 0;
} }
...@@ -161,6 +168,9 @@ class TtsPlatformImpl { ...@@ -161,6 +168,9 @@ class TtsPlatformImpl {
@CalledByNative @CalledByNative
private boolean speak( private boolean speak(
int utteranceId, String text, String lang, float rate, float pitch, float volume) { int utteranceId, String text, String lang, float rate, float pitch, float volume) {
// Don't speak when in the background.
if (!ApplicationStatus.hasVisibleActivities()) return false;
if (!mInitialized) { if (!mInitialized) {
mPendingUtterance = mPendingUtterance =
new PendingUtterance(this, utteranceId, text, lang, rate, pitch, volume); new PendingUtterance(this, utteranceId, text, lang, rate, pitch, volume);
...@@ -318,8 +328,18 @@ class TtsPlatformImpl { ...@@ -318,8 +328,18 @@ class TtsPlatformImpl {
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
@Override
public void onActivityStateChange(Activity activity, @ActivityState int newState) {
// Stop speech if all browser windows are no longer visible.
if (!ApplicationStatus.hasVisibleActivities()) {
TtsPlatformImplJni.get().requestTtsStop(
mNativeTtsPlatformImplAndroid, TtsPlatformImpl.this);
}
}
@NativeMethods @NativeMethods
interface Natives { interface Natives {
void requestTtsStop(long nativeTtsPlatformImplAndroid, TtsPlatformImpl caller);
void voicesChanged(long nativeTtsPlatformImplAndroid, TtsPlatformImpl caller); void voicesChanged(long nativeTtsPlatformImplAndroid, TtsPlatformImpl caller);
void onEndEvent(long nativeTtsPlatformImplAndroid, TtsPlatformImpl caller, int utteranceId); void onEndEvent(long nativeTtsPlatformImplAndroid, TtsPlatformImpl caller, int utteranceId);
void onStartEvent( void onStartEvent(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment