Reorganize spell checkers settings

Bug: 15976603
Bug: 16115751
Change-Id: I3b23d7f01d8d39da27215a5263b12304ac64db0f
This commit is contained in:
Tadashi G. Takaoka
2014-07-10 15:37:28 +09:00
parent 1aa40913df
commit cd6fdead7c
12 changed files with 363 additions and 618 deletions

View File

@@ -1,99 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:minHeight="?android:attr/listPreferredItemHeight"
android:gravity="center_vertical">
<LinearLayout
android:id="@+id/inputmethod_pref"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground">
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dip"
android:layout_marginEnd="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
android:layout_weight="1">
<TextView
android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="marquee"
android:fadingEdge="horizontal"/>
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:paddingBottom="3dip"
android:visibility="gone"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="13sp"
android:textColor="?android:attr/textColorSecondary"
android:focusable="false"
android:maxLines="4" />
</RelativeLayout>
</LinearLayout>
<View
android:layout_width="2dip"
android:layout_height="match_parent"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:background="@android:drawable/divider_horizontal_dark" />
<ImageView
android:id="@+id/inputmethod_settings"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingStart="15dip"
android:paddingEnd="?android:attr/scrollbarSize"
android:src="@drawable/ic_sysbar_quicksettings"
android:contentDescription="@string/input_method_settings_button"
android:layout_gravity="center"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground" />
</LinearLayout>

View File

@@ -13,9 +13,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pref_all"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
@@ -33,16 +33,17 @@
android:focusable="true"
android:background="?android:attr/selectableItemBackground">
<RadioButton
android:id="@+id/pref_radio"
<LinearLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="false"
android:focusable="false" />
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="15dip"
android:layout_marginEnd="6dip"
android:layout_marginTop="6dip"
android:layout_marginBottom="6dip"
@@ -52,10 +53,10 @@
android:id="@+android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="2"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceMedium"
android:ellipsize="marquee"
android:fadingEdge="horizontal" />
android:fadingEdge="horizontal"/>
<TextView
android:id="@android:id/summary"
@@ -63,46 +64,19 @@
android:layout_height="wrap_content"
android:layout_below="@android:id/title"
android:layout_alignStart="@android:id/title"
android:paddingBottom="3dip"
android:visibility="gone"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="13sp"
android:textColor="?android:attr/textColorSecondary"
android:focusable="false"
android:maxLines="4" />
</RelativeLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/pref_right_button1"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/spellchecker_quick_settings" >
<View
android:layout_width="2dip"
android:layout_height="match_parent"
android:layout_marginTop="5dip"
android:layout_marginBottom="5dip"
android:background="@android:drawable/divider_horizontal_dark" />
<ImageView
android:layout_width="40dip"
android:layout_height="fill_parent"
android:paddingStart="5dip"
android:paddingEnd="5dip"
android:src="@drawable/ic_sysbar_quicksettings"
android:layout_gravity="center"
android:contentDescription="@string/spellchecker_quick_settings" />
</LinearLayout>
<View
android:id="@+id/pref_right_separator2"
android:layout_width="2dip"
android:layout_height="match_parent"
android:layout_marginTop="5dip"
@@ -110,16 +84,16 @@
android:background="@android:drawable/divider_horizontal_dark" />
<ImageView
android:id="@+id/pref_right_button2"
android:layout_width="40dip"
android:id="@+id/pref_right_button"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:paddingStart="5dip"
android:paddingEnd="5dip"
android:src="@drawable/ic_menu_3d_globe"
android:layout_gravity="end"
android:paddingStart="15dip"
android:paddingEnd="?android:attr/scrollbarSize"
android:src="@drawable/ic_sysbar_quicksettings"
android:contentDescription="@string/input_method_settings_button"
android:layout_gravity="center"
android:clickable="true"
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/spellchecker_language" />
android:background="?android:attr/selectableItemBackground" />
</LinearLayout>
</LinearLayout>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project
<!-- Copyright (C) 2014 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -14,11 +14,10 @@
limitations under the License.
-->
<CheckBox
<RadioButton
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+android:id/checkbox"
android:id="@+id/pref_radio"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:focusable="false"
android:clickable="false"/>
android:clickable="false"
android:focusable="false" />

