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

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

Merge "Fix issues in TextServicesManagerService"

parents 3970f683 df5659d3
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -32,5 +32,6 @@ interface ITextServicesManager {
            in ITextServicesSessionListener tsListener,
            in ITextServicesSessionListener tsListener,
            in ISpellCheckerSessionListener scListener);
            in ISpellCheckerSessionListener scListener);
    oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
    oneway void finishSpellCheckerService(in ISpellCheckerSessionListener listener);
    oneway void setCurrentSpellChecker(in SpellCheckerInfo info);
    SpellCheckerInfo[] getEnabledSpellCheckers();
    SpellCheckerInfo[] getEnabledSpellCheckers();
}
}
+78 −32
Original line number Original line Diff line number Diff line
@@ -73,6 +73,16 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
        synchronized (mSpellCheckerMap) {
        synchronized (mSpellCheckerMap) {
            buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap);
            buildSpellCheckerMapLocked(context, mSpellCheckerList, mSpellCheckerMap);
        }
        }
        SpellCheckerInfo sci = getCurrentSpellChecker(null);
        if (sci == null) {
            sci = findAvailSpellCheckerLocked(null, null);
            if (sci != null) {
                // Set the current spell checker if there is one or more spell checkers
                // available. In this case, "sci" is the first one in the available spell
                // checkers.
                setCurrentSpellCheckerLocked(sci);
            }
        }
    }
    }


    private class TextServicesMonitor extends PackageMonitor {
    private class TextServicesMonitor extends PackageMonitor {
@@ -87,10 +97,10 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                final int change = isPackageDisappearing(packageName);
                final int change = isPackageDisappearing(packageName);
                if (change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE) {
                if (change == PACKAGE_PERMANENT_CHANGE || change == PACKAGE_TEMPORARY_CHANGE) {
                    // Package disappearing
                    // Package disappearing
                    setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName));
                    setCurrentSpellCheckerLocked(findAvailSpellCheckerLocked(null, packageName));
                } else if (isPackageModified(packageName)) {
                } else if (isPackageModified(packageName)) {
                    // Package modified
                    // Package modified
                    setCurrentSpellChecker(findAvailSpellCheckerLocked(null, packageName));
                    setCurrentSpellCheckerLocked(findAvailSpellCheckerLocked(null, packageName));
                }
                }
            }
            }
        }
        }
@@ -160,13 +170,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId);
                Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId);
            }
            }
            if (TextUtils.isEmpty(curSpellCheckerId)) {
            if (TextUtils.isEmpty(curSpellCheckerId)) {
                final SpellCheckerInfo sci = findAvailSpellCheckerLocked(null, null);
                return null;
                if (sci == null) return null;
                // Set the current spell checker if there is one or more spell checkers
                // available. In this case, "sci" is the first one in the available spell
                // checkers.
                setCurrentSpellChecker(sci);
                return sci;
            }
            }
            return mSpellCheckerMap.get(curSpellCheckerId);
            return mSpellCheckerMap.get(curSpellCheckerId);
        }
        }
