diff --git a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java index a78c60dd099..2ce4e72f3d7 100644 --- a/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java +++ b/src/com/android/settings/localepicker/LocaleDragAndDropAdapter.java @@ -18,6 +18,7 @@ package com.android.settings.localepicker; import android.content.Context; import android.graphics.Canvas; +import android.os.Bundle; import android.support.v4.view.MotionEventCompat; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; @@ -36,6 +37,7 @@ import com.android.internal.app.LocaleStore; import com.android.settings.R; import java.text.NumberFormat; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -45,6 +47,7 @@ class LocaleDragAndDropAdapter extends RecyclerView.Adapter { private static final String TAG = "LocaleDragAndDropAdapter"; + private static final String CFGKEY_SELECTED_LOCALES = "selectedLocales"; private final Context mContext; private final List mFeedItemList; private final ItemTouchHelper mItemTouchHelper; @@ -105,6 +108,7 @@ class LocaleDragAndDropAdapter private static final int SELECTION_LOST = 0; private static final int SELECTION_UNCHANGED = -1; private int mSelectionStatus = SELECTION_UNCHANGED; + @Override public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, @@ -148,7 +152,6 @@ class LocaleDragAndDropAdapter public void onBindViewHolder(final CustomViewHolder holder, int i) { final LocaleStore.LocaleInfo feedItem = mFeedItemList.get(i); final LocaleDragCell dragCell = holder.getLocaleDragCell(); - String label = feedItem.getFullNameNative(); dragCell.setLabel(label); dragCell.setLocalized(feedItem.isTranslated()); @@ -156,7 +159,7 @@ class LocaleDragAndDropAdapter dragCell.setShowCheckbox(mRemoveMode); dragCell.setShowMiniLabel(!mRemoveMode); dragCell.setShowHandle(!mRemoveMode && mDragEnabled); - dragCell.setChecked(false); + dragCell.setChecked(mRemoveMode ? feedItem.getChecked() : false); dragCell.setTag(feedItem); dragCell.getCheckbox() .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @@ -286,4 +289,40 @@ class LocaleDragAndDropAdapter private void setDragEnabled(boolean enabled) { mDragEnabled = enabled; } + + /** + * Saves the list of checked locales to preserve status when the list is destroyed. + * (for instance when the device is rotated) + * @param outInstanceState Bundle in which to place the saved state + */ + public void saveState(Bundle outInstanceState) { + if (outInstanceState != null) { + final ArrayList selectedLocales = new ArrayList<>(); + for (LocaleStore.LocaleInfo li : mFeedItemList) { + if (li.getChecked()) { + selectedLocales.add(li.getId()); + } + } + outInstanceState.putStringArrayList(CFGKEY_SELECTED_LOCALES, selectedLocales); + } + } + + /** + * Restores the list of checked locales to preserve status when the list is recreated. + * (for instance when the device is rotated) + * @param savedInstanceState Bundle with the data saved by {@link #saveState(Bundle)} + */ + public void restoreState(Bundle savedInstanceState) { + if (savedInstanceState != null && mRemoveMode) { + final ArrayList selectedLocales = + savedInstanceState.getStringArrayList(CFGKEY_SELECTED_LOCALES); + if (selectedLocales == null || selectedLocales.isEmpty()) { + return; + } + for (LocaleStore.LocaleInfo li : mFeedItemList) { + li.setChecked(selectedLocales.contains(li.getId())); + } + notifyItemRangeChanged(0, mFeedItemList.size()); + } + } } diff --git a/src/com/android/settings/localepicker/LocaleListEditor.java b/src/com/android/settings/localepicker/LocaleListEditor.java index 63649d75302..3287d393064 100644 --- a/src/com/android/settings/localepicker/LocaleListEditor.java +++ b/src/com/android/settings/localepicker/LocaleListEditor.java @@ -31,6 +31,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; + import com.android.internal.app.LocalePicker; import com.android.internal.app.LocalePickerWithRegion; import com.android.internal.app.LocaleStore; @@ -48,12 +49,15 @@ import java.util.Locale; public class LocaleListEditor extends SettingsPreferenceFragment implements LocalePickerWithRegion.LocaleSelectedListener { + private static final String CFGKEY_REMOVE_MODE = "localeRemoveMode"; + private static final String CFGKEY_REMOVE_DIALOG = "showingLocaleRemoveDialog"; private static final int MENU_ID_REMOVE = Menu.FIRST + 1; private LocaleDragAndDropAdapter mAdapter; private Menu mMenu; - private boolean mRemoveMode; private View mAddLanguage; + private boolean mRemoveMode; + private boolean mShowingRemoveDialog; @Override protected int getMetricsCategory() { @@ -82,15 +86,45 @@ public class LocaleListEditor extends SettingsPreferenceFragment return result; } + @Override + public void onViewStateRestored(Bundle savedInstanceState) { + super.onViewStateRestored(savedInstanceState); + if (savedInstanceState != null) { + mRemoveMode = savedInstanceState.getBoolean(CFGKEY_REMOVE_MODE, false); + mShowingRemoveDialog = savedInstanceState.getBoolean(CFGKEY_REMOVE_DIALOG, false); + } + setRemoveMode(mRemoveMode); + mAdapter.restoreState(savedInstanceState); + + if (mShowingRemoveDialog) { + showRemoveLocaleWarningDialog(); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(CFGKEY_REMOVE_MODE, mRemoveMode); + outState.putBoolean(CFGKEY_REMOVE_DIALOG, mShowingRemoveDialog); + mAdapter.saveState(outState); + } + @Override public boolean onOptionsItemSelected(MenuItem menuItem) { - if (menuItem.getItemId() == MENU_ID_REMOVE) { - if (mRemoveMode) { - removeLocaleWarningDialog(); - } else { - setRemoveMode(true); - } - return true; + switch (menuItem.getItemId()) { + case MENU_ID_REMOVE: + if (mRemoveMode) { + showRemoveLocaleWarningDialog(); + } else { + setRemoveMode(true); + } + return true; + case android.R.id.home: + if (mRemoveMode) { + setRemoveMode(false); + return true; + } + break; } return super.onOptionsItemSelected(menuItem); } @@ -98,12 +132,15 @@ public class LocaleListEditor extends SettingsPreferenceFragment private void setRemoveMode(boolean mRemoveMode) { this.mRemoveMode = mRemoveMode; mAdapter.setRemoveMode(mRemoveMode); - mMenu.findItem(MENU_ID_REMOVE).setShowAsAction( - mRemoveMode ? MenuItem.SHOW_AS_ACTION_ALWAYS : MenuItem.SHOW_AS_ACTION_NEVER); mAddLanguage.setVisibility(mRemoveMode ? View.INVISIBLE : View.VISIBLE); + updateVisibilityOfRemoveMenu(); } - private void removeLocaleWarningDialog() { + // Show the appropriate warning when the user tries to remove locales. + // Shows no warning if there is no locale checked, shows a warning + // about removing all the locales if all of them are checked, and + // a "regular" warning otherwise. + private void showRemoveLocaleWarningDialog() { int checkedCount = mAdapter.getCheckedCount(); // Nothing checked, just exit remove mode without a warning dialog @@ -114,6 +151,7 @@ public class LocaleListEditor extends SettingsPreferenceFragment // All locales selected, warning dialog, can't remove them all if (checkedCount == mAdapter.getItemCount()) { + mShowingRemoveDialog = true; new AlertDialog.Builder(getActivity()) .setTitle(R.string.dlg_remove_locales_error_title) .setMessage(R.string.dlg_remove_locales_error_message) @@ -122,6 +160,12 @@ public class LocaleListEditor extends SettingsPreferenceFragment public void onClick(DialogInterface dialog, int which) { } }) + .setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + mShowingRemoveDialog = false; + } + }) .create() .show(); return; @@ -129,21 +173,38 @@ public class LocaleListEditor extends SettingsPreferenceFragment final String title = getResources().getQuantityString(R.plurals.dlg_remove_locales_title, checkedCount); + mShowingRemoveDialog = true; new AlertDialog.Builder(getActivity()) .setTitle(title) .setMessage(R.string.dlg_remove_locales_message) .setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - setRemoveMode(!mRemoveMode); + setRemoveMode(false); } }) .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { + // This is a sensitive area to change. + // removeChecked() triggers a system update and "kills" the frame. + // This means that saveState + restoreState are called before + // setRemoveMode is called. + // So we want that mRemoveMode and dialog status have the right values + // before that save. + // We can't just call setRemoveMode(false) before calling removeCheched + // because that unchecks all items and removeChecked would have nothing + // to remove. + mRemoveMode = false; + mShowingRemoveDialog = false; mAdapter.removeChecked(); - setRemoveMode(!mRemoveMode); - updateVisibilityOfRemoveMenu(); + setRemoveMode(false); + } + }) + .setOnDismissListener(new DialogInterface.OnDismissListener() { + @Override + public void onDismiss(DialogInterface dialog) { + mShowingRemoveDialog = false; } }) .create() @@ -208,8 +269,14 @@ public class LocaleListEditor extends SettingsPreferenceFragment // Hide the "Remove" menu if there is only one locale in the list, show it otherwise // This is called when the menu is first created, and then one add / remove locale private void updateVisibilityOfRemoveMenu() { + if (mMenu == null) { + return; + } + final MenuItem menuItemRemove = mMenu.findItem(MENU_ID_REMOVE); if (menuItemRemove != null) { + menuItemRemove.setShowAsAction( + mRemoveMode ? MenuItem.SHOW_AS_ACTION_ALWAYS : MenuItem.SHOW_AS_ACTION_NEVER); menuItemRemove.setVisible(mAdapter.getItemCount() > 1); } }