Home | History | Annotate | Download | only in localepicker
      1 /*
      2  * Copyright (C) 2016 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.settings.localepicker;
     18 
     19 import android.app.AlertDialog;
     20 import android.app.FragmentTransaction;
     21 import android.content.Context;
     22 import android.content.DialogInterface;
     23 import android.os.Bundle;
     24 import android.os.LocaleList;
     25 import android.support.v7.widget.RecyclerView;
     26 import android.view.LayoutInflater;
     27 import android.view.Menu;
     28 import android.view.MenuInflater;
     29 import android.view.MenuItem;
     30 import android.view.View;
     31 import android.view.ViewGroup;
     32 
     33 import com.android.internal.app.LocalePicker;
     34 import com.android.internal.app.LocalePickerWithRegion;
     35 import com.android.internal.app.LocaleStore;
     36 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
     37 import com.android.settings.R;
     38 import com.android.settings.SettingsPreferenceFragment;
     39 
     40 import java.util.ArrayList;
     41 import java.util.List;
     42 import java.util.Locale;
     43 
     44 /**
     45  * Drag-and-drop editor for the user-ordered locale lists.
     46  */
     47 public class LocaleListEditor extends SettingsPreferenceFragment
     48         implements LocalePickerWithRegion.LocaleSelectedListener {
     49 
     50     private static final String CFGKEY_REMOVE_MODE = "localeRemoveMode";
     51     private static final String CFGKEY_REMOVE_DIALOG = "showingLocaleRemoveDialog";
     52     private static final int MENU_ID_REMOVE = Menu.FIRST + 1;
     53 
     54     private LocaleDragAndDropAdapter mAdapter;
     55     private Menu mMenu;
     56     private View mAddLanguage;
     57     private boolean mRemoveMode;
     58     private boolean mShowingRemoveDialog;
     59 
     60     @Override
     61     public int getMetricsCategory() {
     62         return MetricsEvent.USER_LOCALE_LIST;
     63     }
     64 
     65     @Override
     66     public void onCreate(Bundle savedInstanceState) {
     67         super.onCreate(savedInstanceState);
     68         setHasOptionsMenu(true);
     69 
     70         LocaleStore.fillCache(this.getContext());
     71         final List<LocaleStore.LocaleInfo> feedsList = getUserLocaleList(this.getContext());
     72         mAdapter = new LocaleDragAndDropAdapter(this.getContext(), feedsList);
     73     }
     74 
     75     @Override
     76     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstState) {
     77         final View result = super.onCreateView(inflater, container, savedInstState);
     78         final View myLayout = inflater.inflate(R.layout.locale_order_list, (ViewGroup) result);
     79 
     80         getActivity().setTitle(R.string.pref_title_lang_selection);
     81 
     82         configureDragAndDrop(myLayout);
     83         return result;
     84     }
     85 
     86     @Override
     87     public void onViewStateRestored(Bundle savedInstanceState) {
     88         super.onViewStateRestored(savedInstanceState);
     89         if (savedInstanceState != null) {
     90             mRemoveMode = savedInstanceState.getBoolean(CFGKEY_REMOVE_MODE, false);
     91             mShowingRemoveDialog = savedInstanceState.getBoolean(CFGKEY_REMOVE_DIALOG, false);
     92         }
     93         setRemoveMode(mRemoveMode);
     94         mAdapter.restoreState(savedInstanceState);
     95 
     96         if (mShowingRemoveDialog) {
     97             showRemoveLocaleWarningDialog();
     98         }
     99     }
    100 
    101     @Override
    102     public void onSaveInstanceState(Bundle outState) {
    103         super.onSaveInstanceState(outState);
    104         outState.putBoolean(CFGKEY_REMOVE_MODE, mRemoveMode);
    105         outState.putBoolean(CFGKEY_REMOVE_DIALOG, mShowingRemoveDialog);
    106         mAdapter.saveState(outState);
    107     }
    108 
    109     @Override
    110     public boolean onOptionsItemSelected(MenuItem menuItem) {
    111         switch (menuItem.getItemId()) {
    112             case MENU_ID_REMOVE:
    113                 if (mRemoveMode) {
    114                     showRemoveLocaleWarningDialog();
    115                 } else {
    116                     setRemoveMode(true);
    117                 }
    118                 return true;
    119             case android.R.id.home:
    120                 if (mRemoveMode) {
    121                     setRemoveMode(false);
    122                     return true;
    123                 }
    124                 break;
    125         }
    126         return super.onOptionsItemSelected(menuItem);
    127     }
    128 
    129     private void setRemoveMode(boolean mRemoveMode) {
    130         this.mRemoveMode = mRemoveMode;
    131         mAdapter.setRemoveMode(mRemoveMode);
    132         mAddLanguage.setVisibility(mRemoveMode ? View.INVISIBLE : View.VISIBLE);
    133         updateVisibilityOfRemoveMenu();
    134     }
    135 
    136     // Show the appropriate warning when the user tries to remove locales.
    137     // Shows no warning if there is no locale checked, shows a warning
    138     // about removing all the locales if all of them are checked, and
    139     // a "regular" warning otherwise.
    140     private void showRemoveLocaleWarningDialog() {
    141         int checkedCount = mAdapter.getCheckedCount();
    142 
    143         // Nothing checked, just exit remove mode without a warning dialog
    144         if (checkedCount == 0) {
    145             setRemoveMode(!mRemoveMode);
    146             return;
    147         }
    148 
    149         // All locales selected, warning dialog, can't remove them all
    150         if (checkedCount == mAdapter.getItemCount()) {
    151             mShowingRemoveDialog = true;
    152             new AlertDialog.Builder(getActivity())
    153                     .setTitle(R.string.dlg_remove_locales_error_title)
    154                     .setMessage(R.string.dlg_remove_locales_error_message)
    155                     .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
    156                         @Override
    157                         public void onClick(DialogInterface dialog, int which) {
    158                         }
    159                     })
    160                     .setOnDismissListener(new DialogInterface.OnDismissListener() {
    161                         @Override
    162                         public void onDismiss(DialogInterface dialog) {
    163                             mShowingRemoveDialog = false;
    164                         }
    165                     })
    166                     .create()
    167                     .show();
    168             return;
    169         }
    170 
    171         final String title = getResources().getQuantityString(R.plurals.dlg_remove_locales_title,
    172                 checkedCount);
    173         mShowingRemoveDialog = true;
    174         new AlertDialog.Builder(getActivity())
    175                 .setTitle(title)
    176                 .setMessage(R.string.dlg_remove_locales_message)
    177                 .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
    178                     @Override
    179                     public void onClick(DialogInterface dialog, int which) {
    180                         setRemoveMode(false);
    181                     }
    182                 })
    183                 .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
    184                     @Override
    185                     public void onClick(DialogInterface dialog, int which) {
    186                         // This is a sensitive area to change.
    187                         // removeChecked() triggers a system update and "kills" the frame.
    188                         // This means that saveState + restoreState are called before
    189                         // setRemoveMode is called.
    190                         // So we want that mRemoveMode and dialog status have the right values
    191                         // before that save.
    192                         // We can't just call setRemoveMode(false) before calling removeCheched
    193                         // because that unchecks all items and removeChecked would have nothing
    194                         // to remove.
    195                         mRemoveMode = false;
    196                         mShowingRemoveDialog = false;
    197                         mAdapter.removeChecked();
    198                         setRemoveMode(false);
    199                     }
    200                 })
    201                 .setOnDismissListener(new DialogInterface.OnDismissListener() {
    202                     @Override
    203                     public void onDismiss(DialogInterface dialog) {
    204                         mShowingRemoveDialog = false;
    205                     }
    206                 })
    207                 .create()
    208                 .show();
    209     }
    210 
    211     @Override
    212     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    213         final MenuItem menuItem =
    214                 menu.add(Menu.NONE, MENU_ID_REMOVE, 0, R.string.locale_remove_menu);
    215         menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    216         menuItem.setIcon(R.drawable.ic_delete);
    217         super.onCreateOptionsMenu(menu, inflater);
    218         mMenu = menu;
    219         updateVisibilityOfRemoveMenu();
    220     }
    221 
    222     private static List<LocaleStore.LocaleInfo> getUserLocaleList(Context context) {
    223         final List<LocaleStore.LocaleInfo> result = new ArrayList<>();
    224 
    225         final LocaleList localeList = LocalePicker.getLocales();
    226         for (int i = 0; i < localeList.size(); i++) {
    227             Locale locale = localeList.get(i);
    228             result.add(LocaleStore.getLocaleInfo(locale));
    229         }
    230 
    231         return result;
    232     }
    233 
    234     private void configureDragAndDrop(View view) {
    235         final RecyclerView list = (RecyclerView) view.findViewById(R.id.dragList);
    236         final LocaleLinearLayoutManager llm = new LocaleLinearLayoutManager(getContext(), mAdapter);
    237         llm.setAutoMeasureEnabled(true);
    238         list.setLayoutManager(llm);
    239 
    240         list.setHasFixedSize(true);
    241         mAdapter.setRecyclerView(list);
    242         list.setAdapter(mAdapter);
    243 
    244         mAddLanguage = view.findViewById(R.id.add_language);
    245         mAddLanguage.setOnClickListener(new View.OnClickListener() {
    246             @Override
    247             public void onClick(View v) {
    248                 final LocalePickerWithRegion selector = LocalePickerWithRegion.createLanguagePicker(
    249                         getContext(), LocaleListEditor.this, false /* translate only */);
    250                 getFragmentManager()
    251                         .beginTransaction()
    252                         .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
    253                         .replace(getId(), selector)
    254                         .addToBackStack("localeListEditor")
    255                         .commit();
    256             }
    257         });
    258     }
    259 
    260     @Override
    261     public void onLocaleSelected(LocaleStore.LocaleInfo locale) {
    262         mAdapter.addLocale(locale);
    263         updateVisibilityOfRemoveMenu();
    264     }
    265 
    266     // Hide the "Remove" menu if there is only one locale in the list, show it otherwise
    267     // This is called when the menu is first created, and then one add / remove locale
    268     private void updateVisibilityOfRemoveMenu() {
    269         if (mMenu == null) {
    270             return;
    271         }
    272 
    273         final MenuItem menuItemRemove = mMenu.findItem(MENU_ID_REMOVE);
    274         if (menuItemRemove != null) {
    275             menuItemRemove.setShowAsAction(
    276                     mRemoveMode ? MenuItem.SHOW_AS_ACTION_ALWAYS : MenuItem.SHOW_AS_ACTION_NEVER);
    277             menuItemRemove.setVisible(mAdapter.getItemCount() > 1);
    278         }
    279     }
    280 }
    281