merge in ics-mr0-release history after reset to ics-mr0
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index 2ecf307..1ad851d 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -146,6 +146,15 @@
         public void onCancel() {}
 
         /**
+         * @hide
+         * Request to close this session.
+         * This function will run on the incoming IPC thread.
+         * So, this is not called on the main thread,
+         * but will be called in series on another thread.
+         */
+        public void onClose() {}
+
+        /**
          * @return Locale for this session
          */
         public String getLocale() {
@@ -162,7 +171,7 @@
 
     // Preventing from exposing ISpellCheckerSession.aidl, create an internal class.
     private static class InternalISpellCheckerSession extends ISpellCheckerSession.Stub {
-        private final ISpellCheckerSessionListener mListener;
+        private ISpellCheckerSessionListener mListener;
         private final Session mSession;
         private final String mLocale;
         private final Bundle mBundle;
@@ -192,6 +201,12 @@
             mSession.onCancel();
         }
 
+        @Override
+        public void onClose() {
+            mSession.onClose();
+            mListener = null;
+        }
+
         public String getLocale() {
             return mLocale;
         }
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 793f514..a80f4a3 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -152,6 +152,7 @@
     public void close() {
         mIsUsed = false;
         try {
+            mSpellCheckerSessionListenerImpl.close();
             mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl);
         } catch (RemoteException e) {
             // do nothing
@@ -190,9 +191,10 @@
     private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub {
         private static final int TASK_CANCEL = 1;
         private static final int TASK_GET_SUGGESTIONS_MULTIPLE = 2;
+        private static final int TASK_CLOSE = 3;
         private final Queue<SpellCheckerParams> mPendingTasks =
                 new LinkedList<SpellCheckerParams>();
-        private final Handler mHandler;
+        private Handler mHandler;
 
         private boolean mOpened;
         private ISpellCheckerSession mISpellCheckerSession;
@@ -224,6 +226,9 @@
                 case TASK_GET_SUGGESTIONS_MULTIPLE:
                     processGetSuggestionsMultiple(scp);
                     break;
+                case TASK_CLOSE:
+                    processClose();
+                    break;
             }
         }
 
@@ -247,6 +252,13 @@
                             suggestionsLimit, sequentialWords));
         }
 
+        public void close() {
+            if (DBG) {
+                Log.w(TAG, "close");
+            }
+            processOrEnqueueTask(new SpellCheckerParams(TASK_CLOSE, null, 0, false));
+        }
+
         public boolean isDisconnected() {
             return mOpened && mISpellCheckerSession == null;
         }
@@ -284,6 +296,22 @@
             }
         }
 
+        private void processClose() {
+            if (!checkOpenConnection()) {
+                return;
+            }
+            if (DBG) {
+                Log.w(TAG, "Close spell checker tasks.");
+            }
+            try {
+                mISpellCheckerSession.onClose();
+                mISpellCheckerSession = null;
+                mHandler = null;
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to close " + e);
+            }
+        }
+
         private void processGetSuggestionsMultiple(SpellCheckerParams scp) {
             if (!checkOpenConnection()) {
                 return;
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
index 5a00603..3c61968 100644
--- a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
@@ -25,4 +25,5 @@
     void onGetSuggestionsMultiple(
             in TextInfo[] textInfos, int suggestionsLimit, boolean multipleWords);
     void onCancel();
+    void onClose();
 }
diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java
index 1976eba..373b11c 100644
--- a/services/java/com/android/server/TextServicesManagerService.java
+++ b/services/java/com/android/server/TextServicesManagerService.java
@@ -334,7 +334,7 @@
         }
         final String sciId = info.getId();
         final InternalServiceConnection connection = new InternalServiceConnection(
-                sciId, locale, scListener, bundle);
+                sciId, locale, bundle);
         final Intent serviceIntent = new Intent(SpellCheckerService.SERVICE_INTERFACE);
         serviceIntent.setComponent(info.getComponent());
         if (DBG) {
@@ -635,7 +635,9 @@
                     if (DBG) {
                         Slog.w(TAG, "Remove " + removeList.get(i));
                     }
-                    mListeners.remove(removeList.get(i));
+                    final InternalDeathRecipient idr = removeList.get(i);
+                    idr.mScListener.asBinder().unlinkToDeath(idr, 0);
+                    mListeners.remove(idr);
                 }
                 cleanLocked();
             }
@@ -664,6 +666,11 @@
         public void removeAll() {
             Slog.e(TAG, "Remove the spell checker bind unexpectedly.");
             synchronized(mSpellCheckerMap) {
+                final int size = mListeners.size();
+                for (int i = 0; i < size; ++i) {
+                    final InternalDeathRecipient idr = mListeners.get(i);
+                    idr.mScListener.asBinder().unlinkToDeath(idr, 0);
+                }
                 mListeners.clear();
                 cleanLocked();
             }
@@ -671,15 +678,13 @@
     }
 
     private class InternalServiceConnection implements ServiceConnection {
-        private final ISpellCheckerSessionListener mListener;
         private final String mSciId;
         private final String mLocale;
         private final Bundle mBundle;
         public InternalServiceConnection(
-                String id, String locale, ISpellCheckerSessionListener listener, Bundle bundle) {
+                String id, String locale, Bundle bundle) {
             mSciId = id;
             mLocale = locale;
-            mListener = listener;
             mBundle = bundle;
         }