Show toast when subtype is rotated by Meta-Space.

This follows up to my previous CL [1], with which we changed global
hardware key combinations regarding how multilingual user can manage
multiple keyboard layouts / input methods.  Now we offer Meta-Space to
rotate input method (subtype), while we offered Shift-Space to rotate
hardware keyboard layouts previously.

One thing that is lost during above transition is an indication when the
such a key combination takes effect.  Actually there was a toast that
shows new keyboard layout name, which is now lost.

With this CL, we bring back a toast so that we can show the new input
method (subtype) name. Note that the toast will be shown if all of the
following conditions are met.
 - The input method (subtype) is rotated by a hardware key combination.
 - IME window does not have IME_VISIBLE bit.  Otherwise, showing a toast
   is likely to cause UI overlap with the current IME's window.

  [1]: I4005692215edfcf8bed3e86b1e07000148f986f5
       ae61f7118a92e097e854c840d5726c0920f5db0e

Bug: 27547054
Change-Id: If3fe17adbffe4c1125783fc77fed3cfe78fc7933
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index b8cbf16..811e34e 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -125,6 +125,7 @@
 import android.widget.RadioButton;
 import android.widget.Switch;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -452,6 +453,7 @@
     private AlertDialog.Builder mDialogBuilder;
     private AlertDialog mSwitchingDialog;
     private View mSwitchingDialogTitleView;
+    private Toast mSubtypeSwitchedByShortCutToast;
     private InputMethodInfo[] mIms;
     private int[] mSubtypeIds;
     private LocaleList mLastSystemLocales;
@@ -2952,6 +2954,27 @@
                 return;
             }
             setInputMethodLocked(nextSubtype.mImi.getId(), nextSubtype.mSubtypeId);
+            if (mSubtypeSwitchedByShortCutToast != null) {
+                mSubtypeSwitchedByShortCutToast.cancel();
+                mSubtypeSwitchedByShortCutToast = null;
+            }
+            if ((mImeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+                // IME window is shown.  The user should be able to visually understand that the
+                // subtype is changed in most of cases.  To avoid UI overlap, we do not show a toast
+                // in this case.
+                return;
+            }
+            final InputMethodInfo newInputMethodInfo = mMethodMap.get(mCurMethodId);
+            if (newInputMethodInfo == null) {
+                return;
+            }
+            final CharSequence toastText = InputMethodUtils.getImeAndSubtypeDisplayName(mContext,
+                    newInputMethodInfo, mCurrentSubtype);
+            if (!TextUtils.isEmpty(toastText)) {
+                mSubtypeSwitchedByShortCutToast = Toast.makeText(mContext, toastText.toString(),
+                        Toast.LENGTH_SHORT);
+                mSubtypeSwitchedByShortCutToast.show();
+            }
         }
     }
 
@@ -3823,6 +3846,22 @@
         }
     }
 
+    private static String imeWindowStatusToString(final int imeWindowVis) {
+        final StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        if ((imeWindowVis & InputMethodService.IME_ACTIVE) != 0) {
+            sb.append("Active");
+            first = false;
+        }
+        if ((imeWindowVis & InputMethodService.IME_VISIBLE) != 0) {
+            if (!first) {
+                sb.append("|");
+            }
+            sb.append("Visible");
+        }
+        return sb.toString();
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -3870,6 +3909,7 @@
             method = mCurMethod;
             p.println("  mCurMethod=" + mCurMethod);
             p.println("  mEnabledSession=" + mEnabledSession);
+            p.println("  mImeWindowVis=" + imeWindowStatusToString(mImeWindowVis));
             p.println("  mShowRequested=" + mShowRequested
                     + " mShowExplicitlyRequested=" + mShowExplicitlyRequested
                     + " mShowForced=" + mShowForced