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