View File

@@ -25,10 +25,14 @@
android:fragment="com.android.settings.LocalePicker"
/>
<com.android.settings.inputmethod.SpellCheckersPreference
<!-- Spell checker preference title, summary and fragment will be set programmatically. -->
<!-- Note: Mark this as persistent="false" to remove unnecessarily saved shared preference.
See: InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference. -->
<PreferenceScreen
android:key="spellcheckers_settings"
android:title="@string/spellcheckers_settings_title"
settings:keywords="@string/keywords_spell_checker"
android:persistent="false"
/>
<!-- User dictionary preference title and fragment will be set programmatically. -->

View File

@@ -14,7 +14,11 @@
limitations under the License.
-->
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/spellcheckers_settings_title">
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/spellcheckers_settings_title">
<Preference
android:key="spellchecker_language"
android:title="@string/phone_language"
android:persistent="false" />
</PreferenceScreen>

View File

@@ -1,132 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.inputmethod;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import android.content.Context;
import android.content.Intent;
import android.preference.CheckBoxPreference;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.TextView;
// TODO: Make this non-persistent.
class CheckBoxAndSettingsPreference extends CheckBoxPreference {
private SettingsPreferenceFragment mFragment;
private TextView mTitleText;
private TextView mSummaryText;
private ImageView mSettingsButton;
private Intent mSettingsIntent;
public CheckBoxAndSettingsPreference(Context context) {
this(context, null);
}
public CheckBoxAndSettingsPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CheckBoxAndSettingsPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public CheckBoxAndSettingsPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayoutResource(R.layout.preference_inputmethod);
setWidgetLayoutResource(R.layout.preference_inputmethod_widget);
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
View textLayout = view.findViewById(R.id.inputmethod_pref);
textLayout.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View arg0) {
onCheckBoxClicked();
}
});
mSettingsButton = (ImageView) view.findViewById(R.id.inputmethod_settings);
mTitleText = (TextView)view.findViewById(android.R.id.title);
mSummaryText = (TextView)view.findViewById(android.R.id.summary);
mSettingsButton.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View clickedView) {
onSettingsButtonClicked();
}
});
enableSettingsButton();
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
enableSettingsButton();
}
public void setFragmentIntent(SettingsPreferenceFragment fragment, Intent intent) {
mFragment = fragment;
mSettingsIntent = intent;
}
protected void onCheckBoxClicked() {
if (isChecked()) {
setChecked(false);
} else {
setChecked(true);
}
}
protected void onSettingsButtonClicked() {
if (mFragment != null && mSettingsIntent != null) {
mFragment.startActivity(mSettingsIntent);
}
}
private void enableSettingsButton() {
if (mSettingsButton != null) {
if (mSettingsIntent == null) {
mSettingsButton.setVisibility(View.GONE);
} else {
final boolean checked = isChecked();
mSettingsButton.setEnabled(checked);
mSettingsButton.setClickable(checked);
mSettingsButton.setFocusable(checked);
if (!checked) {
mSettingsButton.setAlpha(Utils.DISABLED_ALPHA);
}
}
}
if (mTitleText != null) {
mTitleText.setEnabled(true);
}
if (mSummaryText != null) {
mSummaryText.setEnabled(true);
}
}
}

View File

