8

I'm having a really weird problem.

I keep getting this crash in my logcat, but the weird this is that my app has nothing to do with the Text To Speech thing. not just this activity, my entire app doesn't use it at all.

08-04 03:47:19.321: E/ActivityThread(24755): Activity com.lablabla.similarsearch.WebViewActivity has leaked ServiceConnection android.speech.tts.TextToSpeech$Connection@443065c0 that was originally bound here
08-04 03:47:19.321: E/ActivityThread(24755): android.app.ServiceConnectionLeaked: Activity com.lablabla.similarsearch.WebViewActivity has leaked ServiceConnection android.speech.tts.TextToSpeech$Connection@443065c0 that was originally bound here
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.LoadedApk$ServiceDispatcher.<init>(LoadedApk.java:974)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:868)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.ContextImpl.bindServiceAsUser(ContextImpl.java:1452)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.ContextImpl.bindService(ContextImpl.java:1440)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.content.ContextWrapper.bindService(ContextWrapper.java:496)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.speech.tts.TextToSpeech.connectToEngine(TextToSpeech.java:685)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.speech.tts.TextToSpeech.initTts(TextToSpeech.java:655)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.speech.tts.TextToSpeech.<init>(TextToSpeech.java:608)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.webkit.AccessibilityInjector$TextToSpeechWrapper.<init>(AccessibilityInjector.java:682)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.webkit.AccessibilityInjector.addTtsApis(AccessibilityInjector.java:483)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.webkit.AccessibilityInjector.addAccessibilityApisIfNecessary(AccessibilityInjector.java:168)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.webkit.AccessibilityInjector.updateJavaScriptEnabled(AccessibilityInjector.java:418)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.webkit.WebViewClassic.updateJavaScriptEnabled(WebViewClassic.java:1682)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.webkit.WebSettingsClassic.setJavaScriptEnabled(WebSettingsClassic.java:1125)
08-04 03:47:19.321: E/ActivityThread(24755):    at com.lablabla.similarsearch.WebViewActivity.onCreate(WebViewActivity.java:24)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.Activity.performCreate(Activity.java:5133)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.ActivityThread.access$600(ActivityThread.java:141)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.os.Looper.loop(Looper.java:137)
08-04 03:47:19.321: E/ActivityThread(24755):    at android.app.ActivityThread.main(ActivityThread.java:5103)
08-04 03:47:19.321: E/ActivityThread(24755):    at java.lang.reflect.Method.invokeNative(Native Method)
08-04 03:47:19.321: E/ActivityThread(24755):    at java.lang.reflect.Method.invoke(Method.java:525)
08-04 03:47:19.321: E/ActivityThread(24755):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
08-04 03:47:19.321: E/ActivityThread(24755):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
08-04 03:47:19.321: E/ActivityThread(24755):    at dalvik.system.NativeStart.main(Native Method)

And here's the code for that activity: (All it does is get a url from the Intent and load it to a WebView)

public class WebViewActivity extends Activity {

    public static final String EXTRA_URL = "extra_url";

    private WebView webView;
    private String baseUrl;

    @SuppressLint("SetJavaScriptEnabled")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.webview);
        webView = (WebView) findViewById(R.id.webView);
        webView.getSettings().setJavaScriptEnabled(true);
        webView.setWebViewClient(new WebViewClient());
        webView.getSettings().setUserAgentString(
            "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/20 Safari/537.31");
        baseUrl = getIntent().getStringExtra(EXTRA_URL);
        webView.loadUrl(baseUrl);
    }
}
Dave Newton
  • 158,873
  • 26
  • 254
  • 302
La bla bla
  • 8,558
  • 13
  • 60
  • 109
  • Did you ever figure out what this was? I'm seeing the same thing while testing my app with TalkBack. When I hit the back button to exit one of my activities, TalkBack spews the same errors. My activity has a webview with javascript enabled, too. My activity does NOT actively make use of the TTS service. I'm merely testing how well it works with TalkBack. I found a thread on Google Groups that discusses the same issue but apparently it magically resolved itself. https://groups.google.com/forum/#!topic/eyes-free/b_3OJI8h4tQ – Robert Nekic Sep 13 '13 at 19:20
  • I did not. It doesn't seem to affect the app it self, not could I find any indication that it causes any issues with other apps or services affecting the phone's normal functions. I just started a bounty on this, maybe it will be resolved that way. – La bla bla Sep 13 '13 at 22:32

