| /* |
| * Copyright (C) 2009 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.customlocale2; |
| |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Locale; |
| |
| import android.app.ActivityManagerNative; |
| import android.app.AlertDialog; |
| import android.app.Dialog; |
| import android.app.IActivityManager; |
| import android.app.ListActivity; |
| import android.content.DialogInterface; |
| import android.content.Intent; |
| import android.content.SharedPreferences; |
| import android.content.res.Configuration; |
| import android.os.Bundle; |
| import android.os.RemoteException; |
| import android.util.Log; |
| import android.view.ContextMenu; |
| import android.view.View; |
| import android.view.ContextMenu.ContextMenuInfo; |
| import android.widget.ArrayAdapter; |
| import android.widget.Button; |
| import android.widget.ListAdapter; |
| import android.widget.ListView; |
| import android.widget.TextView; |
| import android.widget.Toast; |
| import android.widget.AdapterView.AdapterContextMenuInfo; |
| |
| /** |
| * Displays the list of system locales as well as maintain a custom list of user |
| * locales. The user can select a locale and apply it or it can create or remove |
| * a custom locale. |
| */ |
| public class CustomLocaleActivity extends ListActivity { |
| |
| private static final String TAG = "CustomLocale"; |
| private static final boolean DEBUG = true; |
| |
| private static final int DLG_REMOVE_ID = 0; |
| |
| private static final String CUSTOM_LOCALES_SEP = " "; |
| private static final String CUSTOM_LOCALES = "custom_locales"; |
| |
| /** Request code returned when the NewLocaleDialog activity finishes. */ |
| private static final int UPDATE_LIST = 42; |
| /** Menu item id for applying a locale */ |
| private static final int MENU_APPLY = 43; |
| /** Menu item id for removing a custom locale */ |
| private static final int MENU_REMOVE = 44; |
| |
| /** List view displaying system and custom locales. */ |
| private ListView mListView; |
| /** Textview used to display current locale */ |
| private TextView mCurrentLocaleTextView; |
| /** Private shared preferences of this activity. */ |
| private SharedPreferences mPrefs; |
| |
| private Button mRemoveLocaleButton; |
| private Button mSelectLocaleButton; |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| setContentView(R.layout.main); |
| |
| mPrefs = getPreferences(MODE_PRIVATE); |
| |
| Button addLocaleButton = (Button) findViewById(R.id.add_new_locale_button); |
| mRemoveLocaleButton = (Button) findViewById(R.id.remove_locale_button); |
| mSelectLocaleButton = (Button) findViewById(R.id.select_locale_button); |
| |
| addLocaleButton.setOnClickListener(new View.OnClickListener() { |
| public void onClick(View v) { |
| onAddNewLocale(); |
| } |
| }); |
| |
| mRemoveLocaleButton.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| showDialog(DLG_REMOVE_ID); |
| } |
| }); |
| |
| mSelectLocaleButton.setOnClickListener(new View.OnClickListener() { |
| @Override |
| public void onClick(View v) { |
| onSelectLocale(); |
| } |
| }); |
| |
| mListView = (ListView) findViewById(android.R.id.list); |
| mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); |
| mListView.setItemsCanFocus(false); |
| mListView.setFocusable(true); |
| mListView.setFocusableInTouchMode(true); |
| mListView.requestFocus(); |
| setupLocaleList(); |
| |
| mCurrentLocaleTextView = (TextView) findViewById(R.id.current_locale); |
| displayCurrentLocale(); |
| } |
| |
| @Override |
| protected void onResume() { |
| super.onResume(); |
| updateLocaleButtons(); |
| } |
| |
| @Override |
| protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
| super.onActivityResult(requestCode, resultCode, data); |
| |
| if (requestCode == UPDATE_LIST && resultCode == RESULT_OK && data != null) { |
| String locale = data.getExtras().getString(NewLocaleDialog.INTENT_EXTRA_LOCALE); |
| if (locale != null && locale.length() > 0) { |
| // Get current custom locale list |
| String customLocales = mPrefs.getString(CUSTOM_LOCALES, null); |
| |
| // Update |
| if (customLocales == null) { |
| customLocales = locale; |
| } else { |
| customLocales += CUSTOM_LOCALES_SEP + locale; |
| } |
| |
| // Save prefs |
| if (DEBUG) { |
| Log.d(TAG, "add/customLocales: " + customLocales); |
| } |
| mPrefs.edit().putString(CUSTOM_LOCALES, customLocales).commit(); |
| |
| Toast.makeText(this, |
| getString(R.string.added_custom_locale_1s, locale), |
| Toast.LENGTH_SHORT) |
| .show(); |
| |
| // Update list view |
| setupLocaleList(); |
| |
| // Find the item to select it in the list view |
| checkLocaleInList(locale); |
| |
| if (data.getExtras().getBoolean(NewLocaleDialog.INTENT_EXTRA_SELECT)) { |
| changeSystemLocale(locale); |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected void onListItemClick(ListView l, View v, int position, long id) { |
| super.onListItemClick(l, v, position, id); |
| updateLocaleButtons(); |
| } |
| |
| @Override |
| public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { |
| super.onCreateContextMenu(menu, v, menuInfo); |
| |
| if (menuInfo instanceof AdapterContextMenuInfo) { |
| int position = ((AdapterContextMenuInfo) menuInfo).position; |
| Object o = mListView.getItemAtPosition(position); |
| if (o instanceof LocaleInfo) { |
| if (((LocaleInfo) o).isCustom()) { |
| menu.setHeaderTitle("System Locale"); |
| menu.add(0, MENU_APPLY, 0, "Apply"); |
| } else { |
| menu.setHeaderTitle("Custom Locale"); |
| menu.add(0, MENU_APPLY, 0, "Apply"); |
| menu.add(0, MENU_REMOVE, 0, "Remove"); |
| } |
| } |
| } |
| } |
| |
| @Override |
| protected Dialog onCreateDialog(int id) { |
| if (id == DLG_REMOVE_ID) { |
| return createRemoveLocaleDialog(); |
| } |
| return super.onCreateDialog(id); |
| } |
| |
| //--- private parts --- |
| |
| private void setupLocaleList() { |
| if (DEBUG) { |
| Log.d(TAG, "Update locate list"); |
| } |
| |
| ArrayList<LocaleInfo> data = new ArrayList<LocaleInfo>(); |
| |
| // Insert all system locales |
| String[] locales = getAssets().getLocales(); |
| for (String locale : locales) { |
| if (locale != null && locale.length() > 0) { |
| Locale loc = new Locale(locale); |
| data.add(new LocaleInfo(locale, loc.getDisplayName())); |
| } |
| } |
| locales = null; |
| |
| // Insert all custom locales |
| String customLocales = mPrefs.getString(CUSTOM_LOCALES, ""); |
| if (DEBUG) { |
| Log.d(TAG, "customLocales: " + customLocales); |
| } |
| for (String locale : customLocales.split(CUSTOM_LOCALES_SEP)) { |
| if (locale != null && locale.length() > 0) { |
| Locale loc = new Locale(locale); |
| data.add(new LocaleInfo( |
| locale, |
| loc.getDisplayName(), |
| true /*custom*/)); |
| } |
| } |
| |
| // Sort all locales by code |
| Collections.sort(data, new Comparator<LocaleInfo>() { |
| public int compare(LocaleInfo lhs, LocaleInfo rhs) { |
| return lhs.getLocale().compareTo(rhs.getLocale()); |
| } |
| }); |
| |
| // Update the list view adapter |
| mListView.setAdapter(new ArrayAdapter<LocaleInfo>( |
| this, |
| android.R.layout.simple_list_item_single_choice, |
| data)); |
| updateLocaleButtons(); |
| } |
| |
| private void changeSystemLocale(String locale) { |
| if (ChangeLocale.changeSystemLocale(locale)) { |
| Toast.makeText(this, |
| getString(R.string.select_locale_1s, locale), |
| Toast.LENGTH_SHORT) |
| .show(); |
| } |
| } |
| |
| private void displayCurrentLocale() { |
| try { |
| IActivityManager am = ActivityManagerNative.getDefault(); |
| Configuration config = am.getConfiguration(); |
| |
| if (config.locale != null) { |
| String text = String.format("%1$s - %2$s", |
| config.locale.toString(), |
| config.locale.getDisplayName()); |
| mCurrentLocaleTextView.setText(text); |
| |
| checkLocaleInList(config.locale.toString()); |
| } |
| } catch (RemoteException e) { |
| if (DEBUG) { |
| Log.e(TAG, "get current locale failed", e); |
| } |
| } |
| } |
| |
| /** Find the locale by code to select it in the list view */ |
| private void checkLocaleInList(String locale) { |
| ListAdapter a = mListView.getAdapter(); |
| for (int i = 0; i < a.getCount(); i++) { |
| Object o = a.getItem(i); |
| if (o instanceof LocaleInfo) { |
| String code = ((LocaleInfo) o).getLocale(); |
| if (code != null && code.equals(locale)) { |
| mListView.setSelection(i); |
| mListView.clearChoices(); |
| mListView.setItemChecked(i, true); |
| updateLocaleButtons(); |
| break; |
| } |
| } |
| } |
| } |
| |
| private LocaleInfo getCheckedLocale() { |
| int pos = mListView.getCheckedItemPosition(); |
| ListAdapter a = mListView.getAdapter(); |
| int n = a.getCount(); |
| if (pos >= 0 && pos < n) { |
| Object o = a.getItem(pos); |
| if (o instanceof LocaleInfo) { |
| return (LocaleInfo) o; |
| } |
| } |
| |
| return null; |
| } |
| |
| /** Update the Select/Remove buttons based on the currently checked locale. */ |
| private void updateLocaleButtons() { |
| LocaleInfo info = getCheckedLocale(); |
| if (info != null) { |
| // Enable it |
| mSelectLocaleButton.setEnabled(true); |
| mSelectLocaleButton.setText( |
| getString(R.string.select_locale_1s_button, info.getLocale())); |
| |
| // Enable the remove button only for custom locales and set the tag to the locale |
| mRemoveLocaleButton.setEnabled(info.isCustom()); |
| } else { |
| // If nothing is selected, disable the buttons |
| mSelectLocaleButton.setEnabled(false); |
| mSelectLocaleButton.setText(R.string.select_locale_button); |
| |
| mRemoveLocaleButton.setEnabled(false); |
| } |
| } |
| |
| /** Invoked by the button "Add new..." */ |
| private void onAddNewLocale() { |
| Intent i = new Intent(CustomLocaleActivity.this, NewLocaleDialog.class); |
| startActivityForResult(i, UPDATE_LIST); |
| } |
| |
| /** Invoked by the button Select / mSelectLocaleButton */ |
| private void onSelectLocale() { |
| LocaleInfo info = getCheckedLocale(); |
| if (info != null) { |
| changeSystemLocale(info.getLocale()); |
| } |
| } |
| |
| /** |
| * Invoked by the button Remove / mRemoveLocaleButton. |
| * Creates a dialog to ask for confirmation before actually remove the custom locale. |
| */ |
| private Dialog createRemoveLocaleDialog() { |
| |
| LocaleInfo info = getCheckedLocale(); |
| final String localeToRemove = info == null ? "<error>" : info.getLocale(); |
| |
| AlertDialog.Builder b = new AlertDialog.Builder(this); |
| b.setMessage(getString(R.string.confirm_remove_locale_1s, localeToRemove)); |
| b.setCancelable(false); |
| b.setPositiveButton(R.string.confirm_remove_locale_yes, |
| new DialogInterface.OnClickListener() { |
| @Override |
| public void onClick(DialogInterface dialog, int which) { |
| removeCustomLocale(localeToRemove); |
| dismissDialog(DLG_REMOVE_ID); |
| } |
| }); |
| b.setNegativeButton(R.string.confirm_remove_locale_no, |
| new DialogInterface.OnClickListener() { |
| @Override |
| public void onClick(DialogInterface dialog, int which) { |
| dismissDialog(DLG_REMOVE_ID); |
| } |
| }); |
| |
| return b.create(); |
| } |
| |
| private void removeCustomLocale(String localeToRemove) { |
| // Get current custom locale list |
| String oldLocales = mPrefs.getString(CUSTOM_LOCALES, ""); |
| |
| if (DEBUG) { |
| Log.d(TAG, "Remove " + localeToRemove + " from custom locales: " + oldLocales); |
| } |
| |
| // Update |
| StringBuilder sb = new StringBuilder(); |
| for (String locale : oldLocales.split(CUSTOM_LOCALES_SEP)) { |
| if (locale != null && locale.length() > 0 && !locale.equals(localeToRemove)) { |
| if (sb.length() > 0) { |
| sb.append(CUSTOM_LOCALES_SEP); |
| } |
| sb.append(locale); |
| } |
| } |
| |
| String newLocales = sb.toString(); |
| if (!newLocales.equals(oldLocales)) { |
| // Save prefs |
| boolean ok = mPrefs.edit().putString(CUSTOM_LOCALES, newLocales).commit(); |
| if (DEBUG) { |
| Log.d(TAG, "Prefs commit:" + Boolean.toString(ok) + ". Saved: " + newLocales); |
| } |
| |
| Toast.makeText(this, |
| getString(R.string.removed_custom_locale_1s, localeToRemove), |
| Toast.LENGTH_SHORT) |
| .show(); |
| |
| // Update list view |
| setupLocaleList(); |
| } |
| } |
| |
| /** |
| * Immutable structure that holds the information displayed by a list view item. |
| */ |
| private static class LocaleInfo { |
| private final String mLocale; |
| private final String mDisplayName; |
| private final boolean mIsCustom; |
| |
| public LocaleInfo(String locale, String displayName, boolean isCustom) { |
| mLocale = locale; |
| mDisplayName = displayName; |
| mIsCustom = isCustom; |
| } |
| |
| public LocaleInfo(String locale, String displayName) { |
| this(locale, displayName, false /*custom*/); |
| } |
| |
| public String getLocale() { |
| return mLocale; |
| } |
| |
| public boolean isCustom() { |
| return mIsCustom; |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| sb.append(mLocale) |
| .append(" - ") |
| .append(mDisplayName); |
| if (mIsCustom) { |
| sb.append(" [Custom]"); |
| } |
| return sb.toString(); |
| } |
| } |
| } |