@@ -187,12 +191,13 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
            if (!mSpellCheckerMap.containsKey(sciId)) {
            if (!mSpellCheckerMap.containsKey(sciId)) {
                return;
                return;
            }
            }
            final int uid = Binder.getCallingUid();
            if (mSpellCheckerBindGroups.containsKey(sciId)) {
            if (mSpellCheckerBindGroups.containsKey(sciId)) {
                final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId);
                final SpellCheckerBindGroup bindGroup = mSpellCheckerBindGroups.get(sciId);
                if (bindGroup != null) {
                if (bindGroup != null) {
                    final InternalDeathRecipient recipient =
                    final InternalDeathRecipient recipient =
                            mSpellCheckerBindGroups.get(sciId).addListener(
                            mSpellCheckerBindGroups.get(sciId).addListener(
                                    tsListener, locale, scListener);
                                    tsListener, locale, scListener, uid);
                    if (recipient == null) {
                    if (recipient == null) {
                        if (DBG) {
                        if (DBG) {
                            Slog.w(TAG, "Didn't create a death recipient.");
                            Slog.w(TAG, "Didn't create a death recipient.");
@@ -204,14 +209,22 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                        bindGroup.removeAll();
                        bindGroup.removeAll();
                    } else if (bindGroup.mSpellChecker != null) {
                    } else if (bindGroup.mSpellChecker != null) {
                        if (DBG) {
                        if (DBG) {
                            Slog.w(TAG, "Existing bind found. Return a spell checker session now.");
                            Slog.w(TAG, "Existing bind found. Return a spell checker session now. "
                                    + "Listeners count = " + bindGroup.mListeners.size());
                        }
                        }
                        try {
                        try {
                            final ISpellCheckerSession session =
                            final ISpellCheckerSession session =
                                    bindGroup.mSpellChecker.getISpellCheckerSession(
                                    bindGroup.mSpellChecker.getISpellCheckerSession(
                                            recipient.mScLocale, recipient.mScListener);
                                            recipient.mScLocale, recipient.mScListener);
                            if (session != null) {
                                tsListener.onServiceConnected(session);
                                tsListener.onServiceConnected(session);
                                return;
                                return;
                            } else {
                                if (DBG) {
                                    Slog.w(TAG, "Existing bind already expired. ");
                                }
                                bindGroup.removeAll();
                            }
                        } catch (RemoteException e) {
                        } catch (RemoteException e) {
                            Slog.e(TAG, "Exception in getting spell checker session: " + e);
                            Slog.e(TAG, "Exception in getting spell checker session: " + e);
                            bindGroup.removeAll();
                            bindGroup.removeAll();
@@ -221,7 +234,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
            }
            }
            final long ident = Binder.clearCallingIdentity();
            final long ident = Binder.clearCallingIdentity();
            try {
            try {
                startSpellCheckerServiceInnerLocked(info, locale, tsListener, scListener);
                startSpellCheckerServiceInnerLocked(info, locale, tsListener, scListener, uid);
            } finally {
            } finally {
                Binder.restoreCallingIdentity(ident);
                Binder.restoreCallingIdentity(ident);
            }
            }
@@ -230,7 +243,11 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
    }
    }


    private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale,
    private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale,
            ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener) {
            ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener,
            int uid) {
        if (DBG) {
            Slog.w(TAG, "Start spell checker session inner locked.");
        }
        final String sciId = info.getId();
        final String sciId = info.getId();
        final InternalServiceConnection connection = new InternalServiceConnection(
        final InternalServiceConnection connection = new InternalServiceConnection(
                sciId, locale, scListener);
                sciId, locale, scListener);
@@ -244,7 +261,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
            return;
            return;
        }
        }
        final SpellCheckerBindGroup group = new SpellCheckerBindGroup(
        final SpellCheckerBindGroup group = new SpellCheckerBindGroup(
                connection, tsListener, locale, scListener);
                connection, tsListener, locale, scListener, uid);
        mSpellCheckerBindGroups.put(sciId, group);
        mSpellCheckerBindGroups.put(sciId, group);
    }
    }


@@ -272,19 +289,39 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
        }
        }
    }
    }


    private void setCurrentSpellChecker(SpellCheckerInfo sci) {
    @Override
    public void setCurrentSpellChecker(SpellCheckerInfo sci) {
        synchronized(mSpellCheckerMap) {
            if (mContext.checkCallingOrSelfPermission(
                    android.Manifest.permission.WRITE_SECURE_SETTINGS)
                    != PackageManager.PERMISSION_GRANTED) {
                throw new SecurityException(
                        "Requires permission "
                        + android.Manifest.permission.WRITE_SECURE_SETTINGS);
            }
            setCurrentSpellCheckerLocked(sci);
        }
    }

    private void setCurrentSpellCheckerLocked(SpellCheckerInfo sci) {
        if (DBG) {
        if (DBG) {
            Slog.w(TAG, "setCurrentSpellChecker: " + sci.getId());
            Slog.w(TAG, "setCurrentSpellChecker: " + sci.getId());
        }
        }
        if (sci == null || mSpellCheckerMap.containsKey(sci.getId())) return;
        if (sci == null || !mSpellCheckerMap.containsKey(sci.getId())) return;
        final long ident = Binder.clearCallingIdentity();
        try {
            Settings.Secure.putString(mContext.getContentResolver(),
            Settings.Secure.putString(mContext.getContentResolver(),
                    Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId());
                    Settings.Secure.SPELL_CHECKER_SERVICE, sci == null ? "" : sci.getId());
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
    }
    }


    // SpellCheckerBindGroup contains active text service session listeners.
    // SpellCheckerBindGroup contains active text service session listeners.
    // 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 {
        private final String TAG = SpellCheckerBindGroup.class.getSimpleName();
        private final InternalServiceConnection mInternalConnection;
        private final InternalServiceConnection mInternalConnection;
        private final ArrayList<InternalDeathRecipient> mListeners =
        private final ArrayList<InternalDeathRecipient> mListeners =
                new ArrayList<InternalDeathRecipient>();
                new ArrayList<InternalDeathRecipient>();
@@ -293,10 +330,10 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {


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


        public void onServiceConnected(ISpellCheckerService spellChecker) {
        public void onServiceConnected(ISpellCheckerService spellChecker) {
@@ -310,7 +347,7 @@ 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);
                        Slog.e(TAG, "Exception in getting the spell checker session: " + e);
                        removeAll();
                        removeAll();
                        return;
                        return;
                    }
                    }
@@ -321,7 +358,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
        }
        }


        public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener,
        public InternalDeathRecipient addListener(ITextServicesSessionListener tsListener,
                String locale, ISpellCheckerSessionListener scListener) {
                String locale, ISpellCheckerSessionListener scListener, int uid) {
            if (DBG) {
            if (DBG) {
                Slog.d(TAG, "addListener: " + locale);
                Slog.d(TAG, "addListener: " + locale);
            }
            }
@@ -336,10 +373,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                        }
                        }
                    }
                    }
                    recipient = new InternalDeathRecipient(
                    recipient = new InternalDeathRecipient(
                            this, tsListener, locale, scListener);
                            this, tsListener, locale, scListener, uid);
                    scListener.asBinder().linkToDeath(recipient, 0);
                    scListener.asBinder().linkToDeath(recipient, 0);
                    mListeners.add(new InternalDeathRecipient(
                    mListeners.add(recipient);
                            this, tsListener, locale, scListener));
                } catch(RemoteException e) {
                } catch(RemoteException e) {
                    // do nothing
                    // do nothing
                }
                }
