Merge "Remove unnecessary internal lock"
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
index efa3167..495d5c688 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -37,6 +37,10 @@
 
 /**
  * InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes.
+ * <p>
+ * This class is designed to be used from and only from {@link InputMethodManagerService} by using
+ * {@link InputMethodManagerService#mMethodMap} as a global lock.
+ * </p>
  */
 public class InputMethodSubtypeSwitchingController {
     private static final String TAG = InputMethodSubtypeSwitchingController.class.getSimpleName();
@@ -207,12 +211,11 @@
         }
     }
 
-    private final Object mLock = new Object();
     private final InputMethodSettings mSettings;
     private InputMethodAndSubtypeList mSubtypeList;
 
     @VisibleForTesting
-    public static ImeSubtypeListItem getNextInputMethodImpl(List<ImeSubtypeListItem> imList,
+    public static ImeSubtypeListItem getNextInputMethodLockedImpl(List<ImeSubtypeListItem> imList,
             boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
         if (imi == null) {
             return null;
@@ -256,34 +259,34 @@
         return null;
     }
 
-    public InputMethodSubtypeSwitchingController(InputMethodSettings settings) {
+    private InputMethodSubtypeSwitchingController(InputMethodSettings settings, Context context) {
         mSettings = settings;
+        resetCircularListLocked(context);
+    }
+
+    public static InputMethodSubtypeSwitchingController createInstanceLocked(
+            InputMethodSettings settings, Context context) {
+        return new InputMethodSubtypeSwitchingController(settings, context);
     }
 
     // TODO: write unit tests for this method and the logic that determines the next subtype
-    public void onCommitText(InputMethodInfo imi, InputMethodSubtype subtype) {
+    public void onCommitTextLocked(InputMethodInfo imi, InputMethodSubtype subtype) {
         // TODO: Implement this.
     }
 
     public void resetCircularListLocked(Context context) {
-        synchronized(mLock) {
-            mSubtypeList = new InputMethodAndSubtypeList(context, mSettings);
-        }
+        mSubtypeList = new InputMethodAndSubtypeList(context, mSettings);
     }
 
-    public ImeSubtypeListItem getNextInputMethod(
+    public ImeSubtypeListItem getNextInputMethodLocked(
             boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
-        synchronized(mLock) {
-            return getNextInputMethodImpl(mSubtypeList.getSortedInputMethodAndSubtypeList(),
-                    onlyCurrentIme, imi, subtype);
-        }
+        return getNextInputMethodLockedImpl(mSubtypeList.getSortedInputMethodAndSubtypeList(),
+                onlyCurrentIme, imi, subtype);
     }
 
-    public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(boolean showSubtypes,
+    public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeListLocked(boolean showSubtypes,
             boolean inputShown, boolean isScreenLocked) {
-        synchronized(mLock) {
-            return mSubtypeList.getSortedInputMethodAndSubtypeList(
-                    showSubtypes, inputShown, isScreenLocked);
-        }
+        return mSubtypeList.getSortedInputMethodAndSubtypeList(
+                showSubtypes, inputShown, isScreenLocked);
     }
 }
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
index 2a4d921..0f343b1 100644
--- a/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodSubtypeSwitchingControllerTest.java
@@ -105,44 +105,44 @@
 
         // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US"
         currentIme = imList.get(0);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(1), nextIme);
         // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr"
         currentIme = imList.get(1);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(2), nextIme);
         // "switchAwareLatinIme/fr" -> "switchAwareJapaneseIme/ja_JP"
         currentIme = imList.get(2);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(5), nextIme);
         // "switchAwareJapaneseIme/ja_JP" -> "switchAwareLatinIme/en_US"
         currentIme = imList.get(5);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(0), nextIme);
 
         // "nonSwitchAwareLatinIme/en_UK" -> "nonSwitchAwareLatinIme/hi"
         currentIme = imList.get(3);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(4), nextIme);
         // "nonSwitchAwareLatinIme/hi" -> "nonSwitchAwareJapaneseIme/ja_JP"
         currentIme = imList.get(4);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(6), nextIme);
         // "nonSwitchAwareJapaneseIme/ja_JP" -> "nonSwitchAwareLatinIme/en_UK"
         currentIme = imList.get(6);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(3), nextIme);
