am 3fe1708d: Merge "Fix isssue 2548710: Native AudioTrack resources never freed." into froyo

Merge commit '3fe1708d9d204fa63e8abe6e434378d89e963752' into froyo-plus-aosp

* commit '3fe1708d9d204fa63e8abe6e434378d89e963752':
  Fix isssue 2548710: Native AudioTrack resources never freed.
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index 80e9865..44f30f7 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -47,9 +47,10 @@
     private static final int DO_UPDATE_CURSOR = 95;
     private static final int DO_APP_PRIVATE_COMMAND = 100;
     private static final int DO_TOGGLE_SOFT_INPUT = 105;
-   
-    final HandlerCaller mCaller;
-    final InputMethodSession mInputMethodSession;
+    private static final int DO_FINISH_SESSION = 110;
+
+    HandlerCaller mCaller;
+    InputMethodSession mInputMethodSession;
     
     // NOTE: we should have a cache of these.
     static class InputMethodEventCallbackWrapper implements InputMethodSession.EventCallback {
@@ -127,6 +128,10 @@
                 mInputMethodSession.toggleSoftInput(msg.arg1, msg.arg2);
                 return;
             }
+            case DO_FINISH_SESSION: {
+                mInputMethodSession = null;
+                return;
+            }
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
@@ -174,4 +179,8 @@
     public void toggleSoftInput(int showFlags, int hideFlags) {
         mCaller.executeOrSendMessage(mCaller.obtainMessageII(DO_TOGGLE_SOFT_INPUT, showFlags, hideFlags));
     }
+
+    public void finishSession() {
+        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_FINISH_SESSION));
+    }
 }
diff --git a/core/java/android/inputmethodservice/IInputMethodWrapper.java b/core/java/android/inputmethodservice/IInputMethodWrapper.java
index bfa82ee..35fd46f 100644
--- a/core/java/android/inputmethodservice/IInputMethodWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodWrapper.java
@@ -39,6 +39,7 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -64,9 +65,9 @@
     private static final int DO_SHOW_SOFT_INPUT = 60;
     private static final int DO_HIDE_SOFT_INPUT = 70;
    
-    final AbstractInputMethodService mTarget;
+    final WeakReference<AbstractInputMethodService> mTarget;
     final HandlerCaller mCaller;