@@ -350,7 +386,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {


        public void removeListener(ISpellCheckerSessionListener listener) {
        public void removeListener(ISpellCheckerSessionListener listener) {
            if (DBG) {
            if (DBG) {
                Slog.d(TAG, "remove listener");
                Slog.w(TAG, "remove listener: " + listener.hashCode());
            }
            }
            synchronized(mSpellCheckerMap) {
            synchronized(mSpellCheckerMap) {
                final int size = mListeners.size();
                final int size = mListeners.size();
@@ -359,11 +395,17 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
                for (int i = 0; i < size; ++i) {
                for (int i = 0; i < size; ++i) {
                    final InternalDeathRecipient tempRecipient = mListeners.get(i);
                    final InternalDeathRecipient tempRecipient = mListeners.get(i);
                    if(tempRecipient.hasSpellCheckerListener(listener)) {
                    if(tempRecipient.hasSpellCheckerListener(listener)) {
                        if (DBG) {
                            Slog.w(TAG, "found existing listener.");
                        }
                        removeList.add(tempRecipient);
                        removeList.add(tempRecipient);
                    }
                    }
                }
                }
                final int removeSize = removeList.size();
                final int removeSize = removeList.size();
                for (int i = 0; i < removeSize; ++i) {
                for (int i = 0; i < removeSize; ++i) {
                    if (DBG) {
                        Slog.w(TAG, "Remove " + removeList.get(i));
                    }
                    mListeners.remove(removeList.get(i));
                    mListeners.remove(removeList.get(i));
                }
                }
                cleanLocked();
                cleanLocked();
@@ -385,10 +427,12 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {


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


    private class InternalServiceConnection implements ServiceConnection {
    private class InternalServiceConnection implements ServiceConnection {
        private final ISpellCheckerSessionListener mListener;
        private final ISpellCheckerSessionListener mListener;
@@ -426,17 +470,19 @@ public class TextServicesManagerService extends ITextServicesManager.Stub {
        public final ISpellCheckerSessionListener mScListener;
        public final ISpellCheckerSessionListener mScListener;
        public final String mScLocale;
        public final String mScLocale;
        private final SpellCheckerBindGroup mGroup;
        private final SpellCheckerBindGroup mGroup;
        public final int mUid;
        public InternalDeathRecipient(SpellCheckerBindGroup group,
        public InternalDeathRecipient(SpellCheckerBindGroup group,
                ITextServicesSessionListener tsListener, String scLocale,
                ITextServicesSessionListener tsListener, String scLocale,
                ISpellCheckerSessionListener scListener) {
                ISpellCheckerSessionListener scListener, int uid) {
            mTsListener = tsListener;
            mTsListener = tsListener;
            mScListener = scListener;
            mScListener = scListener;
            mScLocale = scLocale;
            mScLocale = scLocale;
            mGroup = group;
            mGroup = group;
            mUid = uid;
        }
        }


        public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) {
        public boolean hasSpellCheckerListener(ISpellCheckerSessionListener listener) {
            return mScListener.equals(listener);
            return listener.asBinder().equals(mScListener.asBinder());
        }
        }


        @Override
        @Override