@@ -158,46 +158,46 @@
 
         // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US"
         currentIme = imList.get(0);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(1), nextIme);
         // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr"
         currentIme = imList.get(1);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(2), nextIme);
         // "switchAwareLatinIme/fr" -> "switchAwareLatinIme/en_US"
         currentIme = imList.get(2);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(0), nextIme);
 
         // "nonSwitchAwareLatinIme/en_UK" -> "nonSwitchAwareLatinIme/hi"
         currentIme = imList.get(3);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(4), nextIme);
         // "nonSwitchAwareLatinIme/hi" -> "switchAwareLatinIme/en_UK"
         currentIme = imList.get(4);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertEquals(imList.get(3), nextIme);
 
         // "switchAwareJapaneseIme/ja_JP" -> null
         currentIme = imList.get(5);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertNull(nextIme);
 
         // "nonSwitchAwareJapaneseIme/ja_JP" -> null
         currentIme = imList.get(6);
-        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
+        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodLockedImpl(
                 imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                         currentIme.mSubtypeName.toString()));
         assertNull(nextIme);
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 2d270e7..fb69c86 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -692,8 +692,10 @@
                 mRes, context.getContentResolver(), mMethodMap, mMethodList, userId);
         updateCurrentProfileIds();
         mFileManager = new InputMethodFileManager(mMethodMap, userId);
-        mSwitchingController = new InputMethodSubtypeSwitchingController(mSettings);
-        mSwitchingController.resetCircularListLocked(context);
+        synchronized (mMethodMap) {
+            mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
+                    mSettings, context);
+        }
 
         // Just checking if defaultImiId is empty or not
         final String defaultImiId = mSettings.getSelectedInputMethod();
@@ -702,17 +704,23 @@
         }
         mImeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
 
-        buildInputMethodListLocked(mMethodList, mMethodMap,
-                !mImeSelectedOnBoot /* resetDefaultEnabledIme */);
+        synchronized (mMethodMap) {
+            buildInputMethodListLocked(mMethodList, mMethodMap,
+                    !mImeSelectedOnBoot /* resetDefaultEnabledIme */);
+        }
         mSettings.enableAllIMEsIfThereIsNoEnabledIME();
 
         if (!mImeSelectedOnBoot) {
             Slog.w(TAG, "No IME selected. Choose the most applicable IME.");
-            resetDefaultImeLocked(context);
+            synchronized (mMethodMap) {
+                resetDefaultImeLocked(context);
+            }
         }
 
         mSettingsObserver = new SettingsObserver(mHandler);
-        updateFromSettingsLocked(true);
+        synchronized (mMethodMap) {
+            updateFromSettingsLocked(true);
+        }
 
         // IMMS wants to receive Intent.ACTION_LOCALE_CHANGED in order to update the current IME
         // according to the new system locale.
@@ -2174,7 +2182,7 @@
             return false;
         }
         synchronized (mMethodMap) {
-            final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethod(
+            final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
                     onlyCurrentIme, mMethodMap.get(mCurMethodId), mCurrentSubtype);
             if (nextSubtype == null) {
                 return false;
@@ -2190,7 +2198,7 @@
             return false;
         }
         synchronized (mMethodMap) {
-            final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethod(
+            final ImeSubtypeListItem nextSubtype = mSwitchingController.getNextInputMethodLocked(
                     false /* onlyCurrentIme */, mMethodMap.get(mCurMethodId), mCurrentSubtype);
             if (nextSubtype == null) {
                 return false;
@@ -2273,9 +2281,11 @@
         if (DEBUG) {
             Slog.d(TAG, "Got the notification of commitText");
         }
-        final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
-        if (imi != null) {
-            mSwitchingController.onCommitText(imi, mCurrentSubtype);
+        synchronized (mMethodMap) {
+            final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
+            if (imi != null) {
+                mSwitchingController.onCommitTextLocked(imi, mCurrentSubtype);
+            }
         }
     }
 
@@ -2698,7 +2708,7 @@
             hideInputMethodMenuLocked();
 
             final List<ImeSubtypeListItem> imList =
-                    mSwitchingController.getSortedInputMethodAndSubtypeList(
+                    mSwitchingController.getSortedInputMethodAndSubtypeListLocked(
                             showSubtypes, mInputShown, isScreenLocked);
 
             if (lastInputMethodSubtypeId == NOT_A_SUBTYPE_ID) {