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 Diff line number Diff line
@@ -24,6 +24,7 @@ import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.textservice.SuggestionsInfo;
import android.view.textservice.TextInfo;

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

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

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

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

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

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

        private void processOrEnqueueTask(SpellCheckerParams scp) {
            if (DBG) {
                Log.d(TAG, "process or enqueue task: " + mISpellCheckerSession);
            }
            if (mISpellCheckerSession == null) {
                mPendingTasks.offer(scp);
            } else {
@@ -215,6 +223,9 @@ public class SpellCheckerSession {
            if (!checkOpenConnection()) {
                return;
            }
            if (DBG) {
                Log.w(TAG, "Cancel spell checker tasks.");
            }
            try {
                mISpellCheckerSession.cancel();
            } catch (RemoteException e) {
@@ -226,6 +237,9 @@ public class SpellCheckerSession {
            if (!checkOpenConnection()) {
                return;
            }
            if (DBG) {
                Log.w(TAG, "Get suggestions from the spell checker.");
            }
            try {
                mISpellCheckerSession.getSuggestionsMultiple(
                        scp.mTextInfos, scp.mSuggestionsLimit, scp.mSequentialWords);
@@ -254,6 +268,9 @@ public class SpellCheckerSession {
    private class InternalListener extends ITextServicesSessionListener.Stub {
        @Override
        public void onServiceConnected(ISpellCheckerSession session) {
            if (DBG) {
                Log.w(TAG, "SpellCheckerSession connected.");
            }
            mSpellCheckerSessionListenerImpl.onServiceConnected(session);
        }
    }
+84 −20
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -177,7 +178,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
        if (!mSystemReady) {
            return;
        }
        if (info == null || tsListener == null) {
        if (info == null || tsListener == null || scListener == null) {
            Slog.e(TAG, "getSpellCheckerService: Invalid input.");
            return;
        }
@@ -187,13 +188,57 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                return;
            }
            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;
                    }
                    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(
                sciId, locale, scListener);
        final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE);
        serviceIntent.setComponent(info.getComponent());
        if (DBG) {
            Slog.w(TAG, "bind service: " + info.getId());
        }
        if (!mContext.bindService(serviceIntent, connection, Context.BIND_AUTO_CREATE)) {
            Slog.e(TAG, "Failed to get a spell checker service.");
            return;
@@ -202,8 +247,6 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                connection, tsListener, locale, scListener);
        mSpellCheckerBindGroups.put(sciId, group);
    }
        return;
    }

    @Override
    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
    // mSpellCheckerBindGroups
    private class SpellCheckerBindGroup {
        final InternalServiceConnection mInternalConnection;
        final ArrayList<InternalDeathRecipient> mListeners =
        private final InternalServiceConnection mInternalConnection;
        private final ArrayList<InternalDeathRecipient> mListeners =
                new ArrayList<InternalDeathRecipient>();
        public ISpellCheckerService mSpellChecker;
        public boolean mConnected;

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

@@ -264,26 +310,32 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                                listener.mScLocale, listener.mScListener);
                        listener.mTsListener.onServiceConnected(session);
                    } 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,
                ISpellCheckerSessionListener scListener) {
        public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener,
                String locale, ISpellCheckerSessionListener scListener) {
            if (DBG) {
                Slog.d(TAG, "addListener: " + locale);
            }
            InternalDeathRecipient recipient = null;
            synchronized(mSpellCheckerMap) {
                try {
                    final int size = mListeners.size();
                    for (int i = 0; i < size; ++i) {
                        if (mListeners.get(i).hasSpellCheckerListener(scListener)) {
                            // 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);
                    scListener.asBinder().linkToDeath(recipient, 0);
                    mListeners.add(new InternalDeathRecipient(
@@ -293,6 +345,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                }
                cleanLocked();
            }
            return recipient;
        }

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

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

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