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

Commit 8f3957cb authored by Przemyslaw Szczepaniak's avatar Przemyslaw Szczepaniak Committed by Android (Google) Code Review
Browse files

TTS onServiceConnection moved to async task

ITextToSpeechService.setCallback (service rpc call) is no longer
executed on UI thread.

I kept OnInitListener.onInit being called on the UI thread. It's
not specified explicitly, but I don't want to introduce subtle
bugs.

+bonus import fix.

Bug: 6540404
Change-Id: I0136e7efeb374b605ed29ee8b3f550ec2bd2c356
parent b920b405
Loading
Loading
Loading
Loading
+81 −25
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.media.AudioManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
@@ -1276,9 +1277,11 @@ public class TextToSpeech {
        return mEnginesHelper.getEngines();
    }


    private class Connection implements ServiceConnection {
        private ITextToSpeechService mService;

        private OnServiceConnectedAsyncTask mOnServiceConnectedAsyncTask;

        private final ITextToSpeechCallback.Stub mCallback = new ITextToSpeechCallback.Stub() {
            @Override
            public void onDone(String utteranceId) {
@@ -1305,52 +1308,105 @@ public class TextToSpeech {
            }
        };

        private class OnServiceConnectedAsyncTask extends AsyncTask<Void, Void, Integer> {
            private final ComponentName mName;
            private final ITextToSpeechService mConnectedService;

            public OnServiceConnectedAsyncTask(ComponentName name, IBinder service) {
                mName = name;
                mConnectedService = ITextToSpeechService.Stub.asInterface(service);
            }

            @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.i(TAG, "Connected to " + name);
            protected Integer doInBackground(Void... params) {
                synchronized(mStartLock) {
                if (mServiceConnection != null) {
                    // Disconnect any previous service connection
                    mServiceConnection.disconnect();
                    if (isCancelled()) {
                        return null;
                    }
                mServiceConnection = this;
                mService = ITextToSpeechService.Stub.asInterface(service);

                    try {
                    mService.setCallback(getCallerIdentity(), mCallback);
                    dispatchOnInit(SUCCESS);
                        mConnectedService.setCallback(getCallerIdentity(), mCallback);
                        Log.i(TAG, "Setuped connection to " + mName);
                        return SUCCESS;
                    } catch (RemoteException re) {
                        Log.e(TAG, "Error connecting to service, setCallback() failed");
                    dispatchOnInit(ERROR);
                        return ERROR;
                    }
                }
            }

        public IBinder getCallerIdentity() {
            return mCallback;
            @Override
            protected void onPostExecute(Integer result) {
                synchronized(mStartLock) {
                    if (mOnServiceConnectedAsyncTask == this) {
                        mOnServiceConnectedAsyncTask = null;
                    }

                    mServiceConnection = Connection.this;
                    mService = mConnectedService;

                    dispatchOnInit(result);
                }
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
        public void onServiceConnected(ComponentName name, IBinder service) {
            synchronized(mStartLock) {
                mService = null;
                // If this is the active connection, clear it
                if (mServiceConnection == this) {
                    mServiceConnection = null;
                Log.i(TAG, "Connected to " + name);

                if (mOnServiceConnectedAsyncTask != null) {
                    mOnServiceConnectedAsyncTask.cancel(false);
                }

                mOnServiceConnectedAsyncTask = new OnServiceConnectedAsyncTask(name, service);
                mOnServiceConnectedAsyncTask.execute();
            }
        }

        public void disconnect() {
            mContext.unbindService(this);
        public IBinder getCallerIdentity() {
            return mCallback;
        }

        /**
         * Clear connection related fields and cancel mOnServiceConnectedAsyncTask if set.
         *
         * @return true if we cancel mOnServiceConnectedAsyncTask in progress.
         */
        private boolean clearServiceConnection() {
            synchronized(mStartLock) {
                boolean result = false;
                if (mOnServiceConnectedAsyncTask != null) {
                    result = mOnServiceConnectedAsyncTask.cancel(false);
                    mOnServiceConnectedAsyncTask = null;
                }

                mService = null;
                // If this is the active connection, clear it
                if (mServiceConnection == this) {
                    mServiceConnection = null;
                }
                return result;
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.i(TAG, "Asked to disconnect from " + name);
            if (clearServiceConnection()) {
                /* We need to protect against a rare case where engine
                 * dies just after successful connection - and we process onServiceDisconnected
                 * before OnServiceConnectedAsyncTask.onPostExecute. onServiceDisconnected cancels
                 * OnServiceConnectedAsyncTask.onPostExecute and we don't call dispatchOnInit
                 * with ERROR as argument.
                 */
                dispatchOnInit(ERROR);
            }
        }

        public void disconnect() {
            mContext.unbindService(this);
            clearServiceConnection();
        }

        public <R> R runAction(Action<R> action, R errorResult, String method, boolean reconnect) {
+0 −1
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Set;