Misc fixes to CryptKeeper

- use standard IME, but force it into ASCII if it's the default IME
- provide an IME switcher if there are multiple IME's, in case the
ASCII-capable one is a different one
- make the IME shown by default

Bug: 5004456
Bug: 4698473
Change-Id: Id40a164cfe599bfdb67b81f60d4ab8a52208de88
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index bd456e8..96fdcc9 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1148,7 +1148,8 @@
                   android:immersive="true"
                   android:launchMode="singleTop"
                   android:theme="@android:style/Theme.Holo.NoActionBar"
-                  android:windowSoftInputMode="stateAlwaysHidden">
+                  android:configChanges="mcc|mnc|keyboard|keyboardHidden|uiMode"
+                  android:windowSoftInputMode="stateVisible|adjustResize">
             <intent-filter android:priority="10">
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.HOME" />
diff --git a/res/drawable-hdpi/ic_lockscreen_ime.png b/res/drawable-hdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..29a7989
--- /dev/null
+++ b/res/drawable-hdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_lockscreen_ime.png b/res/drawable-mdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..b27e059
--- /dev/null
+++ b/res/drawable-mdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_lockscreen_ime.png b/res/drawable-xhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..a40ddeb
--- /dev/null
+++ b/res/drawable-xhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/res/layout-land/crypt_keeper_password_entry.xml b/res/layout-land/crypt_keeper_password_entry.xml
new file mode 100644
index 0000000..094434e
--- /dev/null
+++ b/res/layout-land/crypt_keeper_password_entry.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical"
+    >
+        <LinearLayout
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+        >
+            <include layout="@layout/crypt_keeper_status" />
+
+            <!-- Emergency call button.
+                 Text and icon are set by CryptKeeper.updateEmergencyCallButtonState() -->
+            <Button android:id="@+id/emergencyCallButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:layout_margin="16dip"
+                style="@*android:style/Widget.Button.Transparent"
+                android:textSize="14sp"
+                android:drawablePadding="6dip"
+            />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_height="wrap_content"
+            android:layout_width="match_parent"
+            android:layout_marginLeft="8dip"
+            android:layout_marginRight="8dip"
+            android:orientation="horizontal"
+        >
+            <include layout="@layout/crypt_keeper_password_field" />
+        </LinearLayout>
+
+
+    </LinearLayout>
+</ScrollView>
diff --git a/res/layout-sw600dp-land/crypt_keeper_password_entry.xml b/res/layout-sw600dp-land/crypt_keeper_password_entry.xml
index 9415fd1..8898b76 100644
--- a/res/layout-sw600dp-land/crypt_keeper_password_entry.xml
+++ b/res/layout-sw600dp-land/crypt_keeper_password_entry.xml
@@ -46,18 +46,15 @@
         />
 
         <!-- Password entry field -->
-        <view
-            class="com.android.settings.CryptKeeper$CryptEditText"
-            android:id="@+id/passwordEntry"
+        <LinearLayout
             android:layout_height="wrap_content"
             android:layout_width="320dip"
             android:layout_toRightOf="@+id/passwordLabel"
             android:layout_centerVertical="true"
-            android:singleLine="true"
-            android:inputType="textPassword"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:editable="false"
-        />
+            android:orientation="horizontal"
+        >
+            <include layout="@layout/crypt_keeper_password_field" />
+        </LinearLayout>
 
         <TextView android:id="@+id/status"
             android:layout_height="wrap_content"
diff --git a/res/layout-sw600dp/crypt_keeper_password_entry.xml b/res/layout-sw600dp/crypt_keeper_password_entry.xml
index 0610ec0..bc2b353 100644
--- a/res/layout-sw600dp/crypt_keeper_password_entry.xml
+++ b/res/layout-sw600dp/crypt_keeper_password_entry.xml
@@ -45,18 +45,15 @@
         />
 
         <!-- Password entry field -->
-        <view
-            class="com.android.settings.CryptKeeper$CryptEditText"
-            android:id="@+id/passwordEntry"
+        <LinearLayout
             android:layout_height="wrap_content"
             android:layout_width="320dip"
             android:layout_toRightOf="@+id/passwordLabel"
             android:layout_marginTop="26dip"
-            android:singleLine="true"
-            android:inputType="textPassword"
-            android:textAppearance="?android:attr/textAppearanceMedium"
-            android:editable="false"
-        />
+            android:orientation="horizontal"
+        >
+            <include layout="@layout/crypt_keeper_password_field" />
+        </LinearLayout>
 
         <TextView android:id="@+id/status"
             android:layout_height="wrap_content"
