Merge "Use window context to create the touch overlay" into rvc-qpr-dev
diff --git a/src/com/android/car/rotary/RotaryService.java b/src/com/android/car/rotary/RotaryService.java
index 1a7f63e..d4facc4 100644
--- a/src/com/android/car/rotary/RotaryService.java
+++ b/src/com/android/car/rotary/RotaryService.java
@@ -56,8 +56,8 @@
 import android.car.input.RotaryEvent;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.SharedPreferences;
 import android.content.res.Resources;
+import android.content.SharedPreferences;
 import android.database.ContentObserver;
 import android.graphics.PixelFormat;
 import android.hardware.display.DisplayManager;
@@ -235,10 +235,10 @@
     private long mLastWindowAddedTime;
 
     /** Component name of rotary IME. Empty if none. */
-    private String mRotaryInputMethod;
+    @Nullable private String mRotaryInputMethod;
 
     /** Component name of IME used in touch mode. */
-    private String mTouchInputMethod;
+    @Nullable private String mTouchInputMethod;
 
     /** Observer to update {@link #mTouchInputMethod} when the user switches IMEs. */
     private ContentObserver mInputMethodObserver;
@@ -411,10 +411,19 @@
         mPrefs = createDeviceProtectedStorageContext().getSharedPreferences(SHARED_PREFS,
                 Context.MODE_PRIVATE);
         mUserManager = getSystemService(UserManager.class);
-        mTouchInputMethod = mPrefs.getString(
-                TOUCH_INPUT_METHOD_PREFIX + mUserManager.getUserName(),
-                res.getString(R.string.default_touch_input_method));
-        mRotaryInputMethod = res.getString(R.string.rotary_input_method);
+
+        // Verify that the component names for default_touch_input_method and rotary_input_method
+        // are valid. If mTouchInputMethod or mRotaryInputMethod is empty, IMEs should not switch
+        // because RotaryService won't be able to switch them back.
+        String defaultTouchInputMethod = res.getString(R.string.default_touch_input_method);
+        if (isValidIme(defaultTouchInputMethod)) {
+            mTouchInputMethod = mPrefs.getString(
+                TOUCH_INPUT_METHOD_PREFIX + mUserManager.getUserName(), defaultTouchInputMethod);
+        }
+        String rotaryInputMethod = res.getString(R.string.rotary_input_method);
+        if (isValidIme(rotaryInputMethod)) {
+            mRotaryInputMethod = rotaryInputMethod;
+        }
 
         long afterFocusTimeoutMs = res.getInteger(R.integer.after_focus_timeout_ms);
         mPendingFocusedNodes = new PendingFocusedNodes(afterFocusTimeoutMs);
@@ -1929,15 +1938,23 @@
         }
 
         // Update IME.
-        if (mRotaryInputMethod.isEmpty()) {
+        if (TextUtils.isEmpty(mRotaryInputMethod)) {
             L.w("No rotary IME configured");
             return;
         }
+        if (TextUtils.isEmpty(mTouchInputMethod)) {
+            L.w("No touch IME configured");
+            return;
+        }
         if (!inRotaryMode) {
             setEditNode(null);
         }
-        // Switch to the rotary IME or the IME in use before we switched to the rotary IME.
+        // Switch to the rotary IME or the touch IME.
         String newIme = inRotaryMode ? mRotaryInputMethod : mTouchInputMethod;
+        if (!isValidIme(newIme)) {
+            L.w("Invalid IME: " + newIme);
+            return;
+        }
         boolean result =
                 Settings.Secure.putString(getContentResolver(), DEFAULT_INPUT_METHOD, newIme);
         if (!result) {
@@ -2078,4 +2095,18 @@
     private AccessibilityNodeInfo copyNode(@Nullable AccessibilityNodeInfo node) {
         return mNodeCopier.copy(node);
     }
+
+    /**
+     * Checks if the {@code componentName} is an enabled input method.
+     * The string should be in the format {@code "PackageName/.ClassName"}.
+     * Example: {@code "com.android.inputmethod.latin/.CarLatinIME"}.
+     */
+    private boolean isValidIme(String componentName) {
+        if (TextUtils.isEmpty(componentName)) {
+            return false;
+        }
+        String enabledInputMethods = Settings.Secure.getString(
+                getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS);
+        return enabledInputMethods != null && enabledInputMethods.contains(componentName);
+    }
 }