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

Commit f7be31ee authored by satok's avatar satok Committed by Android (Google) Code Review
Browse files

Merge "Handle the existing binds to spell checkers correctly."

parents ae5a9d4a 6be6d754
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,7 @@ import android.app.Service;
import android.content.Intent;
import android.content.Intent;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.util.Log;
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;
import android.view.textservice.TextInfo;


@@ -36,6 +37,7 @@ import java.lang.ref.WeakReference;
 */
 */
public abstract class SpellCheckerService extends Service {
public abstract class SpellCheckerService extends Service {
    private static final String TAG = SpellCheckerService.class.getSimpleName();
    private static final String TAG = SpellCheckerService.class.getSimpleName();
    private static final boolean DBG = false;
    public static final String SERVICE_INTERFACE =
    public static final String SERVICE_INTERFACE =
            "android.service.textservice.SpellCheckerService";
            "android.service.textservice.SpellCheckerService";


@@ -87,6 +89,9 @@ public abstract class SpellCheckerService extends Service {
     */
     */
    @Override
    @Override
    public final IBinder onBind(final Intent intent) {
    public final IBinder onBind(final Intent intent) {
        if (DBG) {
            Log.w(TAG, "onBind");
        }
        return mBinder;
        return mBinder;
    }
    }


+18 −1
Original line number Original line Diff line number Diff line
@@ -30,7 +30,6 @@ import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;
import android.view.textservice.TextInfo;


import java.util.LinkedList;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Queue;
import java.util.Queue;


/**
/**
@@ -125,6 +124,9 @@ public class SpellCheckerSession {
     */
     */
    public void getSuggestions(
    public void getSuggestions(
            TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
            TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
        if (DBG) {
            Log.w(TAG, "getSuggestions from " + mSpellCheckerInfo.getId());
        }
        // TODO: Handle multiple words suggestions by using WordBreakIterator
        // TODO: Handle multiple words suggestions by using WordBreakIterator
        mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
        mSpellCheckerSessionListenerImpl.getSuggestionsMultiple(
                textInfos, suggestionsLimit, sequentialWords);
                textInfos, suggestionsLimit, sequentialWords);
@@ -186,6 +188,9 @@ public class SpellCheckerSession {


        public void getSuggestionsMultiple(
        public void getSuggestionsMultiple(
                TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
                TextInfo[] textInfos, int suggestionsLimit, boolean sequentialWords) {
            if (DBG) {
                Log.w(TAG, "getSuggestionsMultiple");
            }
            processOrEnqueueTask(
            processOrEnqueueTask(
                    new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos,
                    new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE, textInfos,
                            suggestionsLimit, sequentialWords));
                            suggestionsLimit, sequentialWords));
@@ -204,6 +209,9 @@ public class SpellCheckerSession {
        }
        }


        private void processOrEnqueueTask(SpellCheckerParams scp) {
        private void processOrEnqueueTask(SpellCheckerParams scp) {
            if (DBG) {
                Log.d(TAG, "process or enqueue task: " + mISpellCheckerSession);
            }
            if (mISpellCheckerSession == null) {
            if (mISpellCheckerSession == null) {
                mPendingTasks.offer(scp);
                mPendingTasks.offer(scp);
            } else {
            } else {
@@ -215,6 +223,9 @@ public class SpellCheckerSession {
            if (!checkOpenConnection()) {
            if (!checkOpenConnection()) {
                return;
                return;
            }
            }
            if (DBG) {
                Log.w(TAG, "Cancel spell checker tasks.");
            }
            try {
            try {
                mISpellCheckerSession.cancel();
                mISpellCheckerSession.cancel();
            } catch (RemoteException e) {
            } catch (RemoteException e) {
@@ -226,6 +237,9 @@ public class SpellCheckerSession {
            if (!checkOpenConnection()) {
            if (!checkOpenConnection()) {
                return;
                return;
            }
            }
            if (DBG) {
                Log.w(TAG, "Get suggestions from the spell checker.");
            }
            try {
            try {
                mISpellCheckerSession.getSuggestionsMultiple(
                mISpellCheckerSession.getSuggestionsMultiple(
                        scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords);
                        scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords);
@@ -254,6 +268,9 @@ public class SpellCheckerSession {
    private class InternalListener extends ITextServicesSessionListener.Stub {
    private class InternalListener extends ITextServicesSessionListener.Stub {
        @Override
        @Override
        public void onServiceConnected(ISpellCheckerSession session) {
        public void onServiceConnected(ISpellCheckerSession session) {
            if (DBG) {
                Log.w(TAG, "SpellCheckerSession connected.");
            }
            mSpellCheckerSessionListenerImpl.onServiceConnected(session);
            mSpellCheckerSessionListenerImpl.onServiceConnected(session);
        }
        }
    }
    }
+84 −20
Original line number Original line Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemClock;
@@ -177,7 +178,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
        if (!mSystemReady) {
        if (!mSystemReady) {
            return;
            return;
        }
        }
        if (info == null || tsListener == null) {
        if (info == null || tsListener == null || scListener == null) {
            Slog.e(TAG, "getSpellCheckerService: Invalid input.");
            Slog.e(TAG, "getSpellCheckerService: Invalid input.");
            return;
            return;
        }
        }
@@ -187,13 +188,57 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                return;
                return;
            }
            }
            if (mSpellCheckerBindGroups.containsKey(sciId)) {
            if (mSpellCheckerBindGroups.containsKey(sciId)) {
                mSpellCheckerBindGroups.get(sciId).addListener(tsListener, locale, scListener);
                final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId);
                if (bindGroup != null) {
                    final InternalDeathRecipient recipient =
                            mSpellCheckerBindGroups.get(sciId).addListener(
                                    tsListener, locale, scListener);
                    if (recipient == null) {
                        if (DBG) {
                            Slog.w(TAG, "Didn't create a death recipient.");
                        }
                        return;
                        return;
                    }
                    }
                    if (bindGroup.mSpellChecker == null & bindGroup.mConnected) {
                        Slog.e(TAG, "The state of the spell checker bind group is illegal.");
                        bindGroup.removeAll();
                    } else if (bindGroup.mSpellChecker != null) {
                        if (DBG) {
                            Slog.w(TAG, "Existing bind found. Return a spell checker session now.");
                        }
                        try {
                            final ISpellCheckerSession session =
                                    bindGroup.mSpellChecker.getISpellCheckerSession(
                                            recipient.mScLocale, recipient.mScListener);
                            tsListener.onServiceConnected(session);
                            return;
                        } catch (RemoteException e) {
                            Slog.e(TAG, "Exception in getting spell checker session: " + e);
                            bindGroup.removeAll();
                        }
                    }
                }
            }
            final long ident = Binder.clearCallingIdentity();
            try {
                startSpellCheckerServiceInnerLocked(info, locale, tsListener, scListener);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
        return;
    }

    private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale,
            ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener) {
        final String sciId = info.getId();
        final InternalServiceConnection connection = new InternalServiceConnection(
        final InternalServiceConnection connection = new InternalServiceConnection(
                sciId, locale, scListener);
                sciId, locale, scListener);
        final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE);
        final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE);
        serviceIntent.setComponent(info.getComponent());
        serviceIntent.setComponent(info.getComponent());
        if (DBG) {
            Slog.w(TAG, "bind service: " + info.getId());
        }
        if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
        if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
            Slog.e(TAG, "Failed to get a spell checker service.");
            Slog.e(TAG, "Failed to get a spell checker service.");
            return;
            return;
@@ -202,8 +247,6 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                connection, tsListener, locale, scListener);
                connection, tsListener, locale, scListener);
        mSpellCheckerBindGroups.put(sciId, group);
        mSpellCheckerBindGroups.put(sciId, group);
    }
    }
        return;
    }


    @Override
    @Override
    public SpellCheckerInfo[] getEnabledSpellCheckers() {
    public SpellCheckerInfo[] getEnabledSpellCheckers() {
@@ -242,14 +285,17 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
    // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from
    // If there are no listeners anymore, the SpellCheckerBindGroup instance will be removed from
    // mSpellCheckerBindGroups
    // mSpellCheckerBindGroups
    private class SpellCheckerBindGroup {
    private class SpellCheckerBindGroup {
        final InternalServiceConnection mInternalConnection;
        private final InternalServiceConnection mInternalConnection;
        final ArrayList<InternalDeathRecipient> mListeners =
        private final ArrayList<InternalDeathRecipient> mListeners =
                new ArrayList<InternalDeathRecipient>();
                new ArrayList<InternalDeathRecipient>();
        public ISpellCheckerService mSpellChecker;
        public boolean mConnected;


        public SpellCheckerBindGroup(InternalServiceConnection connection,
        public SpellCheckerBindGroup(InternalServiceConnection connection,
                ITextServicesSessionListener listener, String locale,
                ITextServicesSessionListener listener, String locale,
                ISpellCheckerSessionListener scListener) {
                ISpellCheckerSessionListener scListener) {
            mInternalConnection = connection;
            mInternalConnection = connection;
            mConnected = false;
            addListener(listener, locale, scListener);
            addListener(listener, locale, scListener);
        }
        }


@@ -264,26 +310,32 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                                listener.mScLocale, listener.mScListener);
                                listener.mScLocale, listener.mScListener);
                        listener.mTsListener.onServiceConnected(session);
                        listener.mTsListener.onServiceConnected(session);
                    } catch (RemoteException e) {
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Exception in getting spell checker session: " + e);
                        removeAll();
                        return;
                    }
                    }
                }
                }
                mSpellChecker = spellChecker;
                mConnected = true;
            }
            }
        }
        }


        public void addListener(ITextServicesSessionListener tsListener, String locale,
        public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener,
                ISpellCheckerSessionListener scListener) {
                String locale, ISpellCheckerSessionListener scListener) {
            if (DBG) {
            if (DBG) {
                Slog.d(TAG, "addListener: " + locale);
                Slog.d(TAG, "addListener: " + locale);
            }
            }
            InternalDeathRecipient recipient = null;
            synchronized(mSpellCheckerMap) {
            synchronized(mSpellCheckerMap) {
                try {
                try {
                    final int size = mListeners.size();
                    final int size = mListeners.size();
                    for (int i = 0; i < size; ++i) {
                    for (int i = 0; i < size; ++i) {
                        if (mListeners.get(i).hasSpellCheckerListener(scListener)) {
                        if (mListeners.get(i).hasSpellCheckerListener(scListener)) {
                            // do not add the lister if the group already contains this.
                            // do not add the lister if the group already contains this.
                            return;
                            return null;
                        }
                        }
                    }
                    }
                    final InternalDeathRecipient recipient = new InternalDeathRecipient(
                    recipient = new InternalDeathRecipient(
                            this, tsListener, locale, scListener);
                            this, tsListener, locale, scListener);
                    scListener.asBinder().linkToDeath(recipient, 0);
                    scListener.asBinder().linkToDeath(recipient, 0);
                    mListeners.add(new InternalDeathRecipient(
                    mListeners.add(new InternalDeathRecipient(
@@ -293,6 +345,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                }
                }
                cleanLocked();
                cleanLocked();
            }
            }
            return recipient;
        }
        }


        public void removeListener(ISpellCheckerSessionListener listener) {
        public void removeListener(ISpellCheckerSessionListener listener) {
@@ -322,11 +375,19 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                Slog.d(TAG, "cleanLocked");
                Slog.d(TAG, "cleanLocked");
            }
            }
            if (mListeners.isEmpty()) {
            if (mListeners.isEmpty()) {
                if (mSpellCheckerBindGroups.containsKey(this)) {
                    mSpellCheckerBindGroups.remove(this);
                    mSpellCheckerBindGroups.remove(this);
                }
                // Unbind service when there is no active clients.
                // Unbind service when there is no active clients.
                mContext.unbindService(mInternalConnection);
                mContext.unbindService(mInternalConnection);
            }
            }
        }
        }

        public void removeAll() {
            Slog.e(TAG, "Remove the spell checker bind unexpectedly.");
            mListeners.clear();
            cleanLocked();
        }
    }
    }


    private class InternalServiceConnection implements ServiceConnection {
    private class InternalServiceConnection implements ServiceConnection {
@@ -343,6 +404,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
        @Override
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        public void onServiceConnected(ComponentName name, IBinder service) {
            synchronized(mSpellCheckerMap) {
            synchronized(mSpellCheckerMap) {
                if (DBG) {
                    Slog.w(TAG, "onServiceConnected: " + name);
                }
                ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service);
                ISpellCheckerService spellChecker = ISpellCheckerService.Stub.asInterface(service);
                final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
                final SpellCheckerBindGroup group = mSpellCheckerBindGroups.get(mSciId);
                if (group != null) {
                if (group != null) {