Home | History | Annotate | Download | only in customlocale2
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy 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,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.customlocale2;
     18 
     19 
     20 import java.util.ArrayList;
     21 import java.util.Collections;
     22 import java.util.Comparator;
     23 import java.util.Locale;
     24 
     25 import android.app.ActivityManagerNative;
     26 import android.app.AlertDialog;
     27 import android.app.Dialog;
     28 import android.app.IActivityManager;
     29 import android.app.ListActivity;
     30 import android.content.DialogInterface;
     31 import android.content.Intent;
     32 import android.content.SharedPreferences;
     33 import android.content.res.Configuration;
     34 import android.os.Bundle;
     35 import android.os.RemoteException;
     36 import android.util.Log;
     37 import android.view.ContextMenu;
     38 import android.view.View;
     39 import android.view.ContextMenu.ContextMenuInfo;
     40 import android.widget.ArrayAdapter;
     41 import android.widget.Button;
     42 import android.widget.ListAdapter;
     43 import android.widget.ListView;
     44 import android.widget.TextView;
     45 import android.widget.Toast;
     46 import android.widget.AdapterView.AdapterContextMenuInfo;
     47 
     48 /**
     49  * Displays the list of system locales as well as maintain a custom list of user
     50  * locales. The user can select a locale and apply it or it can create or remove
     51  * a custom locale.
     52  */
     53 public class CustomLocaleActivity extends ListActivity {
     54 
     55     private static final String TAG = "CustomLocale";
     56     private static final boolean DEBUG = true;
     57 
     58     private static final int DLG_REMOVE_ID = 0;
     59 
     60     private static final String CUSTOM_LOCALES_SEP = " ";
     61     private static final String CUSTOM_LOCALES = "custom_locales";
     62 
     63     /** Request code returned when the NewLocaleDialog activity finishes. */
     64     private static final int UPDATE_LIST = 42;
     65     /** Menu item id for applying a locale */
     66     private static final int MENU_APPLY = 43;
     67     /** Menu item id for removing a custom locale */
     68     private static final int MENU_REMOVE = 44;
     69 
     70     /** List view displaying system and custom locales. */
     71     private ListView mListView;
     72     /** Textview used to display current locale */
     73     private TextView mCurrentLocaleTextView;
     74     /** Private shared preferences of this activity. */
     75     private SharedPreferences mPrefs;
     76 
     77     private Button mRemoveLocaleButton;
     78     private Button mSelectLocaleButton;
     79 
     80     @Override
     81     protected void onCreate(Bundle savedInstanceState) {
     82         super.onCreate(savedInstanceState);
     83         setContentView(R.layout.main);
     84 
     85         mPrefs = getPreferences(MODE_PRIVATE);
     86 
     87         Button addLocaleButton = (Button) findViewById(R.id.add_new_locale_button);
     88         mRemoveLocaleButton = (Button) findViewById(R.id.remove_locale_button);
     89         mSelectLocaleButton = (Button) findViewById(R.id.select_locale_button);
     90 
     91         addLocaleButton.setOnClickListener(new View.OnClickListener() {
     92             public void onClick(View v) {
     93                 onAddNewLocale();
     94             }
     95         });
     96 
     97         mRemoveLocaleButton.setOnClickListener(new View.OnClickListener() {
     98             @Override
     99             public void onClick(View v) {
    100                 showDialog(DLG_REMOVE_ID);
    101             }
    102         });
    103 
    104         mSelectLocaleButton.setOnClickListener(new View.OnClickListener() {
    105             @Override
    106             public void onClick(View v) {
    107                 onSelectLocale();
    108             }
    109         });
    110 
    111         mListView = (ListView) findViewById(android.R.id.list);
    112         mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
    113         mListView.setItemsCanFocus(false);
    114         mListView.setFocusable(true);
    115         mListView.setFocusableInTouchMode(true);
    116         mListView.requestFocus();
    117         setupLocaleList();
    118 
    119         mCurrentLocaleTextView = (TextView) findViewById(R.id.current_locale);
    120         displayCurrentLocale();
    121     }
    122 
    123     @Override
    124     protected void onResume() {
    125         super.onResume();
    126         updateLocaleButtons();
    127     }
    128 
    129     @Override
    130     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    131         super.onActivityResult(requestCode, resultCode, data);
    132 
    133         if (requestCode == UPDATE_LIST && resultCode == RESULT_OK && data != null) {
    134             String locale = data.getExtras().getString(NewLocaleDialog.INTENT_EXTRA_LOCALE);
    135             if (locale != null && locale.length() > 0) {
    136                 // Get current custom locale list
    137                 String customLocales = mPrefs.getString(CUSTOM_LOCALES, null);
    138 
    139                 // Update
    140                 if (customLocales == null) {
    141                     customLocales = locale;
    142                 } else {
    143                     customLocales += CUSTOM_LOCALES_SEP + locale;
    144                 }
    145 
    146                 // Save prefs
    147                 if (DEBUG) {
    148                     Log.d(TAG, "add/customLocales: " + customLocales);
    149                 }
    150                 mPrefs.edit().putString(CUSTOM_LOCALES, customLocales).commit();
    151 
    152                 Toast.makeText(this,
    153                                getString(R.string.added_custom_locale_1s, locale),
    154                                Toast.LENGTH_SHORT)
    155                      .show();
    156 
    157                 // Update list view
    158                 setupLocaleList();
    159 
    160                 // Find the item to select it in the list view
    161                 checkLocaleInList(locale);
    162 
    163                 if (data.getExtras().getBoolean(NewLocaleDialog.INTENT_EXTRA_SELECT)) {
    164                     changeSystemLocale(locale);
    165                 }
    166             }
    167         }
    168     }
    169 
    170     @Override
    171     protected void onListItemClick(ListView l, View v, int position, long id) {
    172         super.onListItemClick(l, v, position, id);
    173         updateLocaleButtons();
    174     }
    175 
    176     @Override
    177     public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
    178         super.onCreateContextMenu(menu, v, menuInfo);
    179 
    180         if (menuInfo instanceof AdapterContextMenuInfo) {
    181             int position = ((AdapterContextMenuInfo) menuInfo).position;
    182             Object o = mListView.getItemAtPosition(position);
    183             if (o instanceof LocaleInfo) {
    184                 if (((LocaleInfo) o).isCustom()) {
    185                     menu.setHeaderTitle("System Locale");
    186                     menu.add(0, MENU_APPLY, 0, "Apply");
    187                 } else {
    188                     menu.setHeaderTitle("Custom Locale");
    189                     menu.add(0, MENU_APPLY, 0, "Apply");
    190                     menu.add(0, MENU_REMOVE, 0, "Remove");
    191                 }
    192             }
    193         }
    194     }
    195 
    196     @Override
    197     protected Dialog onCreateDialog(int id) {
    198         if (id == DLG_REMOVE_ID) {
    199             return createRemoveLocaleDialog();
    200         }
    201         return super.onCreateDialog(id);
    202     }
    203 
    204     //--- private parts ---
    205 
    206     private void setupLocaleList() {
    207         if (DEBUG) {
    208             Log.d(TAG, "Update locate list");
    209         }
    210 
    211         ArrayList<LocaleInfo> data = new ArrayList<LocaleInfo>();
    212 
    213         // Insert all system locales
    214         String[] locales = getAssets().getLocales();
    215         for (String locale : locales) {
    216             if (locale != null && locale.length() > 0) {
    217                 Locale loc = new Locale(locale);
    218                 data.add(new LocaleInfo(locale, loc.getDisplayName()));
    219             }
    220         }
    221         locales = null;
    222 
    223         // Insert all custom locales
    224         String customLocales = mPrefs.getString(CUSTOM_LOCALES, "");
    225         if (DEBUG) {
    226             Log.d(TAG, "customLocales: " + customLocales);
    227         }
    228         for (String locale : customLocales.split(CUSTOM_LOCALES_SEP)) {
    229             if (locale != null && locale.length() > 0) {
    230                 Locale loc = new Locale(locale);
    231                 data.add(new LocaleInfo(
    232                                 locale,
    233                                 loc.getDisplayName(),
    234                                 true /*custom*/));
    235             }
    236         }
    237 
    238         // Sort all locales by code
    239         Collections.sort(data, new Comparator<LocaleInfo>() {
    240             public int compare(LocaleInfo lhs, LocaleInfo rhs) {
    241                 return lhs.getLocale().compareTo(rhs.getLocale());
    242             }
    243         });
    244 
    245         // Update the list view adapter
    246         mListView.setAdapter(new ArrayAdapter<LocaleInfo>(
    247                         this,
    248                         android.R.layout.simple_list_item_single_choice,
    249                         data));
    250         updateLocaleButtons();
    251     }
    252 
    253     private void changeSystemLocale(String locale) {
    254         if (ChangeLocale.changeSystemLocale(locale)) {
    255             Toast.makeText(this,
    256                             getString(R.string.select_locale_1s, locale),
    257                             Toast.LENGTH_SHORT)
    258                  .show();
    259         }
    260     }
    261 
    262     private void displayCurrentLocale() {
    263         try {
    264             IActivityManager am = ActivityManagerNative.getDefault();
    265             Configuration config = am.getConfiguration();
    266 
    267             if (config.locale != null) {
    268                 String text = String.format("%1$s - %2$s",
    269                         config.locale.toString(),
    270                         config.locale.getDisplayName());
    271                 mCurrentLocaleTextView.setText(text);
    272 
    273                 checkLocaleInList(config.locale.toString());
    274             }
    275         } catch (RemoteException e) {
    276             if (DEBUG) {
    277                 Log.e(TAG, "get current locale failed", e);
    278             }
    279         }
    280     }
    281 
    282     /** Find the locale by code to select it in the list view */
    283     private void checkLocaleInList(String locale) {
    284         ListAdapter a = mListView.getAdapter();
    285         for (int i = 0; i < a.getCount(); i++) {
    286             Object o = a.getItem(i);
    287             if (o instanceof LocaleInfo) {
    288                 String code = ((LocaleInfo) o).getLocale();
    289                 if (code != null && code.equals(locale)) {
    290                     mListView.setSelection(i);
    291                     mListView.clearChoices();
    292                     mListView.setItemChecked(i, true);
    293                     updateLocaleButtons();
    294                     break;
    295                 }
    296             }
    297         }
    298     }
    299 
    300     private LocaleInfo getCheckedLocale() {
    301         int pos = mListView.getCheckedItemPosition();
    302         ListAdapter a = mListView.getAdapter();
    303         int n = a.getCount();
    304         if (pos >= 0 && pos < n) {
    305             Object o = a.getItem(pos);
    306             if (o instanceof LocaleInfo) {
    307                 return (LocaleInfo) o;
    308             }
    309         }
    310 
    311         return null;
    312     }
    313 
    314     /** Update the Select/Remove buttons based on the currently checked locale. */
    315     private void updateLocaleButtons() {
    316         LocaleInfo info = getCheckedLocale();
    317         if (info != null) {
    318             // Enable it
    319             mSelectLocaleButton.setEnabled(true);
    320             mSelectLocaleButton.setText(
    321                 getString(R.string.select_locale_1s_button, info.getLocale()));
    322 
    323             // Enable the remove button only for custom locales and set the tag to the locale
    324             mRemoveLocaleButton.setEnabled(info.isCustom());
    325         } else {
    326             // If nothing is selected, disable the buttons
    327             mSelectLocaleButton.setEnabled(false);
    328             mSelectLocaleButton.setText(R.string.select_locale_button);
    329 
    330             mRemoveLocaleButton.setEnabled(false);
    331         }
    332     }
    333 
    334     /** Invoked by the button "Add new..." */
    335     private void onAddNewLocale() {
    336         Intent i = new Intent(CustomLocaleActivity.this, NewLocaleDialog.class);
    337         startActivityForResult(i, UPDATE_LIST);
    338     }
    339 
    340     /** Invoked by the button Select / mSelectLocaleButton */
    341     private void onSelectLocale() {
    342         LocaleInfo info = getCheckedLocale();
    343         if (info != null) {
    344             changeSystemLocale(info.getLocale());
    345         }
    346     }
    347 
    348     /**
    349      * Invoked by the button Remove / mRemoveLocaleButton.
    350      * Creates a dialog to ask for confirmation before actually remove the custom locale.
    351      */
    352     private Dialog createRemoveLocaleDialog() {
    353 
    354         LocaleInfo info = getCheckedLocale();
    355         final String localeToRemove = info == null ? "<error>" : info.getLocale();
    356 
    357         AlertDialog.Builder b = new AlertDialog.Builder(this);
    358         b.setMessage(getString(R.string.confirm_remove_locale_1s, localeToRemove));
    359         b.setCancelable(false);
    360         b.setPositiveButton(R.string.confirm_remove_locale_yes,
    361             new DialogInterface.OnClickListener() {
    362                 @Override
    363                 public void onClick(DialogInterface dialog, int which) {
    364                     removeCustomLocale(localeToRemove);
    365                     dismissDialog(DLG_REMOVE_ID);
    366                 }
    367         });
    368         b.setNegativeButton(R.string.confirm_remove_locale_no,
    369             new DialogInterface.OnClickListener() {
    370                 @Override
    371                 public void onClick(DialogInterface dialog, int which) {
    372                     dismissDialog(DLG_REMOVE_ID);
    373                 }
    374         });
    375 
    376         return b.create();
    377     }
    378 
    379     private void removeCustomLocale(String localeToRemove) {
    380         // Get current custom locale list
    381         String oldLocales = mPrefs.getString(CUSTOM_LOCALES, "");
    382 
    383         if (DEBUG) {
    384             Log.d(TAG, "Remove " + localeToRemove + " from custom locales: " + oldLocales);
    385         }
    386 
    387         // Update
    388         StringBuilder sb = new StringBuilder();
    389         for (String locale : oldLocales.split(CUSTOM_LOCALES_SEP)) {
    390             if (locale != null && locale.length() > 0 && !locale.equals(localeToRemove)) {
    391                 if (sb.length() > 0) {
    392                     sb.append(CUSTOM_LOCALES_SEP);
    393                 }
    394                 sb.append(locale);
    395             }
    396         }
    397 
    398         String newLocales = sb.toString();
    399         if (!newLocales.equals(oldLocales)) {
    400             // Save prefs
    401             boolean ok = mPrefs.edit().putString(CUSTOM_LOCALES, newLocales).commit();
    402             if (DEBUG) {
    403                 Log.d(TAG, "Prefs commit:" + Boolean.toString(ok) + ". Saved: " + newLocales);
    404             }
    405 
    406             Toast.makeText(this,
    407                             getString(R.string.removed_custom_locale_1s, localeToRemove),
    408                             Toast.LENGTH_SHORT)
    409                  .show();
    410 
    411             // Update list view
    412             setupLocaleList();
    413         }
    414     }
    415 
    416     /**
    417      * Immutable structure that holds the information displayed by a list view item.
    418      */
    419     private static class LocaleInfo {
    420         private final String mLocale;
    421         private final String mDisplayName;
    422         private final boolean mIsCustom;
    423 
    424         public LocaleInfo(String locale, String displayName, boolean isCustom) {
    425             mLocale = locale;
    426             mDisplayName = displayName;
    427             mIsCustom = isCustom;
    428         }
    429 
    430         public LocaleInfo(String locale, String displayName) {
    431             this(locale, displayName, false /*custom*/);
    432         }
    433 
    434         public String getLocale() {
    435             return mLocale;
    436         }
    437 
    438         public boolean isCustom() {
    439             return mIsCustom;
    440         }
    441 
    442         @Override
    443         public String toString() {
    444             StringBuilder sb = new StringBuilder();
    445             sb.append(mLocale)
    446               .append(" - ")
    447               .append(mDisplayName);
    448             if (mIsCustom) {
    449                 sb.append(" [Custom]");
    450             }
    451             return sb.toString();
    452         }
    453     }
    454 }
    455