Merge "Change the initial disabled state of disabled IMEs" into jb-mr2-dev
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 655d148..4e21324 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
@@ -28,6 +29,8 @@
 import android.util.Slog;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
+import android.view.textservice.SpellCheckerInfo;
+import android.view.textservice.TextServicesManager;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -357,6 +360,78 @@
         return !subtype.isAuxiliary();
     }
 
+    public static void setNonSelectedSystemImesDisabledUntilUsed(
+            PackageManager packageManager, List<InputMethodInfo> enabledImis) {
+        if (DEBUG) {
+            Slog.d(TAG, "setNonSelectedSystemImesDisabledUntilUsed");
+        }
+        final String[] systemImesDisabledUntilUsed = Resources.getSystem().getStringArray(
+                com.android.internal.R.array.config_disabledUntilUsedPreinstalledImes);
+        if (systemImesDisabledUntilUsed == null || systemImesDisabledUntilUsed.length == 0) {
+            return;
+        }
+        // Only the current spell checker should be treated as an enabled one.
+        final SpellCheckerInfo currentSpellChecker =
+                TextServicesManager.getInstance().getCurrentSpellChecker();
+        for (final String packageName : systemImesDisabledUntilUsed) {
+            if (DEBUG) {
+                Slog.d(TAG, "check " + packageName);
+            }
+            boolean enabledIme = false;
+            for (int j = 0; j < enabledImis.size(); ++j) {
+                final InputMethodInfo imi = enabledImis.get(j);
+                if (packageName.equals(imi.getPackageName())) {
+                    enabledIme = true;
+                    break;
+                }
+            }
+            if (enabledIme) {
+                // enabled ime. skip
+                continue;
+            }
+            if (currentSpellChecker != null
+                    && packageName.equals(currentSpellChecker.getPackageName())) {
+                // enabled spell checker. skip
+                if (DEBUG) {
+                    Slog.d(TAG, packageName + " is the current spell checker. skip");
+                }
+                continue;
+            }
+            ApplicationInfo ai = null;
+            try {
+                ai = packageManager.getApplicationInfo(packageName,
+                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
+            } catch (NameNotFoundException e) {
+                Slog.w(TAG, "NameNotFoundException: " + packageName, e);
+            }
+            if (ai == null) {
+                // No app found for packageName
+                continue;
+            }
+            final boolean isSystemPackage = (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+            if (!isSystemPackage) {
+                continue;
+            }
+            setDisabledUntilUsed(packageManager, packageName);
+        }
+    }
+
+    private static void setDisabledUntilUsed(PackageManager packageManager, String packageName) {
+        final int state = packageManager.getApplicationEnabledSetting(packageName);
+        if (state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                || state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
+            if (DEBUG) {
+                Slog.d(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED");
+            }
+            packageManager.setApplicationEnabledSetting(packageName,
+                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0);
+        } else {
+            if (DEBUG) {
+                Slog.d(TAG, packageName + " is already DISABLED_UNTIL_USED");
+            }
+        }
+    }
+
     /**
      * Utility class for putting and getting settings for InputMethod
      * TODO: Move all putters and getters of settings to this class.
@@ -405,8 +480,7 @@
 
         public void setCurrentUserId(int userId) {
             if (DEBUG) {
-                Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to "
-                        + userId + ", new ime = " + getSelectedInputMethod());
+                Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to " + userId);
             }
             // IMMS settings are kept per user, so keep track of current user
             mCurrentUserId = userId;
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5c772b2..0313308 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1108,4 +1108,20 @@
          stream or master volumes. -->
     <bool name="config_useFixedVolume">false</bool>
 
+    <!-- The list of IMEs which should be disabled until used.
+         This function suppresses update notifications for these pre-installed apps.
+         We need to set this configuration carefully that they should not have functionarities
+         other than "IME" or "Spell Checker". In InputMethodManagerService,
+         the listed IMEs are disabled until used when all of the following conditions are met.
+         1. Not selected as an enabled IME in the Settings
+         2. Not selected as a spell checker in the Settings
+         3. Installed
+         4. A pre-installed IME
+         5. Not enabled
+         And the disabled_until_used state for an IME is released by InputMethodManagerService
+         when the IME is selected as an enabled IME. -->
+    <string-array name="config_disabledUntilUsedPreinstalledImes" translatable="false">
+        <item>com.android.inputmethod.latin</item>
+    </string-array>
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 2158e90..6a3bdaa 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -919,6 +919,7 @@
   <java-symbol type="array" name="special_locale_names" />
   <java-symbol type="array" name="config_masterVolumeRamp" />
   <java-symbol type="array" name="config_cdma_dun_supported_types" />
+  <java-symbol type="array" name="config_disabledUntilUsedPreinstalledImes" />
 
   <java-symbol type="drawable" name="default_wallpaper" />
   <java-symbol type="drawable" name="indicator_input_error" />
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index f872cc3..1dd5fc6 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -705,7 +705,7 @@
                     @Override
                     public void onReceive(Context context, Intent intent) {
                         synchronized(mMethodMap) {
-                            checkCurrentLocaleChangedLocked();
+                            resetStateIfCurrentLocaleChangedLocked();
                         }
                     }
                 }, filter);
@@ -781,7 +781,7 @@
         }
     }
 
-    private void checkCurrentLocaleChangedLocked() {
+    private void resetStateIfCurrentLocaleChangedLocked() {
         resetAllInternalStateLocked(true /* updateOnlyWhenLocaleChanged */,
                 true /* resetDefaultImeLocked */);
     }
@@ -791,12 +791,16 @@
         // InputMethodFileManager should be reset when the user is changed
         mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
         final String defaultImiId = mSettings.getSelectedInputMethod();
-        final boolean needsToResetDefaultIme = TextUtils.isEmpty(defaultImiId);
+        final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId);
         if (DEBUG) {
             Slog.d(TAG, "Switch user: " + newUserId + " current ime = " + defaultImiId);
         }
         resetAllInternalStateLocked(false  /* updateOnlyWhenLocaleChanged */,
-                needsToResetDefaultIme);
+                initialUserSwitch /* needsToResetDefaultIme */);
+        if (initialUserSwitch) {
+            InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mContext.getPackageManager(),
+                    mSettings.getEnabledInputMethodListLocked());
+        }
     }
 
     @Override
@@ -838,7 +842,10 @@
                         !mImeSelectedOnBoot /* resetDefaultEnabledIme */);
                 if (!mImeSelectedOnBoot) {
                     Slog.w(TAG, "Reset the default IME as \"Resource\" is ready here.");
-                    checkCurrentLocaleChangedLocked();
+                    resetStateIfCurrentLocaleChangedLocked();
+                    InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(
+                            mContext.getPackageManager(),
+                            mSettings.getEnabledInputMethodListLocked());
                 }
                 mLastSystemLocale = mRes.getConfiguration().locale;
                 try {
@@ -1597,6 +1604,10 @@
                             mSettings.getCurrentUserId());
                     if (ai != null && ai.enabledSetting
                             == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "Update state(" + imm.getId()
+                                    + "): DISABLED_UNTIL_USED -> DEFAULT");
+                        }
                         mIPackageManager.setApplicationEnabledSetting(imm.getPackageName(),
                                 PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
                                 PackageManager.DONT_KILL_APP, mSettings.getCurrentUserId(),