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

Commit 6be6d754 authored by satok's avatar satok
Browse files

Handle the existing binds to spell checkers correctly.

Change-Id: I32efce9f8c09b5a829b0431e8c444fc54b03b440
parent 2043b01b
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) {