Loading core/java/com/android/internal/inputmethod/InputMethodUtils.java +64 −10 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.content.ContentResolver; import android.content.Context; Loading @@ -32,6 +33,7 @@ import android.text.TextUtils.SimpleStringSplitter; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Pair; import android.util.Printer; import android.util.Slog; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; Loading Loading @@ -826,7 +828,14 @@ public class InputMethodUtils { private final HashMap<String, InputMethodInfo> mMethodMap; private final ArrayList<InputMethodInfo> mMethodList; /** * On-memory data store to emulate when {@link #mCopyOnWrite} is {@code true}. */ private final HashMap<String, String> mCopyOnWriteDataStore = new HashMap<>(); private boolean mCopyOnWrite = false; private String mEnabledInputMethodsStrCache; @UserIdInt private int mCurrentUserId; private int[] mCurrentProfileIds = new int[0]; Loading Loading @@ -879,48 +888,85 @@ public class InputMethodUtils { return imsList; } @Deprecated public InputMethodSettings( Resources res, ContentResolver resolver, HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList, @UserIdInt int userId) { this(res, resolver, methodMap, methodList, userId, false /* copyOnWrite */); } public InputMethodSettings( Resources res, ContentResolver resolver, HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList, int userId) { setCurrentUserId(userId); @UserIdInt int userId, boolean copyOnWrite) { mRes = res; mResolver = resolver; mMethodMap = methodMap; mMethodList = methodList; switchCurrentUser(userId, copyOnWrite); } public void setCurrentUserId(int userId) { /** * Must be called when the current user is changed. * * @param userId The user ID. * @param copyOnWrite If {@code true}, for each settings key * (e.g. {@link Settings.Secure#ACTION_INPUT_METHOD_SUBTYPE_SETTINGS}) we use the actual * settings on the {@link Settings.Secure} until we do the first write operation. */ public void switchCurrentUser(@UserIdInt int userId, boolean copyOnWrite) { if (DEBUG) { Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to " + userId); Slog.d(TAG, "--- Switch the current user from " + mCurrentUserId + " to " + userId); } if (mCurrentUserId != userId || mCopyOnWrite != copyOnWrite) { mCopyOnWriteDataStore.clear(); mEnabledInputMethodsStrCache = ""; // TODO: mCurrentProfileIds should be cleared here. } // IMMS settings are kept per user, so keep track of current user mCurrentUserId = userId; mCopyOnWrite = copyOnWrite; // TODO: mCurrentProfileIds should be updated here. } private void putString(final String key, final String str) { if (mCopyOnWrite) { mCopyOnWriteDataStore.put(key, str); } else { Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId); } } private String getString(final String key) { if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) { final String result = mCopyOnWriteDataStore.get(key); return result != null ? result : ""; } return Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId); } private void putInt(final String key, final int value) { if (mCopyOnWrite) { mCopyOnWriteDataStore.put(key, String.valueOf(value)); } else { Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId); } } private int getInt(final String key, final int defaultValue) { if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) { final String result = mCopyOnWriteDataStore.get(key); return result != null ? Integer.valueOf(result) : 0; } return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId); } private void putBoolean(final String key, final boolean value) { Settings.Secure.putIntForUser(mResolver, key, value ? 1 : 0, mCurrentUserId); putInt(key, value ? 1 : 0); } private boolean getBoolean(final String key, final boolean defaultValue) { return Settings.Secure.getIntForUser(mResolver, key, defaultValue ? 1 : 0, mCurrentUserId) == 1; return getInt(key, defaultValue ? 1 : 0) == 1; } public void setCurrentProfileIds(int[] currentProfileIds) { Loading Loading @@ -1290,6 +1336,7 @@ public class InputMethodUtils { putBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, show); } @UserIdInt public int getCurrentUserId() { return mCurrentUserId; } Loading Loading @@ -1324,6 +1371,13 @@ public class InputMethodUtils { } return enabledInputMethodAndSubtypes; } public void dumpLocked(final Printer pw, final String prefix) { pw.println(prefix + "mCurrentUserId=" + mCurrentUserId); pw.println(prefix + "mCurrentProfileIds=" + Arrays.toString(mCurrentProfileIds)); pw.println(prefix + "mCopyOnWrite=" + mCopyOnWrite); pw.println(prefix + "mEnabledInputMethodsStrCache=" + mEnabledInputMethodsStrCache); } } // For spell checker service manager. Loading services/core/java/com/android/server/InputMethodManagerService.java +16 −15 Original line number Diff line number Diff line Loading @@ -857,7 +857,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // mSettings should be created before buildInputMethodListLocked mSettings = new InputMethodSettings( mRes, context.getContentResolver(), mMethodMap, mMethodList, userId); mRes, context.getContentResolver(), mMethodMap, mMethodList, userId, !mSystemReady); // Let the package manager query which are the default imes // as they get certain permissions granted by default. Loading @@ -872,7 +872,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // TODO: We are switching the current user id in the settings // object to query it and then revert the user id. Ideally, we // should call a API in settings with the user id as an argument. mSettings.setCurrentUserId(userId); mSettings.switchCurrentUser(userId, true /* copyOnWrite */); List<InputMethodInfo> imes = mSettings .getEnabledInputMethodListLocked(); String[] packageNames = null; Loading @@ -884,7 +884,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub packageNames[i] = ime.getPackageName(); } } mSettings.setCurrentUserId(currentUserId); // If the system is not ready, then we use copy-on-write mode. final boolean useCopyOnWriteSettings = !mSystemReady; mSettings.switchCurrentUser(currentUserId, useCopyOnWriteSettings); return packageNames; } } Loading Loading @@ -1020,7 +1022,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // ContentObserver should be registered again when the user is changed mSettingsObserver.registerContentObserverLocked(newUserId); mSettings.setCurrentUserId(newUserId); // If the system is not ready, then we use copy-on-write settings. final boolean useCopyOnWriteSettings = !mSystemReady; mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings); updateCurrentProfileIds(); // InputMethodFileManager should be reset when the user is changed mFileManager = new InputMethodFileManager(mMethodMap, newUserId); Loading Loading @@ -1079,6 +1084,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (!mSystemReady) { mSystemReady = true; final int currentUserId = mSettings.getCurrentUserId(); mSettings.switchCurrentUser(currentUserId, false /* copyOnWrite */); mKeyguardManager = mContext.getSystemService(KeyguardManager.class); mNotificationManager = mContext.getSystemService(NotificationManager.class); mStatusBar = statusBar; Loading Loading @@ -3000,7 +3007,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (resetDefaultEnabledIme) { final ArrayList<InputMethodInfo> defaultEnabledIme = InputMethodUtils.getDefaultEnabledImes(mContext, mSystemReady, mMethodList); for (int i = 0; i < defaultEnabledIme.size(); ++i) { final int N = defaultEnabledIme.size(); for (int i = 0; i < N; ++i) { final InputMethodInfo imi = defaultEnabledIme.get(i); if (DEBUG) { Slog.d(TAG, "--- enable ime = " + imi); Loading Loading @@ -3362,16 +3370,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } // Workaround. // ASEC is not ready in the IMMS constructor. Accordingly, forward-locked // IMEs are not recognized and considered uninstalled. // Actually, we can't move everything after SystemReady because // IMMS needs to run in the encryption lock screen. So, we just skip changing // the default IME here and try cheking the default IME again in systemReady(). // TODO: Do nothing before system ready and implement a separated logic for // the encryption lock screen. // TODO: ASEC should be ready before IMMS is instantiated. if (mSystemReady && !setSubtypeOnly) { if (!setSubtypeOnly) { // Set InputMethod here mSettings.putSelectedInputMethod(imi != null ? imi.getId() : ""); } Loading Loading @@ -3852,6 +3851,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub p.println(" mSettingsObserver=" + mSettingsObserver); p.println(" mSwitchingController:"); mSwitchingController.dump(p); p.println(" mSettings:"); mSettings.dumpLocked(p, " "); } p.println(" "); Loading Loading
core/java/com/android/internal/inputmethod/InputMethodUtils.java +64 −10 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.internal.inputmethod; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.AppOpsManager; import android.content.ContentResolver; import android.content.Context; Loading @@ -32,6 +33,7 @@ import android.text.TextUtils.SimpleStringSplitter; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Pair; import android.util.Printer; import android.util.Slog; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; Loading Loading @@ -826,7 +828,14 @@ public class InputMethodUtils { private final HashMap<String, InputMethodInfo> mMethodMap; private final ArrayList<InputMethodInfo> mMethodList; /** * On-memory data store to emulate when {@link #mCopyOnWrite} is {@code true}. */ private final HashMap<String, String> mCopyOnWriteDataStore = new HashMap<>(); private boolean mCopyOnWrite = false; private String mEnabledInputMethodsStrCache; @UserIdInt private int mCurrentUserId; private int[] mCurrentProfileIds = new int[0]; Loading Loading @@ -879,48 +888,85 @@ public class InputMethodUtils { return imsList; } @Deprecated public InputMethodSettings( Resources res, ContentResolver resolver, HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList, @UserIdInt int userId) { this(res, resolver, methodMap, methodList, userId, false /* copyOnWrite */); } public InputMethodSettings( Resources res, ContentResolver resolver, HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList, int userId) { setCurrentUserId(userId); @UserIdInt int userId, boolean copyOnWrite) { mRes = res; mResolver = resolver; mMethodMap = methodMap; mMethodList = methodList; switchCurrentUser(userId, copyOnWrite); } public void setCurrentUserId(int userId) { /** * Must be called when the current user is changed. * * @param userId The user ID. * @param copyOnWrite If {@code true}, for each settings key * (e.g. {@link Settings.Secure#ACTION_INPUT_METHOD_SUBTYPE_SETTINGS}) we use the actual * settings on the {@link Settings.Secure} until we do the first write operation. */ public void switchCurrentUser(@UserIdInt int userId, boolean copyOnWrite) { if (DEBUG) { Slog.d(TAG, "--- Swtich the current user from " + mCurrentUserId + " to " + userId); Slog.d(TAG, "--- Switch the current user from " + mCurrentUserId + " to " + userId); } if (mCurrentUserId != userId || mCopyOnWrite != copyOnWrite) { mCopyOnWriteDataStore.clear(); mEnabledInputMethodsStrCache = ""; // TODO: mCurrentProfileIds should be cleared here. } // IMMS settings are kept per user, so keep track of current user mCurrentUserId = userId; mCopyOnWrite = copyOnWrite; // TODO: mCurrentProfileIds should be updated here. } private void putString(final String key, final String str) { if (mCopyOnWrite) { mCopyOnWriteDataStore.put(key, str); } else { Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId); } } private String getString(final String key) { if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) { final String result = mCopyOnWriteDataStore.get(key); return result != null ? result : ""; } return Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId); } private void putInt(final String key, final int value) { if (mCopyOnWrite) { mCopyOnWriteDataStore.put(key, String.valueOf(value)); } else { Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId); } } private int getInt(final String key, final int defaultValue) { if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) { final String result = mCopyOnWriteDataStore.get(key); return result != null ? Integer.valueOf(result) : 0; } return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId); } private void putBoolean(final String key, final boolean value) { Settings.Secure.putIntForUser(mResolver, key, value ? 1 : 0, mCurrentUserId); putInt(key, value ? 1 : 0); } private boolean getBoolean(final String key, final boolean defaultValue) { return Settings.Secure.getIntForUser(mResolver, key, defaultValue ? 1 : 0, mCurrentUserId) == 1; return getInt(key, defaultValue ? 1 : 0) == 1; } public void setCurrentProfileIds(int[] currentProfileIds) { Loading Loading @@ -1290,6 +1336,7 @@ public class InputMethodUtils { putBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, show); } @UserIdInt public int getCurrentUserId() { return mCurrentUserId; } Loading Loading @@ -1324,6 +1371,13 @@ public class InputMethodUtils { } return enabledInputMethodAndSubtypes; } public void dumpLocked(final Printer pw, final String prefix) { pw.println(prefix + "mCurrentUserId=" + mCurrentUserId); pw.println(prefix + "mCurrentProfileIds=" + Arrays.toString(mCurrentProfileIds)); pw.println(prefix + "mCopyOnWrite=" + mCopyOnWrite); pw.println(prefix + "mEnabledInputMethodsStrCache=" + mEnabledInputMethodsStrCache); } } // For spell checker service manager. Loading
services/core/java/com/android/server/InputMethodManagerService.java +16 −15 Original line number Diff line number Diff line Loading @@ -857,7 +857,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // mSettings should be created before buildInputMethodListLocked mSettings = new InputMethodSettings( mRes, context.getContentResolver(), mMethodMap, mMethodList, userId); mRes, context.getContentResolver(), mMethodMap, mMethodList, userId, !mSystemReady); // Let the package manager query which are the default imes // as they get certain permissions granted by default. Loading @@ -872,7 +872,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // TODO: We are switching the current user id in the settings // object to query it and then revert the user id. Ideally, we // should call a API in settings with the user id as an argument. mSettings.setCurrentUserId(userId); mSettings.switchCurrentUser(userId, true /* copyOnWrite */); List<InputMethodInfo> imes = mSettings .getEnabledInputMethodListLocked(); String[] packageNames = null; Loading @@ -884,7 +884,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub packageNames[i] = ime.getPackageName(); } } mSettings.setCurrentUserId(currentUserId); // If the system is not ready, then we use copy-on-write mode. final boolean useCopyOnWriteSettings = !mSystemReady; mSettings.switchCurrentUser(currentUserId, useCopyOnWriteSettings); return packageNames; } } Loading Loading @@ -1020,7 +1022,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // ContentObserver should be registered again when the user is changed mSettingsObserver.registerContentObserverLocked(newUserId); mSettings.setCurrentUserId(newUserId); // If the system is not ready, then we use copy-on-write settings. final boolean useCopyOnWriteSettings = !mSystemReady; mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings); updateCurrentProfileIds(); // InputMethodFileManager should be reset when the user is changed mFileManager = new InputMethodFileManager(mMethodMap, newUserId); Loading Loading @@ -1079,6 +1084,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } if (!mSystemReady) { mSystemReady = true; final int currentUserId = mSettings.getCurrentUserId(); mSettings.switchCurrentUser(currentUserId, false /* copyOnWrite */); mKeyguardManager = mContext.getSystemService(KeyguardManager.class); mNotificationManager = mContext.getSystemService(NotificationManager.class); mStatusBar = statusBar; Loading Loading @@ -3000,7 +3007,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (resetDefaultEnabledIme) { final ArrayList<InputMethodInfo> defaultEnabledIme = InputMethodUtils.getDefaultEnabledImes(mContext, mSystemReady, mMethodList); for (int i = 0; i < defaultEnabledIme.size(); ++i) { final int N = defaultEnabledIme.size(); for (int i = 0; i < N; ++i) { final InputMethodInfo imi = defaultEnabledIme.get(i); if (DEBUG) { Slog.d(TAG, "--- enable ime = " + imi); Loading Loading @@ -3362,16 +3370,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } // Workaround. // ASEC is not ready in the IMMS constructor. Accordingly, forward-locked // IMEs are not recognized and considered uninstalled. // Actually, we can't move everything after SystemReady because // IMMS needs to run in the encryption lock screen. So, we just skip changing // the default IME here and try cheking the default IME again in systemReady(). // TODO: Do nothing before system ready and implement a separated logic for // the encryption lock screen. // TODO: ASEC should be ready before IMMS is instantiated. if (mSystemReady && !setSubtypeOnly) { if (!setSubtypeOnly) { // Set InputMethod here mSettings.putSelectedInputMethod(imi != null ? imi.getId() : ""); } Loading Loading @@ -3852,6 +3851,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub p.println(" mSettingsObserver=" + mSettingsObserver); p.println(" mSwitchingController:"); mSwitchingController.dump(p); p.println(" mSettings:"); mSettings.dumpLocked(p, " "); } p.println(" "); Loading