Android P Language设置
在AndroidManifest文件中定位:
<activity android:name=".Settings$LanguageAndInputSettingsActivity" android:label="@string/language_settings" android:icon="@drawable/ic_settings_language" android:taskAffinity="com.android.settings" android:parentActivityName="Settings"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.VOICE_LAUNCH" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> <intent-filter android:priority="260"> <action android:name="com.android.settings.action.SETTINGS"/> </intent-filter> <meta-data android:name="com.android.settings.category"
//分类,表示属于系统分类下 android:value="com.android.settings.category.ia.system"/> <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
//对应的路径 android:value="com.android.settings.language.LanguageAndInputSettings"/> <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" android:value="true"/> </activity>
@Override protected int getPreferenceScreenResId() { //要加载的布局 return R.xml.language_and_input; } //初始化controllers @Override protected List<AbstractPreferenceController> createPreferenceControllers(Context context) { return buildPreferenceControllers(context, getLifecycle()); } private static List<AbstractPreferenceController> buildPreferenceControllers( @NonNull Context context, @Nullable Lifecycle lifecycle) { final List<AbstractPreferenceController> controllers = new ArrayList<>(); // Language controllers.add(new PhoneLanguagePreferenceController(context)); // Input final VirtualKeyboardPreferenceController virtualKeyboardPreferenceController = new VirtualKeyboardPreferenceController(context); final PhysicalKeyboardPreferenceController physicalKeyboardPreferenceController = new PhysicalKeyboardPreferenceController(context, lifecycle); controllers.add(virtualKeyboardPreferenceController); controllers.add(physicalKeyboardPreferenceController); controllers.add(new PreferenceCategoryController(context, KEY_KEYBOARDS_CATEGORY).setChildren( Arrays.asList(virtualKeyboardPreferenceController, physicalKeyboardPreferenceController))); // Pointer and Tts final TtsPreferenceController ttsPreferenceController = new TtsPreferenceController(context, new TtsEngines(context)); controllers.add(ttsPreferenceController); final PointerSpeedController pointerController = new PointerSpeedController(context); controllers.add(pointerController); controllers.add(new PreferenceCategoryController(context, KEY_POINTER_AND_TTS_CATEGORY).setChildren( Arrays.asList(pointerController, ttsPreferenceController))); // Input Assistance controllers.add(new SpellCheckerPreferenceController(context)); controllers.add(new DefaultAutofillPreferenceController(context)); controllers.add(new UserDictionaryPreferenceController(context)); return controllers; }
先看到language的controller->PhoneLanguagePreferenceController
@Override public boolean isAvailable() { //判断是否可用 return mContext.getResources().getBoolean(R.bool.config_show_phone_language) && mContext.getAssets().getLocales().length > 1; } @Override public void updateState(Preference preference) { if (preference == null) { return; } //更新Summary final String localeNames = FeatureFactory.getFactory(mContext) .getLocaleFeatureProvider().getLocaleNames(); preference.setSummary(localeNames); } //添加进不需要索引的list(即移除索引,因为该preference与其父界面名称一致) @Override public void updateNonIndexableKeys(List<String> keys) { // No index needed, because this pref has the same name as the parent page. Indexing it will // make search page look like there are duplicate result, creating confusion. keys.add(getPreferenceKey()); } //获得preference的key @Override public String getPreferenceKey() { return KEY_PHONE_LANGUAGE; } @Override public boolean handlePreferenceTreeClick(Preference preference) { if (!KEY_PHONE_LANGUAGE.equals(preference.getKey())) { return false; } //新建SubSettingLauncher加载新的界面 new SubSettingLauncher(mContext) .setDestination(LocaleListEditor.class.getName()) .setSourceMetricsCategory(MetricsProto.MetricsEvent.SETTINGS_LANGUAGE_CATEGORY) .setTitle(R.string.pref_title_lang_selection) .launch(); return true; }
PhoneLanguagePreferenceController继承于RestrictedSettingsFragment并实现了LocalePickerWithRegion.LocaleSelectedListener接口
RestrictedSettingsFragment是所有需要pin码保护的Settings子页面的基类,主要控制进入该设置项前的验证等。打开java文件
/** * A two-step locale picker. It shows a language, then a country. * * <p>It shows suggestions at the top, then the rest of the locales. * Allows the user to search for locales using both their native name and their name in the * default locale.</p> */ public class LocalePickerWithRegion extends ListFragment implements SearchView.OnQueryTextListener {
看到注释部分,这里告诉我们该类是一个选择器,用于显示语言以及所属国家,会在顶部显示建议语言,然后再显示所有可用的语言供选择,并且允许用户使用名称进行搜索。
public interface LocaleSelectedListener { /** * The classes that want to retrieve the locale picked should implement this method. * @param locale the locale picked. */ //方法在子类被重写 void onLocaleSelected(LocaleStore.LocaleInfo locale); } @Override public void onListItemClick(ListView l, View v, int position, long id) { final LocaleStore.LocaleInfo locale = (LocaleStore.LocaleInfo) getListAdapter().getItem(position); //设置listener选中 if (locale.getParent() != null) { if (mListener != null) { mListener.onLocaleSelected(locale); } //设置后返回到父界面 returnToParentFrame(); }
重新回到LocaleListEditor,看到被重写的onLocaleSelected方法
@Override public void onLocaleSelected(LocaleStore.LocaleInfo locale) { mAdapter.addLocale(locale); updateVisibilityOfRemoveMenu(); }
在调用Adapter的addLocale方法后更新了界面。
void addLocale(LocaleStore.LocaleInfo li) { /*UNISOC for bug 945144 repetition localeInfo not add into list @{ */ if (mFeedItemList.contains(li)) { Log.d(TAG," mFeedItemList = " + mFeedItemList); return; } /* @} */ //添加后刷新界面,做更新处理 mFeedItemList.add(li); notifyItemInserted(mFeedItemList.size() - 1); doTheUpdate(); } public void doTheUpdate() { ..... updateLocalesWhenAnimationStops(ll); } public void updateLocalesWhenAnimationStops(final LocaleList localeList) { .... //调用LocalePicker的更新方法 LocalePicker.updateLocales(mLocalesToSetNext); ..... }
最后更新到用户的系统配置中
public static void updateLocales(LocaleList locales) { try { final IActivityManager am = ActivityManager.getService(); final Configuration config = am.getConfiguration(); config.setLocales(locales); config.userSetLocale = true; am.updatePersistentConfiguration(config); // Trigger the dirty bit for the Settings Provider. BackupManager.dataChanged("com.android.providers.settings"); } catch (RemoteException e) { // Intentionally left blank } }
在LocaleListEditor的onCreate方法中对Adapter和feedsList进行了初始化
final List<LocaleStore.LocaleInfo> feedsList = getUserLocaleList(); mAdapter = new LocaleDragAndDropAdapter(this.getContext(), feedsList);
private List<LocaleStore.LocaleInfo> getUserLocaleList() { final List<LocaleStore.LocaleInfo> result = new ArrayList<>(); //调用Picker的getLocales方法后取出info赋值给result集合 final LocaleList localeList = LocalePicker.getLocales(); for (int i = 0; i < localeList.size(); i++) { Locale locale = localeList.get(i); result.add(LocaleStore.getLocaleInfo(locale)); } //分那会result集合 return result; }
说完初始化和添加,下面分析删除,看到覆写的onOptionsItemSelected方法,当点击右上角菜单选择删除后会判断是否处于删除模式,如果是则显示删除警告提醒,如果不是则设置为删除模式。
private void setRemoveMode(boolean mRemoveMode) { this.mRemoveMode = mRemoveMode; //调用Adapter的设置移除模式方法去更新界面 mAdapter.setRemoveMode(mRemoveMode); mAddLanguage.setVisibility(mRemoveMode ? View.INVISIBLE : View.VISIBLE); updateVisibilityOfRemoveMenu(); } //Adapter设置自身为移除模式并且更新UI,将所有的item设置为未选中状态 void setRemoveMode(boolean removeMode) { mRemoveMode = removeMode; int itemCount = mFeedItemList.size(); for (int i = 0; i < itemCount; i++) { mFeedItemList.get(i).setChecked(false); notifyItemChanged(i); } }
然后在onBindViewHolder中给每个checkbox设置监听,更改选中状态,此时用户选择点击删除按钮,就回到点击事件判断中的弹出删除警告方法,用户确认之后,关闭移除模式,并且调用Adapter的removeChecked方法移除所选中的item
private void showRemoveLocaleWarningDialog() { .... .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mRemoveMode = false; mShowingRemoveDialog = false; mAdapter.removeChecked(); setRemoveMode(false); } }) //Adapter移除方法 void removeChecked() { int itemCount = mFeedItemList.size(); for (int i = itemCount - 1; i >= 0; i--) { if (mFeedItemList.get(i).getChecked()) { mFeedItemList.remove(i); } } notifyDataSetChanged(); doTheUpdate(); }

浙公网安备 33010602011771号