Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93dfc03b authored by Yohei Yukawa's avatar Yohei Yukawa Committed by Android (Google) Code Review
Browse files

Merge "Add Copy-On-Write mode to InputMethodSettings." into nyc-dev

parents fbff8c1c 68645a63
Loading
Loading
Loading
Loading
+64 −10
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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];

@@ -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) {
@@ -1290,6 +1336,7 @@ public class InputMethodUtils {
            putBoolean(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, show);
        }

        @UserIdInt
        public int getCurrentUserId() {
            return mCurrentUserId;
        }
@@ -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.
+16 −15
Original line number Diff line number Diff line
@@ -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.
@@ -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;
@@ -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;
                        }
                    }
@@ -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);
@@ -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;
@@ -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);
@@ -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() : "");
        }
@@ -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(" ");