Add IC#closeConnection().

It turns out that BaseInputConnection has still depended on a private
API named BaseInputConnection#reportFinish(), which was introduced
4 years ago to work around a UI freeze due to an unbalanced batch edit
count [1].  Note that such an unbalanced batch edit count cannot always
be avoidable.  It can easily occur in the following situations.
 - The current IME crashed during batch edit.
 - The user changed the View focus during batch edit.
 - The current IME called IMM#switchToNextInputMethod() during batch
   edit.

The remaining problem is that #reportFinish() is still an internal API
and only subclasses of BaseInputConnection can implement it, and IMM
calls it when and only when the current InputConnection is
BaseInputConnection or its subclass.  InputConnectionWrapper and any
other InputConnection implementations will never receive such a callback
to clean up InputConnection#{begin, end}BatchEdit(), which is considered
to be a major contributor to UI freeze.

To address the above issue, we unhide BaseInputConnection#reportFinish()
as InputConnection#closeConnection() so that application developers can
receive an appropriate callback to clean up internal state including
unfinished batch edit.

  [1] I5525d776916f0c42d5e6d4a4282aed590d7f0e9a
      9d69ecbf61a4a142c3f4cbb9d5659faa6f85e832

Bug: 24688781
Bug: 25332806
Change-Id: I234309c5880c9fe0b299b8bd0f8862796d4dda0d
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 6c1ebb4..3a4afad 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -27,13 +27,12 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.inputmethod.BaseInputConnection;
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
-
-import java.lang.ref.WeakReference;
+import android.view.inputmethod.InputConnectionInspector;
+import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
 
 public abstract class IInputConnectionWrapper extends IInputContext.Stub {
     static final String TAG = "IInputConnectionWrapper";
@@ -61,7 +60,7 @@
     private static final int DO_PERFORM_PRIVATE_COMMAND = 120;
     private static final int DO_CLEAR_META_KEY_STATES = 130;
     private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
-    private static final int DO_REPORT_FINISH = 150;
+    private static final int DO_CLOSE_CONNECTION = 150;
 
     @GuardedBy("mLock")
     @Nullable
@@ -222,8 +221,8 @@
                 seq, callback));
     }
 
-    public void reportFinish() {
-        dispatchMessage(obtainMessage(DO_REPORT_FINISH));
+    public void closeConnection() {
+        dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
     }
 
     void dispatchMessage(Message msg) {
@@ -501,10 +500,10 @@
                 }
                 return;
             }
-            case DO_REPORT_FINISH: {
+            case DO_CLOSE_CONNECTION: {
                 // Note that we do not need to worry about race condition here, because 1) mFinished
                 // is updated only inside this block, and 2) the code here is running on a Handler
-                // hence we assume multiple DO_REPORT_FINISH messages will not be handled at the
+                // hence we assume multiple DO_CLOSE_CONNECTION messages will not be handled at the
                 // same time.
                 if (isFinished()) {
                     return;
@@ -518,11 +517,10 @@
                     if (ic == null) {
                         return;
                     }
-                    ic.finishComposingText();
-                    // TODO: Make reportFinish() public method of InputConnection to remove this
-                    // check.
-                    if (ic instanceof BaseInputConnection) {
-                        ((BaseInputConnection) ic).reportFinish();
+                    @MissingMethodFlags
+                    final int missingMethods = InputConnectionInspector.getMissingMethodFlags(ic);
+                    if ((missingMethods & MissingMethodFlags.CLOSE_CONNECTION) == 0) {
+                        ic.closeConnection();
                     }
                 } finally {
                     synchronized (mLock) {