-    final InputMethod mInputMethod;
+    final WeakReference<InputMethod> mInputMethod;
     
     static class Notifier {
         boolean notified;
@@ -96,21 +97,32 @@
     
     public IInputMethodWrapper(AbstractInputMethodService context,
             InputMethod inputMethod) {
-        mTarget = context;
-        mCaller = new HandlerCaller(context, this);
-        mInputMethod = inputMethod;
+        mTarget = new WeakReference<AbstractInputMethodService>(context);
+        mCaller = new HandlerCaller(context.getApplicationContext(), this);
+        mInputMethod = new WeakReference<InputMethod>(inputMethod);
     }
 
     public InputMethod getInternalInputMethod() {
-        return mInputMethod;
+        return mInputMethod.get();
     }
 
     public void executeMessage(Message msg) {
+        InputMethod inputMethod = mInputMethod.get();
+        // Need a valid reference to the inputMethod for everything except a dump.
+        if (inputMethod == null && msg.what != DO_DUMP) {
+            Log.w(TAG, "Input method reference was null, ignoring message: " + msg.what);
+            return;
+        }
+
         switch (msg.what) {
             case DO_DUMP: {
+                AbstractInputMethodService target = mTarget.get();
+                if (target == null) {
+                    return;
+                }
                 HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
                 try {
-                    mTarget.dump((FileDescriptor)args.arg1,
+                    target.dump((FileDescriptor)args.arg1,
                             (PrintWriter)args.arg2, (String[])args.arg3);
                 } catch (RuntimeException e) {
                     ((PrintWriter)args.arg2).println("Exception: " + e);
@@ -122,22 +134,22 @@
             }
             
             case DO_ATTACH_TOKEN: {
-                mInputMethod.attachToken((IBinder)msg.obj);
+                inputMethod.attachToken((IBinder)msg.obj);
                 return;
             }
             case DO_SET_INPUT_CONTEXT: {
-                mInputMethod.bindInput((InputBinding)msg.obj);
+                inputMethod.bindInput((InputBinding)msg.obj);
                 return;
             }
             case DO_UNSET_INPUT_CONTEXT:
-                mInputMethod.unbindInput();
+                inputMethod.unbindInput();
                 return;
             case DO_START_INPUT: {
                 HandlerCaller.SomeArgs args = (HandlerCaller.SomeArgs)msg.obj;
                 IInputContext inputContext = (IInputContext)args.arg1;
                 InputConnection ic = inputContext != null
                         ? new InputConnectionWrapper(inputContext) : null;
-                mInputMethod.startInput(ic, (EditorInfo)args.arg2);
+                inputMethod.startInput(ic, (EditorInfo)args.arg2);
                 return;
             }
             case DO_RESTART_INPUT: {
@@ -145,33 +157,37 @@
                 IInputContext inputContext = (IInputContext)args.arg1;
                 InputConnection ic = inputContext != null
                         ? new InputConnectionWrapper(inputContext) : null;
-                mInputMethod.restartInput(ic, (EditorInfo)args.arg2);
+                inputMethod.restartInput(ic, (EditorInfo)args.arg2);
                 return;
             }
             case DO_CREATE_SESSION: {
-                mInputMethod.createSession(new InputMethodSessionCallbackWrapper(
+                inputMethod.createSession(new InputMethodSessionCallbackWrapper(
                         mCaller.mContext, (IInputMethodCallback)msg.obj));
                 return;
             }
             case DO_SET_SESSION_ENABLED:
-                mInputMethod.setSessionEnabled((InputMethodSession)msg.obj,
+                inputMethod.setSessionEnabled((InputMethodSession)msg.obj,
                         msg.arg1 != 0);
                 return;
             case DO_REVOKE_SESSION:
-                mInputMethod.revokeSession((InputMethodSession)msg.obj);
+                inputMethod.revokeSession((InputMethodSession)msg.obj);
                 return;
             case DO_SHOW_SOFT_INPUT:
-                mInputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj);
+                inputMethod.showSoftInput(msg.arg1, (ResultReceiver)msg.obj);
                 return;
             case DO_HIDE_SOFT_INPUT:
-                mInputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj);
+                inputMethod.hideSoftInput(msg.arg1, (ResultReceiver)msg.obj);
                 return;
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
     
     @Override protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
-        if (mTarget.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+        AbstractInputMethodService target = mTarget.get();
+        if (target == null) {
+            return;
+        }
+        if (target.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
             
             fout.println("Permission Denial: can't dump InputMethodManager from from pid="
diff --git a/core/java/android/text/method/PasswordTransformationMethod.java b/core/java/android/text/method/PasswordTransformationMethod.java
index fad4f64..b769b76 100644
--- a/core/java/android/text/method/PasswordTransformationMethod.java
+++ b/core/java/android/text/method/PasswordTransformationMethod.java
@@ -51,6 +51,8 @@
                 sp.removeSpan(vr[i]);
             }
 
+            removeVisibleSpans(sp);
+
             sp.setSpan(new ViewReference(view), 0, 0,
                        Spannable.SPAN_POINT_POINT);
         }
@@ -100,10 +102,7 @@
             int pref = TextKeyListener.getInstance().getPrefs(v.getContext());
             if ((pref & TextKeyListener.SHOW_PASSWORD) != 0) {
                 if (count > 0) {
-                    Visible[] old = sp.getSpans(0, sp.length(), Visible.class);
-                    for (int i = 0; i < old.length; i++) {
-                        sp.removeSpan(old[i]);
-                    }
+                    removeVisibleSpans(sp);
 
                     if (count == 1) {
                         sp.setSpan(new Visible(sp, this), start, start + count,
@@ -125,14 +124,18 @@
             if (sourceText instanceof Spannable) {
                 Spannable sp = (Spannable) sourceText;
 
-                Visible[] old = sp.getSpans(0, sp.length(), Visible.class);
-                for (int i = 0; i < old.length; i++) {
-                    sp.removeSpan(old[i]);
-                }
+                removeVisibleSpans(sp);
             }
         }
     }
 
+    private static void removeVisibleSpans(Spannable sp) {
+        Visible[] old = sp.getSpans(0, sp.length(), Visible.class);
+        for (int i = 0; i < old.length; i++) {
+            sp.removeSpan(old[i]);
+        }
+    }
+
     private static class PasswordCharSequence
     implements CharSequence, GetChars
     {
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index a05ff14..338dcaa 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -48,4 +48,6 @@
     void appPrivateCommand(String action, in Bundle data);
 
     void toggleSoftInput(int showFlags, int hideFlags);
+
+    void finishSession();
 }
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 5cefaa3..a50693d 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -30,7 +30,8 @@
  * (green << 8) | blue. Each component ranges between 0..255 with 0
  * meaning no contribution for that component, and 255 meaning 100%
  * contribution. Thus opaque-black would be 0xFF000000 (100% opaque but
- * no contributes from red, gree, blue, and opaque-white would be 0xFFFFFFFF
+ * no contributions from red, green, or blue), and opaque-white would be
+ * 0xFFFFFFFF
  */
 public class Color {
     public static final int BLACK       = 0xFF000000;
diff --git a/opengl/tests/gl_jni/jni/gl_code.cpp b/opengl/tests/gl_jni/jni/gl_code.cpp
index 33b25ab..f031c79 100644
--- a/opengl/tests/gl_jni/jni/gl_code.cpp
+++ b/opengl/tests/gl_jni/jni/gl_code.cpp
@@ -180,4 +180,5 @@
 JNIEXPORT void JNICALL Java_com_android_gljni_GLJNILib_changeBackground(JNIEnv * env, jobject obj)
 {
     background = 1.0f - background;
-}
\ No newline at end of file
+}
+
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 0c205ca..5bf66e4 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -889,13 +889,27 @@
                     MSG_UNBIND_METHOD, mCurSeq, mCurClient.client));
         }
     }
+    
+    private void finishSession(SessionState sessionState) {
+        if (sessionState != null && sessionState.session != null) {
+            try {
+                sessionState.session.finishSession();
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Session failed to close due to remote exception", e);
+            }
+        }
+    }
 
     void clearCurMethodLocked() {
         if (mCurMethod != null) {
             for (ClientState cs : mClients.values()) {
                 cs.sessionRequested = false;
+                finishSession(cs.curSession);
                 cs.curSession = null;
             }
+
+            finishSession(mEnabledSession);
+            mEnabledSession = null;
             mCurMethod = null;
         }
         mStatusBar.setIconVisibility(mInputMethodIcon, false);