@@ -72,13 +69,4 @@
         />
     </RelativeLayout>
 
-    <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true"
-        android:background="#00000000"
-        android:keyBackground="@*android:drawable/btn_keyboard_key_fulltrans"
-        android:visibility="visible"
-    />
-
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/res/layout/crypt_keeper_password_entry.xml b/res/layout/crypt_keeper_password_entry.xml
index a7799fc..1278327 100644
--- a/res/layout/crypt_keeper_password_entry.xml
+++ b/res/layout/crypt_keeper_password_entry.xml
@@ -22,36 +22,28 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
 >
+    <include layout="@layout/crypt_keeper_status" />
+
     <LinearLayout
-           android:layout_height="wrap_content"
-           android:layout_width="match_parent"
-           android:orientation="vertical"
-           android:gravity="center_vertical"
-               >
-       <include layout="@layout/crypt_keeper_status" />
-   </LinearLayout>
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
+        android:layout_marginLeft="8dip"
+        android:layout_marginRight="8dip"
+        android:orientation="horizontal"
+    >
+        <include layout="@layout/crypt_keeper_password_field" />
+    </LinearLayout>
 
-   <EditText android:id="@+id/passwordEntry"
-       android:layout_height="wrap_content"
-       android:layout_width="match_parent"
-       android:layout_marginLeft="8dip"
-       android:layout_marginRight="8dip"
-       android:singleLine="true"
-       android:inputType="textPassword"
-       android:textSize="18sp"
-       android:textAppearance="?android:attr/textAppearanceMedium"
+    <!-- Emergency call button.
+         Text and icon are set by CryptKeeper.updateEmergencyCallButtonState() -->
+    <Button android:id="@+id/emergencyCallButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginTop="16dip"
+        style="@*android:style/Widget.Button.Transparent"
+        android:textSize="14sp"
+        android:drawablePadding="6dip"
     />
 
-   <!-- Emergency call button.
-        Text and icon are set by CryptKeeper.updateEmergencyCallButtonState() -->
-   <Button android:id="@+id/emergencyCallButton"
-       android:layout_width="wrap_content"
-       android:layout_height="wrap_content"
-       android:layout_gravity="center"
-       android:layout_marginTop="16dip"
-       style="@*android:style/Widget.Button.Transparent"
-       android:textSize="14sp"
-       android:drawablePadding="6dip"
-       />
-
 </LinearLayout>
diff --git a/res/layout/crypt_keeper_password_field.xml b/res/layout/crypt_keeper_password_field.xml
new file mode 100644
index 0000000..17968e8
--- /dev/null
+++ b/res/layout/crypt_keeper_password_field.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License")
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Contents of the password entry field for CryptKeeper. Comes with an IME
+     switcher, if necessary. Assumed to be in a horizontal LinearLayout. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <EditText android:id="@+id/passwordEntry"
+        android:layout_height="wrap_content"
+        android:layout_width="0dip"
+        android:layout_weight="1"
+        android:singleLine="true"
+        android:inputType="textPassword"
+        android:imeOptions="actionDone"
+        android:privateImeOptions="com.google.android.inputmethod.latin.forceAscii"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+     />
+
+   <ImageView android:id="@+id/switch_ime_button"
+       android:layout_width="wrap_content"
+       android:layout_height="wrap_content"
+       android:src="@drawable/ic_lockscreen_ime"
+       android:clickable="true"
+       android:padding="8dip"
+       android:layout_gravity="center"
+       android:background="?android:attr/selectableItemBackground"
+       android:visibility="gone"
+   />
+</merge>
diff --git a/res/layout/crypt_keeper_status.xml b/res/layout/crypt_keeper_status.xml
index b830b57..59d2365 100644
--- a/res/layout/crypt_keeper_status.xml
+++ b/res/layout/crypt_keeper_status.xml
@@ -32,7 +32,6 @@
         android:layout_alignParentLeft="true"
         android:layout_marginTop="8dip"
         android:layout_marginBottom="8dip"
-        android:layout_marginLeft="-10dip"
         >
 
         <!-- Because we can't have multi-tone fonts, we render two TextViews, one on
diff --git a/src/com/android/settings/CryptKeeper.java b/src/com/android/settings/CryptKeeper.java
index 0552b68..0c8ce28 100644
--- a/src/com/android/settings/CryptKeeper.java
+++ b/src/com/android/settings/CryptKeeper.java
@@ -22,8 +22,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
-import android.graphics.Rect;
-import android.inputmethodservice.KeyboardView;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -36,22 +34,22 @@
 import android.os.storage.IMountService;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