@@ -48,10 +48,11 @@ import android.view.InputDevice;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodSubtype;
import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.TextServicesManager;
import com.android.settings.R;
import com.android.settings.Settings.KeyboardLayoutPickerActivity;
import com.android.settings.Settings.SpellCheckersSettingsActivity;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.SubSettings;
@@ -72,7 +73,8 @@ import java.util.TreeSet;
public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
implements Preference.OnPreferenceChangeListener, InputManager.InputDeviceListener,
KeyboardLayoutDialogFragment.OnSetupKeyboardLayoutsListener, Indexable,
InputMethodPreference.onSavePreferenceListener {
InputMethodPreference.OnSavePreferenceListener {
private static final String KEY_SPELL_CHECKERS = "spellcheckers_settings";
private static final String KEY_PHONE_LANGUAGE = "phone_language";
private static final String KEY_CHOOSE_INPUT_METHODS = "choose_input_methods";
private static final String KEY_CURRENT_INPUT_METHOD = "current_input_method";
@@ -171,12 +173,17 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
updateInputDevices();
// Spell Checker
final SpellCheckersPreference scp = ((SpellCheckersPreference)findPreference(
"spellcheckers_settings"));
if (scp != null) {
final Preference spellChecker = findPreference(KEY_SPELL_CHECKERS);
if (spellChecker != null) {
// Note: KEY_SPELL_CHECKERS preference is marked as persistent="false" in XML.
InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(spellChecker);
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClass(activity, SpellCheckersSettingsActivity.class);
scp.setFragmentIntent(this, intent);
intent.setClass(activity, SubSettings.class);
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT,
SpellCheckersSettings.class.getName());
intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID,
R.string.spellcheckers_settings_title);
spellChecker.setIntent(intent);
}
mHandler = new Handler();
@@ -239,6 +246,18 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
mSettingsObserver.resume();
mIm.registerInputDeviceListener(this, null);
final Preference spellChecker = findPreference(KEY_SPELL_CHECKERS);
if (spellChecker != null) {
final TextServicesManager tsm = (TextServicesManager) getSystemService(
Context.TEXT_SERVICES_MANAGER_SERVICE);
if (tsm.isSpellCheckerEnabled()) {
final SpellCheckerInfo sci = tsm.getCurrentSpellChecker();
spellChecker.setSummary(sci.loadLabel(getPackageManager()));
} else {
spellChecker.setSummary(R.string.switch_off_text);
}
}
if (!mShowsOnlyFullImeAndKeyboardList) {
if (mLanguagePref != null) {
String localeName = getLocaleName(getResources());
@@ -641,7 +660,7 @@ public class InputMethodAndLanguageSettings extends SettingsPreferenceFragment
// Spell checker.
SearchIndexableRaw indexable = new SearchIndexableRaw(context);
indexable.key = "spellcheckers_settings";
indexable.key = KEY_SPELL_CHECKERS;
indexable.title = context.getString(R.string.spellcheckers_settings_title);
indexable.screenTitle = screenTitle;
indexables.add(indexable);

View File

@@ -51,7 +51,7 @@ class InputMethodPreference extends SwitchPreference implements OnPreferenceClic
private static final String TAG = InputMethodPreference.class.getSimpleName();
private static final String EMPTY_TEXT = "";
interface onSavePreferenceListener {
interface OnSavePreferenceListener {
/**
* Called when this preference needs to be saved its state.
*
@@ -66,7 +66,7 @@ class InputMethodPreference extends SwitchPreference implements OnPreferenceClic
private final InputMethodInfo mImi;
private final boolean mHasPriorityInSorting;
private final onSavePreferenceListener mOnSaveListener;
private final OnSavePreferenceListener mOnSaveListener;
private final InputMethodSettingValuesWrapper mInputMethodSettingValues;
private AlertDialog mDialog = null;
@@ -82,7 +82,7 @@ class InputMethodPreference extends SwitchPreference implements OnPreferenceClic
* to save the state to shared preference.
*/
InputMethodPreference(final Context context, final InputMethodInfo imi,
final boolean isImeEnabler, final onSavePreferenceListener onSaveListener) {
final boolean isImeEnabler, final OnSavePreferenceListener onSaveListener) {
super(context);
setPersistent(false);
mImi = imi;

View File

@@ -1,214 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.inputmethod;
import com.android.settings.R;
import com.android.settings.Utils;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.preference.Preference;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.SpellCheckerSubtype;
import android.view.textservice.TextServicesManager;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.Toast;
// TODO: Make this non-persistent.
class SingleSpellCheckerPreference extends Preference {
private static final String TAG = SingleSpellCheckerPreference.class.getSimpleName();
private static final boolean DBG = false;
private final SpellCheckerInfo mSpellCheckerInfo;
private final SpellCheckersSettings mFragment;
private final Resources mRes;
private final TextServicesManager mTsm;
private AlertDialog mDialog = null;
private View mPrefAll;
private RadioButton mRadioButton;
private View mPrefLeftButton;
private View mSettingsButton;
private ImageView mSubtypeButton;
private Intent mSettingsIntent;
private boolean mSelected;
public SingleSpellCheckerPreference(SpellCheckersSettings fragment, SpellCheckerInfo sci,
TextServicesManager tsm) {
super(fragment.getActivity(), null, 0);
mFragment = fragment;
mRes = fragment.getActivity().getResources();
mTsm = tsm;
setLayoutResource(R.layout.preference_spellchecker);
mSpellCheckerInfo = sci;
mSelected = false;
final String settingsActivity = mSpellCheckerInfo.getSettingsActivity();
if (!TextUtils.isEmpty(settingsActivity)) {
mSettingsIntent = new Intent(Intent.ACTION_MAIN);
mSettingsIntent.setClassName(mSpellCheckerInfo.getPackageName(), settingsActivity);
} else {
mSettingsIntent = null;
}
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
mPrefAll = view.findViewById(R.id.pref_all);
mRadioButton = (RadioButton)view.findViewById(R.id.pref_radio);
mPrefLeftButton = view.findViewById(R.id.pref_left_button);
mPrefLeftButton.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View arg0) {
onLeftButtonClicked(arg0);
}
});
mSubtypeButton = (ImageView)view.findViewById(R.id.pref_right_button2);
mSubtypeButton.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View arg0) {
onSubtypeButtonClicked(arg0);
}
});
mSettingsButton = view.findViewById(R.id.pref_right_button1);
mSettingsButton.setOnClickListener(
new OnClickListener() {
@Override
public void onClick(View arg0) {
onSettingsButtonClicked(arg0);
}
});
updateSelectedState(mSelected);
}
private void onLeftButtonClicked(View arg0) {
mFragment.onPreferenceClick(this);
}
public SpellCheckerInfo getSpellCheckerInfo() {
return mSpellCheckerInfo;
}
private void updateSelectedState(boolean selected) {
if (mPrefAll != null) {
mRadioButton.setChecked(selected);
enableButtons(selected);
}
}
public void setSelected(boolean selected) {
mSelected = selected;
updateSelectedState(selected);
}
private void onSubtypeButtonClicked(View arg0) {
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
final AlertDialog.Builder builder = new AlertDialog.Builder(mFragment.getActivity());
builder.setTitle(R.string.phone_language);
final int size = mSpellCheckerInfo.getSubtypeCount();
final CharSequence[] items = new CharSequence[size + 1];
items[0] = mRes.getString(R.string.use_system_language_to_select_input_method_subtypes);
for (int i = 0; i < size; ++i) {
final SpellCheckerSubtype subtype = mSpellCheckerInfo.getSubtypeAt(i);
final CharSequence label = subtype.getDisplayName(
mFragment.getActivity(), mSpellCheckerInfo.getPackageName(),
mSpellCheckerInfo.getServiceInfo().applicationInfo);
items[i + 1] = label;
}
// default: "Use system language"
int checkedItem = 0;
// Allow no implicitly selected subtypes
final SpellCheckerSubtype currentScs = mTsm.getCurrentSpellCheckerSubtype(false);
if (currentScs != null) {
for (int i = 0; i < size; ++i) {
if (mSpellCheckerInfo.getSubtypeAt(i).equals(currentScs)) {
checkedItem = i + 1;
break;
}
}
}
builder.setSingleChoiceItems(items, checkedItem, new AlertDialog.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
mTsm.setSpellCheckerSubtype(null);
} else {
mTsm.setSpellCheckerSubtype(mSpellCheckerInfo.getSubtypeAt(which - 1));
}
if (DBG) {
final SpellCheckerSubtype subtype = mTsm.getCurrentSpellCheckerSubtype(true);
Log.d(TAG, "Current spell check locale is "
+ subtype == null ? "null" : subtype.getLocale());
}
dialog.dismiss();
}
});
mDialog = builder.create();
mDialog.show();
}
private void onSettingsButtonClicked(View arg0) {
if (mFragment != null && mSettingsIntent != null) {
try {
mFragment.startActivity(mSettingsIntent);
} catch (ActivityNotFoundException e) {
final String msg = mFragment.getString(R.string.failed_to_open_app_settings_toast,
mSpellCheckerInfo.loadLabel(mFragment.getActivity().getPackageManager()));
Toast.makeText(mFragment.getActivity(), msg, Toast.LENGTH_LONG).show();
}
}
}
private void enableButtons(boolean enabled) {
if (mSettingsButton != null) {
if (mSettingsIntent == null) {
mSettingsButton.setVisibility(View.GONE);
} else {
mSettingsButton.setEnabled(enabled);
mSettingsButton.setClickable(enabled);
mSettingsButton.setFocusable(enabled);
if (!enabled) {
mSettingsButton.setAlpha(Utils.DISABLED_ALPHA);
}
}
}
if (mSubtypeButton != null) {
if (mSpellCheckerInfo.getSubtypeCount() <= 0) {
mSubtypeButton.setVisibility(View.GONE);
} else {
mSubtypeButton.setEnabled(enabled);
mSubtypeButton.setClickable(enabled);
mSubtypeButton.setFocusable(enabled);
if (!enabled) {
mSubtypeButton.setAlpha(Utils.DISABLED_ALPHA);
}
}
}
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.inputmethod;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.preference.Preference;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.textservice.SpellCheckerInfo;
import android.widget.RadioButton;
import android.widget.Toast;
import com.android.settings.R;
import com.android.settings.Utils;
/**
* Spell checker service preference.
*
* This preference represents a spell checker service. It is used for two purposes. 1) A radio
* button on the left side is used to choose the current spell checker service. 2) A settings
* icon on the right side is used to invoke the setting activity of the spell checker service.
*/
class SpellCheckerPreference extends Preference implements OnClickListener {
interface OnRadioButtonPreferenceListener {
/**
* Called when this preference needs to be saved its state.
*
* Note that this preference is non-persistent and needs explicitly to be saved its state.
* Because changing one IME state may change other IMEs' state, this is a place to update
* other IMEs' state as well.
*
* @param pref This preference.
*/
public void onRadioButtonClicked(SpellCheckerPreference pref);
}
private final SpellCheckerInfo mSci;
private final OnRadioButtonPreferenceListener mOnRadioButtonListener;
private RadioButton mRadioButton;
private View mPrefLeftButton;
private View mSettingsButton;
private boolean mSelected;
public SpellCheckerPreference(final Context context, final SpellCheckerInfo sci,
final OnRadioButtonPreferenceListener onRadioButtonListener) {
super(context, null, 0);
setPersistent(false);
setLayoutResource(R.layout.preference_spellchecker);
setWidgetLayoutResource(R.layout.preference_spellchecker_widget);
mSci = sci;
mOnRadioButtonListener = onRadioButtonListener;
setKey(sci.getId());
setTitle(sci.loadLabel(context.getPackageManager()));
final String settingsActivity = mSci.getSettingsActivity();
if (TextUtils.isEmpty(settingsActivity)) {
setIntent(null);
} else {
final Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setClassName(mSci.getPackageName(), settingsActivity);
setIntent(intent);
}
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
mRadioButton = (RadioButton)view.findViewById(R.id.pref_radio);
mPrefLeftButton = view.findViewById(R.id.pref_left_button);
mPrefLeftButton.setOnClickListener(this);
mSettingsButton = view.findViewById(R.id.pref_right_button);
mSettingsButton.setOnClickListener(this);
updateSelectedState(mSelected);
}
@Override
public void onClick(final View v) {
if (v == mPrefLeftButton) {
mOnRadioButtonListener.onRadioButtonClicked(this);
return;
}
if (v == mSettingsButton) {
onSettingsButtonClicked();
return;
}
}
private void onSettingsButtonClicked() {
final Context context = getContext();
try {
final Intent intent = getIntent();
if (intent != null) {
// Invoke a settings activity of an spell checker.
context.startActivity(intent);
}
} catch (final ActivityNotFoundException e) {
final String message = context.getString(R.string.failed_to_open_app_settings_toast,
mSci.loadLabel(context.getPackageManager()));
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
}
}
public SpellCheckerInfo getSpellCheckerInfo() {
return mSci;
}
public void setSelected(final boolean selected) {
mSelected = selected;
updateSelectedState(selected);
}
private void updateSelectedState(final boolean selected) {
if (mRadioButton != null) {
mRadioButton.setChecked(selected);
enableSettingsButton(isEnabled() && selected);
}
}
private void enableSettingsButton(final boolean enabled) {
if (mSettingsButton == null) {
return;
}
if (getIntent() == null) {
mSettingsButton.setVisibility(View.GONE);
} else {
mSettingsButton.setEnabled(enabled);
mSettingsButton.setClickable(enabled);
mSettingsButton.setFocusable(enabled);
if (!enabled) {
mSettingsButton.setAlpha(Utils.DISABLED_ALPHA);
}
}
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.inputmethod;
import android.content.Context;
import android.util.AttributeSet;
import android.view.textservice.TextServicesManager;
// TODO: Make this non-persistent.
class SpellCheckersPreference extends CheckBoxAndSettingsPreference {
private TextServicesManager mTsm;
public SpellCheckersPreference(Context context) {
this(context, null);
}
public SpellCheckersPreference(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SpellCheckersPreference(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public SpellCheckersPreference(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
mTsm = (TextServicesManager) context.getSystemService(
Context.TEXT_SERVICES_MANAGER_SERVICE);
setChecked(mTsm.isSpellCheckerEnabled());
}
@Override
protected void onCheckBoxClicked() {
super.onCheckBoxClicked();
final boolean checked = isChecked();
mTsm.setSpellCheckerEnabled(checked);
}
}

View File

@@ -20,104 +20,201 @@ import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen;
import android.util.Log;
import android.view.textservice.SpellCheckerInfo;
import android.view.textservice.SpellCheckerSubtype;
import android.view.textservice.TextServicesManager;
import android.widget.Switch;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.SettingsPreferenceFragment;
import java.util.ArrayList;
import com.android.settings.inputmethod.SpellCheckerPreference.OnRadioButtonPreferenceListener;
import com.android.settings.widget.SwitchBar;
import com.android.settings.widget.SwitchBar.OnSwitchChangeListener;
public class SpellCheckersSettings extends SettingsPreferenceFragment
implements Preference.OnPreferenceClickListener {
implements OnSwitchChangeListener, OnPreferenceClickListener,
OnRadioButtonPreferenceListener {
private static final String TAG = SpellCheckersSettings.class.getSimpleName();
private static final boolean DBG = false;
private static final String KEY_SPELL_CHECKER_LANGUAGE = "spellchecker_language";
private static final int ITEM_ID_USE_SYSTEM_LANGUAGE = 0;
private SwitchBar mSwitchBar;
private Preference mSpellCheckerLanaguagePref;
private AlertDialog mDialog = null;
private SpellCheckerInfo mCurrentSci;
private SpellCheckerInfo[] mEnabledScis;
private TextServicesManager mTsm;
private final ArrayList<SingleSpellCheckerPreference> mSpellCheckers = new ArrayList<>();
@Override
public void onCreate(final Bundle icicle) {
super.onCreate(icicle);
mTsm = (TextServicesManager) getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
addPreferencesFromResource(R.xml.spellchecker_prefs);
updateScreen();
mSpellCheckerLanaguagePref = findPreference(KEY_SPELL_CHECKER_LANGUAGE);
mSpellCheckerLanaguagePref.setOnPreferenceClickListener(this);
mTsm = (TextServicesManager) getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
mCurrentSci = mTsm.getCurrentSpellChecker();
mEnabledScis = mTsm.getEnabledSpellCheckers();
populatePreferenceScreen();
}
// Override the behavior of {@link PreferenceFragment}.
@Override
public boolean onPreferenceTreeClick(final PreferenceScreen screen,
final Preference preference) {
return false;
private void populatePreferenceScreen() {
final PreferenceScreen screen = getPreferenceScreen();
final Context context = getActivity();
final int count = (mEnabledScis == null) ? 0 : mEnabledScis.length;
for (int index = 0; index < count; ++index) {
final SpellCheckerInfo sci = mEnabledScis[index];
final SpellCheckerPreference pref = new SpellCheckerPreference(context, sci, this);
screen.addPreference(pref);
InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref);
}
}
@Override
public void onResume() {
super.onResume();
updateScreen();
mSwitchBar = ((SettingsActivity)getActivity()).getSwitchBar();
mSwitchBar.show();
mSwitchBar.addOnSwitchChangeListener(this);
updatePreferenceScreen();
}
private void updateScreen() {
getPreferenceScreen().removeAll();
updateEnabledSpellCheckers();
@Override
public void onPause() {
super.onPause();
mSwitchBar.removeOnSwitchChangeListener(this);
}
private void updateEnabledSpellCheckers() {
@Override
public void onSwitchChanged(final Switch switchView, final boolean isChecked) {
mTsm.setSpellCheckerEnabled(isChecked);
updatePreferenceScreen();
}
private void updatePreferenceScreen() {
mCurrentSci = mTsm.getCurrentSpellChecker();
mEnabledScis = mTsm.getEnabledSpellCheckers();
if (mCurrentSci == null || mEnabledScis == null) {
return;
final boolean isSpellCheckerEnabled = mTsm.isSpellCheckerEnabled();
mSwitchBar.setChecked(isSpellCheckerEnabled);
final SpellCheckerSubtype currentScs = mTsm.getCurrentSpellCheckerSubtype(
false /* allowImplicitlySelectedSubtype */);
mSpellCheckerLanaguagePref.setSummary(getSpellCheckerSubtypeLabel(mCurrentSci, currentScs));
final PreferenceScreen screen = getPreferenceScreen();
final int count = screen.getPreferenceCount();
for (int index = 0; index < count; index++) {
final Preference preference = screen.getPreference(index);
preference.setEnabled(isSpellCheckerEnabled);
if (preference instanceof SpellCheckerPreference) {
final SpellCheckerPreference pref = (SpellCheckerPreference)preference;
final SpellCheckerInfo sci = pref.getSpellCheckerInfo();
pref.setSelected(mCurrentSci != null && mCurrentSci.getId().equals(sci.getId()));
}
}
final PackageManager pm = getPackageManager();
mSpellCheckers.clear();
for (int i = 0; i < mEnabledScis.length; ++i) {
final SpellCheckerInfo sci = mEnabledScis[i];
final SingleSpellCheckerPreference scPref = new SingleSpellCheckerPreference(
this, sci, mTsm);
mSpellCheckers.add(scPref);
scPref.setTitle(sci.loadLabel(pm));
scPref.setSelected(mCurrentSci != null && mCurrentSci.getId().equals(sci.getId()));
getPreferenceScreen().addPreference(scPref);
}
private CharSequence getSpellCheckerSubtypeLabel(final SpellCheckerInfo sci,
final SpellCheckerSubtype subtype) {
if (sci == null) {
return null;
}
if (subtype == null) {
return getString(R.string.use_system_language_to_select_input_method_subtypes);
}
return subtype.getDisplayName(
getActivity(), sci.getPackageName(), sci.getServiceInfo().applicationInfo);
}
@Override
public boolean onPreferenceClick(final Preference pref) {
for (final SingleSpellCheckerPreference scp : mSpellCheckers) {
if (pref.equals(scp)) {
if (isSystemApp(scp.getSpellCheckerInfo())) {
changeCurrentSpellChecker(scp);
} else {
showSecurityWarnDialog(scp);
}
return true;
}
if (pref == mSpellCheckerLanaguagePref) {
showChooseLanguageDialog();
return true;
}
return true;
return false;
}
private void showSecurityWarnDialog(final SingleSpellCheckerPreference scp) {
@Override
public void onRadioButtonClicked(final SpellCheckerPreference pref) {
final SpellCheckerInfo sci = pref.getSpellCheckerInfo();
final boolean isSystemApp =
(sci.getServiceInfo().applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
if (isSystemApp) {
changeCurrentSpellChecker(sci);
} else {
showSecurityWarnDialog(pref);
}
}
private static int convertSubtypeIndexToDialogItemId(final int index) { return index + 1; }
private static int convertDialogItemIdToSubtypeIndex(final int item) { return item - 1; }
private void showChooseLanguageDialog() {
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
final SpellCheckerInfo currentSci = mTsm.getCurrentSpellChecker();
final SpellCheckerSubtype currentScs = mTsm.getCurrentSpellCheckerSubtype(
false /* allowImplicitlySelectedSubtype */);
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(R.string.phone_language);
final int subtypeCount = currentSci.getSubtypeCount();
final CharSequence[] items = new CharSequence[subtypeCount + 1 /* default */ ];
items[ITEM_ID_USE_SYSTEM_LANGUAGE] = getSpellCheckerSubtypeLabel(currentSci, null);
int checkedItemId = ITEM_ID_USE_SYSTEM_LANGUAGE;
for (int index = 0; index < subtypeCount; ++index) {
final SpellCheckerSubtype subtype = currentSci.getSubtypeAt(index);
final int itemId = convertSubtypeIndexToDialogItemId(index);
items[itemId] = getSpellCheckerSubtypeLabel(currentSci, subtype);
if (subtype.equals(currentScs)) {
checkedItemId = itemId;
}
}
builder.setSingleChoiceItems(items, checkedItemId, new AlertDialog.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int item) {
if (item == ITEM_ID_USE_SYSTEM_LANGUAGE) {
mTsm.setSpellCheckerSubtype(null);
} else {
final int index = convertDialogItemIdToSubtypeIndex(item);
mTsm.setSpellCheckerSubtype(currentSci.getSubtypeAt(index));
}
if (DBG) {
final SpellCheckerSubtype subtype = mTsm.getCurrentSpellCheckerSubtype(
true /* allowImplicitlySelectedSubtype */);
Log.d(TAG, "Current spell check locale is "
+ subtype == null ? "null" : subtype.getLocale());
}
dialog.dismiss();
updatePreferenceScreen();
}
});
mDialog = builder.create();
mDialog.show();
}
private void showSecurityWarnDialog(final SpellCheckerPreference pref) {
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
final SpellCheckerInfo sci = pref.getSpellCheckerInfo();
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(android.R.string.dialog_alert_title);
final PackageManager pm = getPackageManager();
builder.setMessage(getString(R.string.spellchecker_security_warning,
scp.getSpellCheckerInfo().getServiceInfo().applicationInfo.loadLabel(pm)));
builder.setMessage(getString(R.string.spellchecker_security_warning, pref.getTitle()));
builder.setCancelable(true);
builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(final DialogInterface dialog, final int which) {
changeCurrentSpellChecker(scp);
changeCurrentSpellChecker(sci);
}
});
builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@@ -129,15 +226,11 @@ public class SpellCheckersSettings extends SettingsPreferenceFragment
mDialog.show();
}
private void changeCurrentSpellChecker(final SingleSpellCheckerPreference scp) {
mTsm.setCurrentSpellChecker(scp.getSpellCheckerInfo());
private void changeCurrentSpellChecker(final SpellCheckerInfo sci) {
mTsm.setCurrentSpellChecker(sci);
if (DBG) {
Log.d(TAG, "Current spell check is " + mTsm.getCurrentSpellChecker().getId());
}
updateScreen();
}
private static boolean isSystemApp(final SpellCheckerInfo sci) {
return (sci.getServiceInfo().applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
updatePreferenceScreen();
}
}