Merge "Make InputMethodPreference support work profile"
This commit is contained in:
@@ -18,11 +18,13 @@ package com.android.settingslib.inputmethod;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.icu.text.ListFormatter;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Settings.SettingNotFoundException;
|
||||
import android.text.TextUtils;
|
||||
@@ -155,9 +157,41 @@ public class InputMethodAndSubtypeUtilCompat {
|
||||
return set;
|
||||
}
|
||||
|
||||
public static void saveInputMethodSubtypeList(PreferenceFragmentCompat context,
|
||||
/**
|
||||
* Save the enabled/disabled input methods and selected subtype states into system settings.
|
||||
*
|
||||
* @param fragment The preference fragment user interact with.
|
||||
* @param resolver The {@link ContentResolver} used to access the database.
|
||||
* @param inputMethodInfos The list of {@link InputMethodInfo} to be checked.
|
||||
* @param hasHardKeyboard {@code true} if the device has the hardware keyboard.
|
||||
*/
|
||||
public static void saveInputMethodSubtypeList(PreferenceFragmentCompat fragment,
|
||||
ContentResolver resolver, List<InputMethodInfo> inputMethodInfos,
|
||||
boolean hasHardKeyboard) {
|
||||
saveInputMethodSubtypeListForUserInternal(
|
||||
fragment, resolver, inputMethodInfos, hasHardKeyboard, UserHandle.myUserId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the enabled/disabled input methods and selected subtype states into system settings as
|
||||
* given userId.
|
||||
*
|
||||
* @param fragment The preference fragment user interact with.
|
||||
* @param resolver The {@link ContentResolver} used to access the database.
|
||||
* @param inputMethodInfos The list of {@link InputMethodInfo} to be checked.
|
||||
* @param hasHardKeyboard {@code true} if the device has the hardware keyboard.
|
||||
* @param userId The given userId
|
||||
*/
|
||||
public static void saveInputMethodSubtypeListForUser(PreferenceFragmentCompat fragment,
|
||||
ContentResolver resolver, List<InputMethodInfo> inputMethodInfos,
|
||||
boolean hasHardKeyboard, @UserIdInt int userId) {
|
||||
saveInputMethodSubtypeListForUserInternal(
|
||||
fragment, resolver, inputMethodInfos, hasHardKeyboard, userId);
|
||||
}
|
||||
|
||||
private static void saveInputMethodSubtypeListForUserInternal(PreferenceFragmentCompat fragment,
|
||||
ContentResolver resolver, List<InputMethodInfo> inputMethodInfos,
|
||||
boolean hasHardKeyboard, @UserIdInt int userId) {
|
||||
String currentInputMethodId = Settings.Secure.getString(resolver,
|
||||
Settings.Secure.DEFAULT_INPUT_METHOD);
|
||||
final int selectedInputMethodSubtype = getInputMethodSubtypeSelected(resolver);
|
||||
@@ -168,7 +202,7 @@ public class InputMethodAndSubtypeUtilCompat {
|
||||
boolean needsToResetSelectedSubtype = false;
|
||||
for (final InputMethodInfo imi : inputMethodInfos) {
|
||||
final String imiId = imi.getId();
|
||||
final Preference pref = context.findPreference(imiId);
|
||||
final Preference pref = fragment.findPreference(imiId);
|
||||
if (pref == null) {
|
||||
continue;
|
||||
}
|
||||
@@ -184,8 +218,11 @@ public class InputMethodAndSubtypeUtilCompat {
|
||||
}
|
||||
final boolean isCurrentInputMethod = imiId.equals(currentInputMethodId);
|
||||
final boolean systemIme = imi.isSystem();
|
||||
// Create context as given userId
|
||||
final Context wrapperContext = userId == UserHandle.myUserId() ? fragment.getActivity()
|
||||
: fragment.getActivity().createContextAsUser(UserHandle.of(userId), 0);
|
||||
if ((!hasHardKeyboard && InputMethodSettingValuesWrapper.getInstance(
|
||||
context.getActivity()).isAlwaysCheckedIme(imi))
|
||||
wrapperContext).isAlwaysCheckedIme(imi))
|
||||
|| isImeChecked) {
|
||||
if (!enabledIMEsAndSubtypesMap.containsKey(imiId)) {
|
||||
// imiId has just been enabled
|
||||
@@ -198,7 +235,7 @@ public class InputMethodAndSubtypeUtilCompat {
|
||||
for (int i = 0; i < subtypeCount; ++i) {
|
||||
final InputMethodSubtype subtype = imi.getSubtypeAt(i);
|
||||
final String subtypeHashCodeStr = String.valueOf(subtype.hashCode());
|
||||
final TwoStatePreference subtypePref = (TwoStatePreference) context
|
||||
final TwoStatePreference subtypePref = (TwoStatePreference) fragment
|
||||
.findPreference(imiId + subtypeHashCodeStr);
|
||||
// In the Configure input method screen which does not have subtype preferences.
|
||||
if (subtypePref == null) {
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.settingslib.inputmethod;
|
||||
|
||||
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
|
||||
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
@@ -75,30 +76,34 @@ public class InputMethodPreference extends PrimarySwitchPreference
|
||||
private final OnSavePreferenceListener mOnSaveListener;
|
||||
private final InputMethodSettingValuesWrapper mInputMethodSettingValues;
|
||||
private final boolean mIsAllowedByOrganization;
|
||||
@UserIdInt
|
||||
private final int mUserId;
|
||||
|
||||
private AlertDialog mDialog = null;
|
||||
|
||||
/**
|
||||
* A preference entry of an input method.
|
||||
*
|
||||
* @param context The Context this is associated with.
|
||||
* @param prefContext The Context this preference is associated with.
|
||||
* @param imi The {@link InputMethodInfo} of this preference.
|
||||
* @param isAllowedByOrganization false if the IME has been disabled by a device or profile
|
||||
* owner.
|
||||
* @param onSaveListener The listener called when this preference has been changed and needs
|
||||
* to save the state to shared preference.
|
||||
* @param userId The userId to specify the corresponding user for this preference.
|
||||
*/
|
||||
public InputMethodPreference(final Context context, final InputMethodInfo imi,
|
||||
final boolean isAllowedByOrganization, final OnSavePreferenceListener onSaveListener) {
|
||||
this(context, imi, imi.loadLabel(context.getPackageManager()), isAllowedByOrganization,
|
||||
onSaveListener);
|
||||
public InputMethodPreference(final Context prefContext, final InputMethodInfo imi,
|
||||
final boolean isAllowedByOrganization, final OnSavePreferenceListener onSaveListener,
|
||||
final @UserIdInt int userId) {
|
||||
this(prefContext, imi, imi.loadLabel(prefContext.getPackageManager()),
|
||||
isAllowedByOrganization, onSaveListener, userId);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
InputMethodPreference(final Context context, final InputMethodInfo imi,
|
||||
InputMethodPreference(final Context prefContext, final InputMethodInfo imi,
|
||||
final CharSequence title, final boolean isAllowedByOrganization,
|
||||
final OnSavePreferenceListener onSaveListener) {
|
||||
super(context);
|
||||
final OnSavePreferenceListener onSaveListener, final @UserIdInt int userId) {
|
||||
super(prefContext);
|
||||
setPersistent(false);
|
||||
mImi = imi;
|
||||
mIsAllowedByOrganization = isAllowedByOrganization;
|
||||
@@ -114,7 +119,12 @@ public class InputMethodPreference extends PrimarySwitchPreference
|
||||
intent.setClassName(imi.getPackageName(), settingsActivity);
|
||||
setIntent(intent);
|
||||
}
|
||||
mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(context);
|
||||
// Handle the context by given userId because {@link InputMethodSettingValuesWrapper} is
|
||||
// per-user instance.
|
||||
final Context userAwareContext = userId == UserHandle.myUserId() ? prefContext :
|
||||
getContext().createContextAsUser(UserHandle.of(userId), 0);
|
||||
mInputMethodSettingValues = InputMethodSettingValuesWrapper.getInstance(userAwareContext);
|
||||
mUserId = userId;
|
||||
mHasPriorityInSorting = imi.isSystem()
|
||||
&& InputMethodAndSubtypeUtil.isValidNonAuxAsciiCapableIme(imi);
|
||||
setOnPreferenceClickListener(this);
|
||||
@@ -130,17 +140,15 @@ public class InputMethodPreference extends PrimarySwitchPreference
|
||||
super.onBindViewHolder(holder);
|
||||
final Switch switchWidget = getSwitch();
|
||||
if (switchWidget != null) {
|
||||
// Avoid default behavior in {@link PrimarySwitchPreference#onBindViewHolder}.
|
||||
switchWidget.setOnClickListener(v -> {
|
||||
// no-op, avoid default behavior in {@link PrimarySwitchPreference#onBindViewHolder}
|
||||
});
|
||||
switchWidget.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
// Avoid the invocation after we call {@link PrimarySwitchPreference#setChecked()}
|
||||
// in {@link setCheckedInternal}
|
||||
if (isChecked != isChecked()) {
|
||||
// Keep switch to previous state because we have to show the dialog first
|
||||
buttonView.setChecked(!isChecked);
|
||||
callChangeListener(isChecked());
|
||||
if (!switchWidget.isEnabled()) {
|
||||
return;
|
||||
}
|
||||
final boolean newValue = !isChecked();
|
||||
// Keep switch to previous state because we have to show the dialog first.
|
||||
switchWidget.setChecked(isChecked());
|
||||
callChangeListener(newValue);
|
||||
});
|
||||
}
|
||||
final ImageView icon = holder.itemView.findViewById(android.R.id.icon);
|
||||
@@ -187,7 +195,7 @@ public class InputMethodPreference extends PrimarySwitchPreference
|
||||
final Intent intent = getIntent();
|
||||
if (intent != null) {
|
||||
// Invoke a settings activity of an input method.
|
||||
context.startActivity(intent);
|
||||
context.startActivityAsUser(intent, UserHandle.of(mUserId));
|
||||
}
|
||||
} catch (final ActivityNotFoundException e) {
|
||||
Log.d(TAG, "IME's Settings Activity Not Found", e);
|
||||
|
||||
@@ -16,13 +16,18 @@
|
||||
|
||||
package com.android.settingslib.inputmethod;
|
||||
|
||||
import android.annotation.AnyThread;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.UiThread;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -39,20 +44,39 @@ import java.util.List;
|
||||
public class InputMethodSettingValuesWrapper {
|
||||
private static final String TAG = InputMethodSettingValuesWrapper.class.getSimpleName();
|
||||
|
||||
private static volatile InputMethodSettingValuesWrapper sInstance;
|
||||
private static final Object sInstanceMapLock = new Object();
|
||||
/**
|
||||
* Manages mapping between user ID and corresponding singleton
|
||||
* {@link InputMethodSettingValuesWrapper} object.
|
||||
*/
|
||||
@GuardedBy("sInstanceMapLock")
|
||||
private static SparseArray<InputMethodSettingValuesWrapper> sInstanceMap = new SparseArray<>();
|
||||
private final ArrayList<InputMethodInfo> mMethodList = new ArrayList<>();
|
||||
private final ContentResolver mContentResolver;
|
||||
private final InputMethodManager mImm;
|
||||
|
||||
public static InputMethodSettingValuesWrapper getInstance(Context context) {
|
||||
if (sInstance == null) {
|
||||
synchronized (TAG) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new InputMethodSettingValuesWrapper(context);
|
||||
}
|
||||
@AnyThread
|
||||
@NonNull
|
||||
public static InputMethodSettingValuesWrapper getInstance(@NonNull Context context) {
|
||||
final int requestUserId = context.getUserId();
|
||||
InputMethodSettingValuesWrapper valuesWrapper;
|
||||
// First time to create the wrapper.
|
||||
synchronized (sInstanceMapLock) {
|
||||
if (sInstanceMap.size() == 0) {
|
||||
valuesWrapper = new InputMethodSettingValuesWrapper(context);
|
||||
sInstanceMap.put(requestUserId, valuesWrapper);
|
||||
return valuesWrapper;
|
||||
}
|
||||
// We have same user context as request.
|
||||
if (sInstanceMap.indexOfKey(requestUserId) >= 0) {
|
||||
return sInstanceMap.get(requestUserId);
|
||||
}
|
||||
// Request by a new user context.
|
||||
valuesWrapper = new InputMethodSettingValuesWrapper(context);
|
||||
sInstanceMap.put(context.getUserId(), valuesWrapper);
|
||||
}
|
||||
return sInstance;
|
||||
|
||||
return valuesWrapper;
|
||||
}
|
||||
|
||||
// Ensure singleton
|
||||
@@ -64,7 +88,7 @@ public class InputMethodSettingValuesWrapper {
|
||||
|
||||
public void refreshAllInputMethodAndSubtypes() {
|
||||
mMethodList.clear();
|
||||
mMethodList.addAll(mImm.getInputMethodList());
|
||||
mMethodList.addAll(mImm.getInputMethodListAsUser(mContentResolver.getUserId()));
|
||||
}
|
||||
|
||||
public List<InputMethodInfo> getInputMethodList() {
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.UserHandle;
|
||||
import android.view.inputmethod.InputMethodInfo;
|
||||
import android.view.inputmethod.InputMethodSubtype;
|
||||
|
||||
@@ -112,7 +113,8 @@ public class InputMethodPreferenceTest {
|
||||
createInputMethodInfo(systemIme, name),
|
||||
title,
|
||||
true /* isAllowedByOrganization */,
|
||||
p -> {} /* onSavePreferenceListener */);
|
||||
p -> {} /* onSavePreferenceListener */,
|
||||
UserHandle.myUserId());
|
||||
}
|
||||
|
||||
private static InputMethodInfo createInputMethodInfo(
|
||||
|
||||
Reference in New Issue
Block a user