2 Answers2

13

I keep getting this crash in my logcat, but the weird this is that my app has nothing to do with the Text To Speech thing. not just this activity, my entire app doesn't use it at all.

Your app indeed has nothing to do with it.

Except that when you call:

webView.getSettings().setJavaScriptEnabled(true);

the method WebViewClassic.updateJavaScriptEnabled(boolean) is executed:

void updateJavaScriptEnabled(boolean enabled) {
    if (isAccessibilityInjectionEnabled()) {

 ==>>>> // Call placed to AccessibilityInjector.updateJavaScriptEnabled(boolean)
        getAccessibilityInjector().updateJavaScriptEnabled(enabled);
    }
}

Here, isAccessibilityInjectionEnabled() returns true in your device's case. It retrieves a list of Accessibility Services that are currently enabled, and provide/support AccessibilityServiceInfo.FEEDBACK_SPOKEN. If this list is non-empty, true is returned.

Moving up the stacktrace:

android.webkit.AccessibilityInjector.addTtsApis()

eventually creates a TextToSpeech object.

The problem: TextToSpeech.connectToEngine() uses Context to call bindService(). The context is your Activity's context (passed on from WebView). I believe the Logcat shows this (or something similar) when WebViewActivity is started:

Sucessfully bound to com.google.android.tts

Hypothesis: When your Activity is destroyed and recreated on screen rotation, the TTS service is still bound while the context isn't valid anymore. This is what the exception refers to.

I tried the following to test my hypothesis:

Instead of defining WebView in xml, I created it dynamically in onCreate():

webView = new WebView(getApplicationContext());

Notice that I used the Application's context in place of Activity's (this). The context stays valid on orientation change, and hence the exception isn't thrown.

To confirm that one (or more) Accessibility Service is enabled, add this code to your activity's onCreate():

AccessibilityManager am = (AccessibilityManager)
                                   getSystemService(ACCESSIBILITY_SERVICE);

List<AccessibilityServiceInfo> listOfServices = 
                                 am.getEnabledAccessibilityServiceList(
                                   AccessibilityServiceInfo.FEEDBACK_ALL_MASK);

for (AccessibilityServiceInfo asi : listOfServices) {
    Log.i("", "Accessibility Service >>>>>>>>: " + asi.getSettingsActivityName());
Log.i("", "Accessibility Service >>>>>>>>: " +
                                 asi.loadDescription(getPackageManager()));

}

Note: I had to turn on TalkBack (under Settings > Accessibility) to replicate the issue. Also, I am not sure why this exception isn't thrown after force stopping the application.

Based on user Robert Nekic's comment: behavior on back press: Exception is thrown when activity's context is used. Application's context still works.

Useful information: Link.

Community
  • 1
  • 1
Vikram
  • 51,313
  • 11
  • 93
  • 122
  • I am getting the logcat error for AccessibilityInjector when Talkback is on for Android 4.4. Can you suggest any workaround for the issue here: http://stackoverflow.com/q/29434063/1263215 – r.bhardwaj Apr 08 '15 at 10:22
  • webview = (WebView) findViewById(R.id.webview_wv); I got webview by finding, so how can I avoid this exception? – thecr0w May 25 '15 at 02:10
  • 1
    @thecr0w I found that using `Application` context was the only way to circumvent this exception. The obvious side-effect is that you cannot define the `WebView` in xml. You'll have to create it at runtime and add it to your layout. One thing that you could try: define your `WebView` in xml & inflate that layout using `LayoutInflater` obtained through `LayoutInflater.fromContext(getApplicationContext())`. I can't say if it will work. – Vikram May 29 '15 at 02:41
1

You can add this code snippet to avoid this service connection leaked exception:

class YourActivity extends Activity {
WebView yourWebView;

    @Override
    public void onDestroy() {

        if (yourWebView != null) {
            yourWebView.getSettings().setJavaScriptEnabled(false);
        }
}

yourWebView.getSettings().setJavaScriptEnabled(false); will trigger the invoke of AccessibilityInjector.updateJavaScriptEnabled() in which:

private void removeTtsApis() {
    if (mTextToSpeech != null) {
        mTextToSpeech.stop();
        mTextToSpeech.shutdown();
        mTextToSpeech = null;
    }

    mWebView.removeJavascriptInterface(ALIAS_TTS_JS_INTERFACE);
}

mTextToSpeech.shutdown() is just the key point.

faywong
  • 141
  • 1
  • 5