-import android.util.AttributeSet;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.InputMethodSubtype;
 import android.widget.Button;
 import android.widget.EditText;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
 import com.android.internal.telephony.ITelephony;
-import com.android.internal.widget.PasswordEntryKeyboardHelper;
-import com.android.internal.widget.PasswordEntryKeyboardView;
+
+import java.util.List;
 
 /**
  * Settings screens to show the UI flows for encrypting/decrypting the device.
@@ -112,37 +110,6 @@
         }
     }
 
-    // Use a custom EditText to prevent the input method from showing.
-    public static class CryptEditText extends EditText {
-        InputMethodManager imm;
-
-        public CryptEditText(Context context, AttributeSet attrs) {
-            super(context, attrs);
-            imm = ((InputMethodManager) getContext().
-                    getSystemService(Context.INPUT_METHOD_SERVICE));
-        }
-
-        @Override
-        protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
-            super.onFocusChanged(focused, direction, previouslyFocusedRect);
-
-            if (focused && imm != null && imm.isActive(this)) {
-                imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0);
-            }
-        }
-
-        @Override
-        public boolean onTouchEvent(MotionEvent event) {
-            boolean handled = super.onTouchEvent(event);
-
-            if (imm != null && imm.isActive(this)) {
-                imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0);
-            }
-
-            return handled;
-        }
-    }
-
     private class DecryptTask extends AsyncTask<String, Void, Integer> {
         @Override
         protected Integer doInBackground(String... params) {
@@ -387,18 +354,79 @@
     private void passwordEntryInit() {
         mPasswordEntry = (EditText) findViewById(R.id.passwordEntry);
         mPasswordEntry.setOnEditorActionListener(this);
+        mPasswordEntry.requestFocus();
 
-        KeyboardView keyboardView = (PasswordEntryKeyboardView) findViewById(R.id.keyboard);
-
-        if (keyboardView != null) {
-            PasswordEntryKeyboardHelper keyboardHelper = new PasswordEntryKeyboardHelper(this,
-                    keyboardView, mPasswordEntry, false);
-            keyboardHelper.setKeyboardMode(PasswordEntryKeyboardHelper.KEYBOARD_MODE_ALPHA);
+        View imeSwitcher = findViewById(R.id.switch_ime_button);
+        final InputMethodManager imm = (InputMethodManager) getSystemService(
+                Context.INPUT_METHOD_SERVICE);
+        if (imeSwitcher != null && hasMultipleEnabledIMEsOrSubtypes(imm, false)) {
+            imeSwitcher.setVisibility(View.VISIBLE);
+            imeSwitcher.setOnClickListener(new OnClickListener() {
+                public void onClick(View v) {
+                    imm.showInputMethodPicker();
+                }
+            });
         }
 
+        // Asynchronously throw up the IME, since there are issues with requesting it to be shown
+        // immediately.
+        mHandler.postDelayed(new Runnable() {
+            @Override public void run() {
+                imm.showSoftInputUnchecked(0, null);
+            }
+        }, 0);
+
         updateEmergencyCallButtonState();
     }
 
+    /**
+     * Method adapted from com.android.inputmethod.latin.Utils
+     *
+     * @param imm The input method manager
+     * @param shouldIncludeAuxiliarySubtypes
+     * @return true if we have multiple IMEs to choose from
+     */
+    private boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManager imm,
+            final boolean shouldIncludeAuxiliarySubtypes) {
+        final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
+
+        // Number of the filtered IMEs
+        int filteredImisCount = 0;
+
+        for (InputMethodInfo imi : enabledImis) {
+            // We can return true immediately after we find two or more filtered IMEs.
+            if (filteredImisCount > 1) return true;
+            final List<InputMethodSubtype> subtypes =
+                    imm.getEnabledInputMethodSubtypeList(imi, true);
+            // IMEs that have no subtypes should be counted.
+            if (subtypes.isEmpty()) {
+                ++filteredImisCount;
+                continue;
+            }
+
+            int auxCount = 0;
+            for (InputMethodSubtype subtype : subtypes) {
+                if (subtype.isAuxiliary()) {
+                    ++auxCount;
+                }
+            }
+            final int nonAuxCount = subtypes.size() - auxCount;
+
+            // IMEs that have one or more non-auxiliary subtypes should be counted.
+            // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
+            // subtypes should be counted as well.
+            if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
+                ++filteredImisCount;
+                continue;
+            }
+        }
+
+        return filteredImisCount > 1
+        // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled
+        // input method subtype (The current IME should be LatinIME.)
+                || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1;
+    }
+
     private IMountService getMountService() {
         IBinder service = ServiceManager.getService("mount");
         if (service != null) {