• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy
6  * of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */
16 
17 package com.android.inputmethod.latin;
18 
19 import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.ASCII_CAPABLE;
20 
21 import android.app.AlertDialog;
22 import android.app.Dialog;
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.SharedPreferences;
27 import android.content.res.Resources;
28 import android.os.Bundle;
29 import android.os.Parcel;
30 import android.os.Parcelable;
31 import android.preference.DialogPreference;
32 import android.preference.Preference;
33 import android.preference.PreferenceFragment;
34 import android.preference.PreferenceGroup;
35 import android.util.Pair;
36 import android.view.Menu;
37 import android.view.MenuInflater;
38 import android.view.MenuItem;
39 import android.view.View;
40 import android.view.inputmethod.InputMethodInfo;
41 import android.view.inputmethod.InputMethodSubtype;
42 import android.widget.ArrayAdapter;
43 import android.widget.Spinner;
44 import android.widget.SpinnerAdapter;
45 import android.widget.Toast;
46 
47 import com.android.inputmethod.compat.CompatUtils;
48 
49 import java.util.ArrayList;
50 import java.util.TreeSet;
51 
52 public final class AdditionalSubtypeSettings extends PreferenceFragment {
53     private SharedPreferences mPrefs;
54     private SubtypeLocaleAdapter mSubtypeLocaleAdapter;
55     private KeyboardLayoutSetAdapter mKeyboardLayoutSetAdapter;
56 
57     private boolean mIsAddingNewSubtype;
58     private AlertDialog mSubtypeEnablerNotificationDialog;
59     private String mSubtypePreferenceKeyForSubtypeEnabler;
60 
61     private static final int MENU_ADD_SUBTYPE = Menu.FIRST;
62     private static final String KEY_IS_ADDING_NEW_SUBTYPE = "is_adding_new_subtype";
63     private static final String KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN =
64             "is_subtype_enabler_notification_dialog_open";
65     private static final String KEY_SUBTYPE_FOR_SUBTYPE_ENABLER = "subtype_for_subtype_enabler";
66     static final class SubtypeLocaleItem extends Pair<String, String>
67             implements Comparable<SubtypeLocaleItem> {
SubtypeLocaleItem(final String localeString, final String displayName)68         public SubtypeLocaleItem(final String localeString, final String displayName) {
69             super(localeString, displayName);
70         }
71 
SubtypeLocaleItem(final String localeString)72         public SubtypeLocaleItem(final String localeString) {
73             this(localeString, SubtypeLocale.getSubtypeLocaleDisplayName(localeString));
74         }
75 
76         @Override
toString()77         public String toString() {
78             return second;
79         }
80 
81         @Override
compareTo(final SubtypeLocaleItem o)82         public int compareTo(final SubtypeLocaleItem o) {
83             return first.compareTo(o.first);
84         }
85     }
86 
87     static final class SubtypeLocaleAdapter extends ArrayAdapter<SubtypeLocaleItem> {
88         private static final String TAG = SubtypeLocaleAdapter.class.getSimpleName();
89         private static final boolean DEBUG_SUBTYPE_ID = false;
90 
SubtypeLocaleAdapter(final Context context)91         public SubtypeLocaleAdapter(final Context context) {
92             super(context, android.R.layout.simple_spinner_item);
93             setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
94 
95             final TreeSet<SubtypeLocaleItem> items = CollectionUtils.newTreeSet();
96             final InputMethodInfo imi = ImfUtils.getInputMethodInfoOfThisIme(context);
97             final int count = imi.getSubtypeCount();
98             for (int i = 0; i < count; i++) {
99                 final InputMethodSubtype subtype = imi.getSubtypeAt(i);
100                 if (DEBUG_SUBTYPE_ID) {
101                     android.util.Log.d(TAG, String.format("%-6s 0x%08x %11d %s",
102                             subtype.getLocale(), subtype.hashCode(), subtype.hashCode(),
103                             SubtypeLocale.getSubtypeDisplayName(subtype, context.getResources())));
104                 }
105                 if (subtype.containsExtraValueKey(ASCII_CAPABLE)) {
106                     items.add(createItem(context, subtype.getLocale()));
107                 }
108             }
109             // TODO: Should filter out already existing combinations of locale and layout.
110             addAll(items);
111         }
112 
createItem(final Context context, final String localeString)113         public static SubtypeLocaleItem createItem(final Context context,
114                 final String localeString) {
115             if (localeString.equals(SubtypeLocale.NO_LANGUAGE)) {
116                 final String displayName = context.getString(R.string.subtype_no_language);
117                 return new SubtypeLocaleItem(localeString, displayName);
118             } else {
119                 return new SubtypeLocaleItem(localeString);
120             }
121         }
122     }
123 
124     static final class KeyboardLayoutSetItem extends Pair<String, String> {
KeyboardLayoutSetItem(final InputMethodSubtype subtype)125         public KeyboardLayoutSetItem(final InputMethodSubtype subtype) {
126             super(SubtypeLocale.getKeyboardLayoutSetName(subtype),
127                     SubtypeLocale.getKeyboardLayoutSetDisplayName(subtype));
128         }
129 
130         @Override
toString()131         public String toString() {
132             return second;
133         }
134     }
135 
136     static final class KeyboardLayoutSetAdapter extends ArrayAdapter<KeyboardLayoutSetItem> {
KeyboardLayoutSetAdapter(final Context context)137         public KeyboardLayoutSetAdapter(final Context context) {
138             super(context, android.R.layout.simple_spinner_item);
139             setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
140 
141             // TODO: Should filter out already existing combinations of locale and layout.
142             for (final String layout : SubtypeLocale.getPredefinedKeyboardLayoutSet()) {
143                 // This is a dummy subtype with NO_LANGUAGE, only for display.
144                 final InputMethodSubtype subtype = AdditionalSubtype.createAdditionalSubtype(
145                         SubtypeLocale.NO_LANGUAGE, layout, null);
146                 add(new KeyboardLayoutSetItem(subtype));
147             }
148         }
149     }
150 
151     private interface SubtypeDialogProxy {
onRemovePressed(SubtypePreference subtypePref)152         public void onRemovePressed(SubtypePreference subtypePref);
onSavePressed(SubtypePreference subtypePref)153         public void onSavePressed(SubtypePreference subtypePref);
onAddPressed(SubtypePreference subtypePref)154         public void onAddPressed(SubtypePreference subtypePref);
getSubtypeLocaleAdapter()155         public SubtypeLocaleAdapter getSubtypeLocaleAdapter();
getKeyboardLayoutSetAdapter()156         public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter();
157     }
158 
159     static final class SubtypePreference extends DialogPreference
160             implements DialogInterface.OnCancelListener {
161         private static final String KEY_PREFIX = "subtype_pref_";
162         private static final String KEY_NEW_SUBTYPE = KEY_PREFIX + "new";
163 
164         private InputMethodSubtype mSubtype;
165         private InputMethodSubtype mPreviousSubtype;
166 
167         private final SubtypeDialogProxy mProxy;
168         private Spinner mSubtypeLocaleSpinner;
169         private Spinner mKeyboardLayoutSetSpinner;
170 
newIncompleteSubtypePreference(final Context context, final SubtypeDialogProxy proxy)171         public static SubtypePreference newIncompleteSubtypePreference(final Context context,
172                 final SubtypeDialogProxy proxy) {
173             return new SubtypePreference(context, null, proxy);
174         }
175 
SubtypePreference(final Context context, final InputMethodSubtype subtype, final SubtypeDialogProxy proxy)176         public SubtypePreference(final Context context, final InputMethodSubtype subtype,
177                 final SubtypeDialogProxy proxy) {
178             super(context, null);
179             setDialogLayoutResource(R.layout.additional_subtype_dialog);
180             setPersistent(false);
181             mProxy = proxy;
182             setSubtype(subtype);
183         }
184 
show()185         public void show() {
186             showDialog(null);
187         }
188 
isIncomplete()189         public final boolean isIncomplete() {
190             return mSubtype == null;
191         }
192 
getSubtype()193         public InputMethodSubtype getSubtype() {
194             return mSubtype;
195         }
196 
setSubtype(final InputMethodSubtype subtype)197         public void setSubtype(final InputMethodSubtype subtype) {
198             mPreviousSubtype = mSubtype;
199             mSubtype = subtype;
200             if (isIncomplete()) {
201                 setTitle(null);
202                 setDialogTitle(R.string.add_style);
203                 setKey(KEY_NEW_SUBTYPE);
204             } else {
205                 final String displayName = SubtypeLocale.getSubtypeDisplayName(
206                         subtype, getContext().getResources());
207                 setTitle(displayName);
208                 setDialogTitle(displayName);
209                 setKey(KEY_PREFIX + subtype.getLocale() + "_"
210                         + SubtypeLocale.getKeyboardLayoutSetName(subtype));
211             }
212         }
213 
revert()214         public void revert() {
215             setSubtype(mPreviousSubtype);
216         }
217 
hasBeenModified()218         public boolean hasBeenModified() {
219             return mSubtype != null && !mSubtype.equals(mPreviousSubtype);
220         }
221 
222         @Override
onCreateDialogView()223         protected View onCreateDialogView() {
224             final View v = super.onCreateDialogView();
225             mSubtypeLocaleSpinner = (Spinner) v.findViewById(R.id.subtype_locale_spinner);
226             mSubtypeLocaleSpinner.setAdapter(mProxy.getSubtypeLocaleAdapter());
227             mKeyboardLayoutSetSpinner = (Spinner) v.findViewById(R.id.keyboard_layout_set_spinner);
228             mKeyboardLayoutSetSpinner.setAdapter(mProxy.getKeyboardLayoutSetAdapter());
229             return v;
230         }
231 
232         @Override
onPrepareDialogBuilder(final AlertDialog.Builder builder)233         protected void onPrepareDialogBuilder(final AlertDialog.Builder builder) {
234             final Context context = builder.getContext();
235             builder.setCancelable(true).setOnCancelListener(this);
236             if (isIncomplete()) {
237                 builder.setPositiveButton(R.string.add, this)
238                         .setNegativeButton(android.R.string.cancel, this);
239             } else {
240                 builder.setPositiveButton(R.string.save, this)
241                         .setNeutralButton(android.R.string.cancel, this)
242                         .setNegativeButton(R.string.remove, this);
243                 final SubtypeLocaleItem localeItem = SubtypeLocaleAdapter.createItem(
244                         context, mSubtype.getLocale());
245                 final KeyboardLayoutSetItem layoutItem = new KeyboardLayoutSetItem(mSubtype);
246                 setSpinnerPosition(mSubtypeLocaleSpinner, localeItem);
247                 setSpinnerPosition(mKeyboardLayoutSetSpinner, layoutItem);
248             }
249         }
250 
setSpinnerPosition(final Spinner spinner, final Object itemToSelect)251         private static void setSpinnerPosition(final Spinner spinner, final Object itemToSelect) {
252             final SpinnerAdapter adapter = spinner.getAdapter();
253             final int count = adapter.getCount();
254             for (int i = 0; i < count; i++) {
255                 final Object item = spinner.getItemAtPosition(i);
256                 if (item.equals(itemToSelect)) {
257                     spinner.setSelection(i);
258                     return;
259                 }
260             }
261         }
262 
263         @Override
onCancel(final DialogInterface dialog)264         public void onCancel(final DialogInterface dialog) {
265             if (isIncomplete()) {
266                 mProxy.onRemovePressed(this);
267             }
268         }
269 
270         @Override
onClick(final DialogInterface dialog, final int which)271         public void onClick(final DialogInterface dialog, final int which) {
272             super.onClick(dialog, which);
273             switch (which) {
274             case DialogInterface.BUTTON_POSITIVE:
275                 final boolean isEditing = !isIncomplete();
276                 final SubtypeLocaleItem locale =
277                         (SubtypeLocaleItem) mSubtypeLocaleSpinner.getSelectedItem();
278                 final KeyboardLayoutSetItem layout =
279                         (KeyboardLayoutSetItem) mKeyboardLayoutSetSpinner.getSelectedItem();
280                 final InputMethodSubtype subtype = AdditionalSubtype.createAdditionalSubtype(
281                         locale.first, layout.first, ASCII_CAPABLE);
282                 setSubtype(subtype);
283                 notifyChanged();
284                 if (isEditing) {
285                     mProxy.onSavePressed(this);
286                 } else {
287                     mProxy.onAddPressed(this);
288                 }
289                 break;
290             case DialogInterface.BUTTON_NEUTRAL:
291                 // Nothing to do
292                 break;
293             case DialogInterface.BUTTON_NEGATIVE:
294                 mProxy.onRemovePressed(this);
295                 break;
296             }
297         }
298 
getSpinnerPosition(final Spinner spinner)299         private static int getSpinnerPosition(final Spinner spinner) {
300             if (spinner == null) return -1;
301             return spinner.getSelectedItemPosition();
302         }
303 
setSpinnerPosition(final Spinner spinner, final int position)304         private static void setSpinnerPosition(final Spinner spinner, final int position) {
305             if (spinner == null || position < 0) return;
306             spinner.setSelection(position);
307         }
308 
309         @Override
onSaveInstanceState()310         protected Parcelable onSaveInstanceState() {
311             final Parcelable superState = super.onSaveInstanceState();
312             final Dialog dialog = getDialog();
313             if (dialog == null || !dialog.isShowing()) {
314                 return superState;
315             }
316 
317             final SavedState myState = new SavedState(superState);
318             myState.mSubtype = mSubtype;
319             myState.mSubtypeLocaleSelectedPos = getSpinnerPosition(mSubtypeLocaleSpinner);
320             myState.mKeyboardLayoutSetSelectedPos = getSpinnerPosition(mKeyboardLayoutSetSpinner);
321             return myState;
322         }
323 
324         @Override
onRestoreInstanceState(final Parcelable state)325         protected void onRestoreInstanceState(final Parcelable state) {
326             if (!(state instanceof SavedState)) {
327                 super.onRestoreInstanceState(state);
328                 return;
329             }
330 
331             final SavedState myState = (SavedState) state;
332             super.onRestoreInstanceState(myState.getSuperState());
333             setSpinnerPosition(mSubtypeLocaleSpinner, myState.mSubtypeLocaleSelectedPos);
334             setSpinnerPosition(mKeyboardLayoutSetSpinner, myState.mKeyboardLayoutSetSelectedPos);
335             setSubtype(myState.mSubtype);
336         }
337 
338         static final class SavedState extends Preference.BaseSavedState {
339             InputMethodSubtype mSubtype;
340             int mSubtypeLocaleSelectedPos;
341             int mKeyboardLayoutSetSelectedPos;
342 
SavedState(final Parcelable superState)343             public SavedState(final Parcelable superState) {
344                 super(superState);
345             }
346 
347             @Override
writeToParcel(final Parcel dest, final int flags)348             public void writeToParcel(final Parcel dest, final int flags) {
349                 super.writeToParcel(dest, flags);
350                 dest.writeInt(mSubtypeLocaleSelectedPos);
351                 dest.writeInt(mKeyboardLayoutSetSelectedPos);
352                 dest.writeParcelable(mSubtype, 0);
353             }
354 
SavedState(final Parcel source)355             public SavedState(final Parcel source) {
356                 super(source);
357                 mSubtypeLocaleSelectedPos = source.readInt();
358                 mKeyboardLayoutSetSelectedPos = source.readInt();
359                 mSubtype = (InputMethodSubtype)source.readParcelable(null);
360             }
361 
362             @SuppressWarnings("hiding")
363             public static final Parcelable.Creator<SavedState> CREATOR =
364                     new Parcelable.Creator<SavedState>() {
365                         @Override
366                         public SavedState createFromParcel(final Parcel source) {
367                             return new SavedState(source);
368                         }
369 
370                         @Override
371                         public SavedState[] newArray(final int size) {
372                             return new SavedState[size];
373                         }
374                     };
375         }
376     }
377 
AdditionalSubtypeSettings()378     public AdditionalSubtypeSettings() {
379         // Empty constructor for fragment generation.
380     }
381 
382     @Override
onCreate(final Bundle savedInstanceState)383     public void onCreate(final Bundle savedInstanceState) {
384         super.onCreate(savedInstanceState);
385 
386         addPreferencesFromResource(R.xml.additional_subtype_settings);
387         setHasOptionsMenu(true);
388 
389         mPrefs = getPreferenceManager().getSharedPreferences();
390     }
391 
392     @Override
onActivityCreated(final Bundle savedInstanceState)393     public void onActivityCreated(final Bundle savedInstanceState) {
394         final Context context = getActivity();
395         mSubtypeLocaleAdapter = new SubtypeLocaleAdapter(context);
396         mKeyboardLayoutSetAdapter = new KeyboardLayoutSetAdapter(context);
397 
398         final String prefSubtypes =
399                 SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources());
400         setPrefSubtypes(prefSubtypes, context);
401 
402         mIsAddingNewSubtype = (savedInstanceState != null)
403                 && savedInstanceState.containsKey(KEY_IS_ADDING_NEW_SUBTYPE);
404         if (mIsAddingNewSubtype) {
405             getPreferenceScreen().addPreference(
406                     SubtypePreference.newIncompleteSubtypePreference(context, mSubtypeProxy));
407         }
408 
409         super.onActivityCreated(savedInstanceState);
410 
411         if (savedInstanceState != null && savedInstanceState.containsKey(
412                 KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN)) {
413             mSubtypePreferenceKeyForSubtypeEnabler = savedInstanceState.getString(
414                     KEY_SUBTYPE_FOR_SUBTYPE_ENABLER);
415             final SubtypePreference subtypePref = (SubtypePreference)findPreference(
416                     mSubtypePreferenceKeyForSubtypeEnabler);
417             mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
418             mSubtypeEnablerNotificationDialog.show();
419         }
420     }
421 
422     @Override
onSaveInstanceState(final Bundle outState)423     public void onSaveInstanceState(final Bundle outState) {
424         super.onSaveInstanceState(outState);
425         if (mIsAddingNewSubtype) {
426             outState.putBoolean(KEY_IS_ADDING_NEW_SUBTYPE, true);
427         }
428         if (mSubtypeEnablerNotificationDialog != null
429                 && mSubtypeEnablerNotificationDialog.isShowing()) {
430             outState.putBoolean(KEY_IS_SUBTYPE_ENABLER_NOTIFICATION_DIALOG_OPEN, true);
431             outState.putString(
432                     KEY_SUBTYPE_FOR_SUBTYPE_ENABLER, mSubtypePreferenceKeyForSubtypeEnabler);
433         }
434     }
435 
436     private final SubtypeDialogProxy mSubtypeProxy = new SubtypeDialogProxy() {
437         @Override
438         public void onRemovePressed(final SubtypePreference subtypePref) {
439             mIsAddingNewSubtype = false;
440             final PreferenceGroup group = getPreferenceScreen();
441             group.removePreference(subtypePref);
442             ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), getSubtypes());
443         }
444 
445         @Override
446         public void onSavePressed(final SubtypePreference subtypePref) {
447             final InputMethodSubtype subtype = subtypePref.getSubtype();
448             if (!subtypePref.hasBeenModified()) {
449                 return;
450             }
451             if (findDuplicatedSubtype(subtype) == null) {
452                 ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), getSubtypes());
453                 return;
454             }
455 
456             // Saved subtype is duplicated.
457             final PreferenceGroup group = getPreferenceScreen();
458             group.removePreference(subtypePref);
459             subtypePref.revert();
460             group.addPreference(subtypePref);
461             showSubtypeAlreadyExistsToast(subtype);
462         }
463 
464         @Override
465         public void onAddPressed(final SubtypePreference subtypePref) {
466             mIsAddingNewSubtype = false;
467             final InputMethodSubtype subtype = subtypePref.getSubtype();
468             if (findDuplicatedSubtype(subtype) == null) {
469                 ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), getSubtypes());
470                 mSubtypePreferenceKeyForSubtypeEnabler = subtypePref.getKey();
471                 mSubtypeEnablerNotificationDialog = createDialog(subtypePref);
472                 mSubtypeEnablerNotificationDialog.show();
473                 return;
474             }
475 
476             // Newly added subtype is duplicated.
477             final PreferenceGroup group = getPreferenceScreen();
478             group.removePreference(subtypePref);
479             showSubtypeAlreadyExistsToast(subtype);
480         }
481 
482         @Override
483         public SubtypeLocaleAdapter getSubtypeLocaleAdapter() {
484             return mSubtypeLocaleAdapter;
485         }
486 
487         @Override
488         public KeyboardLayoutSetAdapter getKeyboardLayoutSetAdapter() {
489             return mKeyboardLayoutSetAdapter;
490         }
491     };
492 
showSubtypeAlreadyExistsToast(final InputMethodSubtype subtype)493     private void showSubtypeAlreadyExistsToast(final InputMethodSubtype subtype) {
494         final Context context = getActivity();
495         final Resources res = context.getResources();
496         final String message = res.getString(R.string.custom_input_style_already_exists,
497                 SubtypeLocale.getSubtypeDisplayName(subtype, res));
498         Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
499     }
500 
findDuplicatedSubtype(final InputMethodSubtype subtype)501     private InputMethodSubtype findDuplicatedSubtype(final InputMethodSubtype subtype) {
502         final String localeString = subtype.getLocale();
503         final String keyboardLayoutSetName = SubtypeLocale.getKeyboardLayoutSetName(subtype);
504         return ImfUtils.findSubtypeByLocaleAndKeyboardLayoutSet(
505                 getActivity(), localeString, keyboardLayoutSetName);
506     }
507 
createDialog( @uppressWarnings"unused") final SubtypePreference subtypePref)508     private AlertDialog createDialog(
509             @SuppressWarnings("unused") final SubtypePreference subtypePref) {
510         final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
511         builder.setTitle(R.string.custom_input_styles_title)
512                 .setMessage(R.string.custom_input_style_note_message)
513                 .setNegativeButton(R.string.not_now, null)
514                 .setPositiveButton(R.string.enable, new DialogInterface.OnClickListener() {
515                     @Override
516                     public void onClick(DialogInterface dialog, int which) {
517                         final Intent intent = CompatUtils.getInputLanguageSelectionIntent(
518                                 ImfUtils.getInputMethodIdOfThisIme(getActivity()),
519                                 Intent.FLAG_ACTIVITY_NEW_TASK
520                                 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
521                                 | Intent.FLAG_ACTIVITY_CLEAR_TOP);
522                         // TODO: Add newly adding subtype to extra value of the intent as a hint
523                         // for the input language selection activity.
524                         // intent.putExtra("newlyAddedSubtype", subtypePref.getSubtype());
525                         startActivity(intent);
526                     }
527                 });
528 
529         return builder.create();
530     }
531 
setPrefSubtypes(final String prefSubtypes, final Context context)532     private void setPrefSubtypes(final String prefSubtypes, final Context context) {
533         final PreferenceGroup group = getPreferenceScreen();
534         group.removeAll();
535         final InputMethodSubtype[] subtypesArray =
536                 AdditionalSubtype.createAdditionalSubtypesArray(prefSubtypes);
537         for (final InputMethodSubtype subtype : subtypesArray) {
538             final SubtypePreference pref = new SubtypePreference(
539                     context, subtype, mSubtypeProxy);
540             group.addPreference(pref);
541         }
542     }
543 
getSubtypes()544     private InputMethodSubtype[] getSubtypes() {
545         final PreferenceGroup group = getPreferenceScreen();
546         final ArrayList<InputMethodSubtype> subtypes = CollectionUtils.newArrayList();
547         final int count = group.getPreferenceCount();
548         for (int i = 0; i < count; i++) {
549             final Preference pref = group.getPreference(i);
550             if (pref instanceof SubtypePreference) {
551                 final SubtypePreference subtypePref = (SubtypePreference)pref;
552                 // We should not save newly adding subtype to preference because it is incomplete.
553                 if (subtypePref.isIncomplete()) continue;
554                 subtypes.add(subtypePref.getSubtype());
555             }
556         }
557         return subtypes.toArray(new InputMethodSubtype[subtypes.size()]);
558     }
559 
560     @Override
onPause()561     public void onPause() {
562         super.onPause();
563         final String oldSubtypes = SettingsValues.getPrefAdditionalSubtypes(mPrefs, getResources());
564         final InputMethodSubtype[] subtypes = getSubtypes();
565         final String prefSubtypes = AdditionalSubtype.createPrefSubtypes(subtypes);
566         if (prefSubtypes.equals(oldSubtypes)) {
567             return;
568         }
569 
570         final SharedPreferences.Editor editor = mPrefs.edit();
571         try {
572             editor.putString(Settings.PREF_CUSTOM_INPUT_STYLES, prefSubtypes);
573         } finally {
574             editor.apply();
575         }
576         ImfUtils.setAdditionalInputMethodSubtypes(getActivity(), subtypes);
577     }
578 
579     @Override
onCreateOptionsMenu(final Menu menu, final MenuInflater inflater)580     public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
581         final MenuItem addSubtypeMenu = menu.add(0, MENU_ADD_SUBTYPE, 0, R.string.add_style);
582         addSubtypeMenu.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
583     }
584 
585     @Override
onOptionsItemSelected(final MenuItem item)586     public boolean onOptionsItemSelected(final MenuItem item) {
587         final int itemId = item.getItemId();
588         if (itemId == MENU_ADD_SUBTYPE) {
589             final SubtypePreference newSubtype =
590                     SubtypePreference.newIncompleteSubtypePreference(getActivity(), mSubtypeProxy);
591             getPreferenceScreen().addPreference(newSubtype);
592             newSubtype.show();
593             mIsAddingNewSubtype = true;
594             return true;
595         }
596         return super.onOptionsItemSelected(item);
597     }
598 }
599