Merge "Add Copy-On-Write mode to InputMethodSettings." into nyc-dev
am: 93dfc03ba6
* commit '93dfc03ba632590e30604dde31b78628df962eff':
Add Copy-On-Write mode to InputMethodSettings.
This commit is contained in:
@@ -18,6 +18,7 @@ package com.android.internal.inputmethod;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
|
import android.annotation.UserIdInt;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@@ -32,6 +33,7 @@ import android.text.TextUtils.SimpleStringSplitter;
|
|||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
import android.util.Printer;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.view.inputmethod.InputMethodInfo;
|
import android.view.inputmethod.InputMethodInfo;
|
||||||
import android.view.inputmethod.InputMethodSubtype;
|
import android.view.inputmethod.InputMethodSubtype;
|
||||||
@@ -826,7 +828,14 @@ public class InputMethodUtils {
|
|||||||
private final HashMap<String, InputMethodInfo> mMethodMap;
|
private final HashMap<String, InputMethodInfo> mMethodMap;
|
||||||
private final ArrayList<InputMethodInfo> mMethodList;
|
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;
|
private String mEnabledInputMethodsStrCache;
|
||||||
|
@UserIdInt
|
||||||
private int mCurrentUserId;
|
private int mCurrentUserId;
|
||||||
private int[] mCurrentProfileIds = new int[0];
|
private int[] mCurrentProfileIds = new int[0];
|
||||||
|
|
||||||
@@ -879,48 +888,85 @@ public class InputMethodUtils {
|
|||||||
return imsList;
|
return imsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public InputMethodSettings(
|
public InputMethodSettings(
|
||||||
Resources res, ContentResolver resolver,
|
Resources res, ContentResolver resolver,
|
||||||
HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
|
HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
|
||||||
int userId) {
|
@UserIdInt int userId) {
|
||||||
setCurrentUserId(userId);
|
this(res, resolver, methodMap, methodList, userId, false /* copyOnWrite */);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputMethodSettings(
|
||||||
|
Resources res, ContentResolver resolver,
|
||||||
|
HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
|
||||||
|
@UserIdInt int userId, boolean copyOnWrite) {
|
||||||
mRes = res;
|
mRes = res;
|
||||||
mResolver = resolver;
|
mResolver = resolver;
|
||||||
mMethodMap = methodMap;
|
mMethodMap = methodMap;
|
||||||
mMethodList = methodList;
|
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) {
|
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;
|
mCurrentUserId = userId;
|
||||||
|
mCopyOnWrite = copyOnWrite;
|
||||||
|
// TODO: mCurrentProfileIds should be updated here.
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putString(final String key, final String str) {
|
private void putString(final String key, final String str) {
|
||||||
Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
|
if (mCopyOnWrite) {
|
||||||
|
mCopyOnWriteDataStore.put(key, str);
|
||||||
|
} else {
|
||||||
|
Settings.Secure.putStringForUser(mResolver, key, str, mCurrentUserId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getString(final String key) {
|
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);
|
return Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putInt(final String key, final int value) {
|
private void putInt(final String key, final int value) {
|
||||||
Settings.Secure.putIntForUser(mResolver, key, value, mCurrentUserId);
|
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) {
|
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);
|
return Settings.Secure.getIntForUser(mResolver, key, defaultValue, mCurrentUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void putBoolean(final String key, final boolean value) {
|
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) {
|
private boolean getBoolean(final String key, final boolean defaultValue) {
|
||||||
return Settings.Secure.getIntForUser(mResolver, key, defaultValue ? 1 : 0,
|
return getInt(key, defaultValue ? 1 : 0) == 1;
|
||||||
mCurrentUserId) == 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentProfileIds(int[] currentProfileIds) {
|
public void setCurrentProfileIds(int[] currentProfileIds) {
|
||||||
@@ -1290,6 +1336,7 @@ public class InputMethodUtils {
|
|||||||
putBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, show);
|
putBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, show);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UserIdInt
|
||||||
public int getCurrentUserId() {
|
public int getCurrentUserId() {
|
||||||
return mCurrentUserId;
|
return mCurrentUserId;
|
||||||
}
|
}
|
||||||
@@ -1324,6 +1371,13 @@ public class InputMethodUtils {
|
|||||||
}
|
}
|
||||||
return enabledInputMethodAndSubtypes;
|
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.
|
// For spell checker service manager.
|
||||||
|
|||||||
@@ -857,7 +857,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
|
|
||||||
// mSettings should be created before buildInputMethodListLocked
|
// mSettings should be created before buildInputMethodListLocked
|
||||||
mSettings = new InputMethodSettings(
|
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
|
// Let the package manager query which are the default imes
|
||||||
// as they get certain permissions granted by default.
|
// as they get certain permissions granted by default.
|
||||||
@@ -872,7 +872,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
// TODO: We are switching the current user id in the settings
|
// TODO: We are switching the current user id in the settings
|
||||||
// object to query it and then revert the user id. Ideally, we
|
// 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.
|
// 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
|
List<InputMethodInfo> imes = mSettings
|
||||||
.getEnabledInputMethodListLocked();
|
.getEnabledInputMethodListLocked();
|
||||||
String[] packageNames = null;
|
String[] packageNames = null;
|
||||||
@@ -884,7 +884,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
packageNames[i] = ime.getPackageName();
|
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;
|
return packageNames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1020,7 +1022,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
|
|
||||||
// ContentObserver should be registered again when the user is changed
|
// ContentObserver should be registered again when the user is changed
|
||||||
mSettingsObserver.registerContentObserverLocked(newUserId);
|
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();
|
updateCurrentProfileIds();
|
||||||
// InputMethodFileManager should be reset when the user is changed
|
// InputMethodFileManager should be reset when the user is changed
|
||||||
mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
|
mFileManager = new InputMethodFileManager(mMethodMap, newUserId);
|
||||||
@@ -1079,6 +1084,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
}
|
}
|
||||||
if (!mSystemReady) {
|
if (!mSystemReady) {
|
||||||
mSystemReady = true;
|
mSystemReady = true;
|
||||||
|
final int currentUserId = mSettings.getCurrentUserId();
|
||||||
|
mSettings.switchCurrentUser(currentUserId, false /* copyOnWrite */);
|
||||||
mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
|
mKeyguardManager = mContext.getSystemService(KeyguardManager.class);
|
||||||
mNotificationManager = mContext.getSystemService(NotificationManager.class);
|
mNotificationManager = mContext.getSystemService(NotificationManager.class);
|
||||||
mStatusBar = statusBar;
|
mStatusBar = statusBar;
|
||||||
@@ -3000,7 +3007,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
if (resetDefaultEnabledIme) {
|
if (resetDefaultEnabledIme) {
|
||||||
final ArrayList<InputMethodInfo> defaultEnabledIme =
|
final ArrayList<InputMethodInfo> defaultEnabledIme =
|
||||||
InputMethodUtils.getDefaultEnabledImes(mContext, mSystemReady, mMethodList);
|
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);
|
final InputMethodInfo imi = defaultEnabledIme.get(i);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.d(TAG, "--- enable ime = " + imi);
|
Slog.d(TAG, "--- enable ime = " + imi);
|
||||||
@@ -3362,16 +3370,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Workaround.
|
if (!setSubtypeOnly) {
|
||||||
// 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) {
|
|
||||||
// Set InputMethod here
|
// Set InputMethod here
|
||||||
mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
|
mSettings.putSelectedInputMethod(imi != null ? imi.getId() : "");
|
||||||
}
|
}
|
||||||
@@ -3852,6 +3851,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
|
|||||||
p.println(" mSettingsObserver=" + mSettingsObserver);
|
p.println(" mSettingsObserver=" + mSettingsObserver);
|
||||||
p.println(" mSwitchingController:");
|
p.println(" mSwitchingController:");
|
||||||
mSwitchingController.dump(p);
|
mSwitchingController.dump(p);
|
||||||
|
p.println(" mSettings:");
|
||||||
|
mSettings.dumpLocked(p, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
p.println(" ");
|
p.println(" ");
|
||||||
|
|||||||
Reference in New Issue
Block a user