139b467482d1bf256a111c757e9b7621c6f523271Jason Monk/* 239b467482d1bf256a111c757e9b7621c6f523271Jason Monk * Copyright (C) 2013 The Android Open Source Project 339b467482d1bf256a111c757e9b7621c6f523271Jason Monk * 439b467482d1bf256a111c757e9b7621c6f523271Jason Monk * Licensed under the Apache License, Version 2.0 (the "License"); 539b467482d1bf256a111c757e9b7621c6f523271Jason Monk * you may not use this file except in compliance with the License. 639b467482d1bf256a111c757e9b7621c6f523271Jason Monk * You may obtain a copy of the License at 739b467482d1bf256a111c757e9b7621c6f523271Jason Monk * 839b467482d1bf256a111c757e9b7621c6f523271Jason Monk * http://www.apache.org/licenses/LICENSE-2.0 939b467482d1bf256a111c757e9b7621c6f523271Jason Monk * 1039b467482d1bf256a111c757e9b7621c6f523271Jason Monk * Unless required by applicable law or agreed to in writing, software 1139b467482d1bf256a111c757e9b7621c6f523271Jason Monk * distributed under the License is distributed on an "AS IS" BASIS, 1239b467482d1bf256a111c757e9b7621c6f523271Jason Monk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1339b467482d1bf256a111c757e9b7621c6f523271Jason Monk * See the License for the specific language governing permissions and 1439b467482d1bf256a111c757e9b7621c6f523271Jason Monk * limitations under the License. 1539b467482d1bf256a111c757e9b7621c6f523271Jason Monk */ 1639b467482d1bf256a111c757e9b7621c6f523271Jason Monk 1739b467482d1bf256a111c757e9b7621c6f523271Jason Monkpackage com.android.settings; 1839b467482d1bf256a111c757e9b7621c6f523271Jason Monk 1939b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.app.AlertDialog; 20d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roosimport android.app.Dialog; 214a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkeyimport android.app.Fragment; 224a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkeyimport android.app.FragmentTransaction; 2339b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.content.Context; 2439b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.content.DialogInterface; 254a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkeyimport android.content.DialogInterface.OnClickListener; 264a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkeyimport android.content.Intent; 2739b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.os.Bundle; 2839b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v14.preference.ListPreferenceDialogFragment; 2939b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.support.v7.preference.ListPreference; 3039b467482d1bf256a111c757e9b7621c6f523271Jason Monkimport android.util.AttributeSet; 3139b467482d1bf256a111c757e9b7621c6f523271Jason Monk 32265d3c2a0c36251bf8a9f571d7239b6dd404d942Tamas Berghammerimport com.android.internal.logging.nano.MetricsProto; 33ac5e5932233eb4b485bd76087987182009be2c2fFan Zhangimport com.android.settings.core.instrumentation.InstrumentedDialogFragment; 34ac5e5932233eb4b485bd76087987182009be2c2fFan Zhang 352e1e0b7ef69b7a93cc170168aea211e739b3412eJulia Reynoldspublic class CustomListPreference extends ListPreference { 3639b467482d1bf256a111c757e9b7621c6f523271Jason Monk 3739b467482d1bf256a111c757e9b7621c6f523271Jason Monk public CustomListPreference(Context context, AttributeSet attrs) { 3839b467482d1bf256a111c757e9b7621c6f523271Jason Monk super(context, attrs); 3939b467482d1bf256a111c757e9b7621c6f523271Jason Monk } 4039b467482d1bf256a111c757e9b7621c6f523271Jason Monk 4139b467482d1bf256a111c757e9b7621c6f523271Jason Monk public CustomListPreference(Context context, AttributeSet attrs, int defStyleAttr, 4239b467482d1bf256a111c757e9b7621c6f523271Jason Monk int defStyleRes) { 4339b467482d1bf256a111c757e9b7621c6f523271Jason Monk super(context, attrs, defStyleAttr, defStyleRes); 4439b467482d1bf256a111c757e9b7621c6f523271Jason Monk } 4539b467482d1bf256a111c757e9b7621c6f523271Jason Monk 4639b467482d1bf256a111c757e9b7621c6f523271Jason Monk protected void onPrepareDialogBuilder(AlertDialog.Builder builder, 4739b467482d1bf256a111c757e9b7621c6f523271Jason Monk DialogInterface.OnClickListener listener) { 4839b467482d1bf256a111c757e9b7621c6f523271Jason Monk } 4939b467482d1bf256a111c757e9b7621c6f523271Jason Monk 5039b467482d1bf256a111c757e9b7621c6f523271Jason Monk protected void onDialogClosed(boolean positiveResult) { 5139b467482d1bf256a111c757e9b7621c6f523271Jason Monk } 5239b467482d1bf256a111c757e9b7621c6f523271Jason Monk 53d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos protected void onDialogCreated(Dialog dialog) { 54d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos } 55d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos 56d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos protected boolean isAutoClosePreference() { 57d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos return true; 58d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos } 59d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos 604a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey /** 614a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * Called when a user is about to choose the given value, to determine if we 624a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * should show a confirmation dialog. 634a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * 644a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * @param value the value the user is about to choose 654a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * @return the message to show in a confirmation dialog, or {@code null} to 664a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * not request confirmation 674a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey */ 684a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey protected CharSequence getConfirmationMessage(String value) { 694a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey return null; 704a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 714a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey 724bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos protected void onDialogStateRestored(Dialog dialog, Bundle savedInstanceState) { 734bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos } 744bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos 7539b467482d1bf256a111c757e9b7621c6f523271Jason Monk public static class CustomListPreferenceDialogFragment extends ListPreferenceDialogFragment { 7639b467482d1bf256a111c757e9b7621c6f523271Jason Monk 774bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos private static final java.lang.String KEY_CLICKED_ENTRY_INDEX 784bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos = "settings.CustomListPrefDialog.KEY_CLICKED_ENTRY_INDEX"; 794bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos 809cbf3255895cfd4c6be8b6cca61207740331cd97Jason Monk private int mClickedDialogEntryIndex; 819cbf3255895cfd4c6be8b6cca61207740331cd97Jason Monk 8239b467482d1bf256a111c757e9b7621c6f523271Jason Monk public static ListPreferenceDialogFragment newInstance(String key) { 8339b467482d1bf256a111c757e9b7621c6f523271Jason Monk final ListPreferenceDialogFragment fragment = new CustomListPreferenceDialogFragment(); 8439b467482d1bf256a111c757e9b7621c6f523271Jason Monk final Bundle b = new Bundle(1); 8539b467482d1bf256a111c757e9b7621c6f523271Jason Monk b.putString(ARG_KEY, key); 8639b467482d1bf256a111c757e9b7621c6f523271Jason Monk fragment.setArguments(b); 8739b467482d1bf256a111c757e9b7621c6f523271Jason Monk return fragment; 8839b467482d1bf256a111c757e9b7621c6f523271Jason Monk } 8939b467482d1bf256a111c757e9b7621c6f523271Jason Monk 9039b467482d1bf256a111c757e9b7621c6f523271Jason Monk private CustomListPreference getCustomizablePreference() { 9139b467482d1bf256a111c757e9b7621c6f523271Jason Monk return (CustomListPreference) getPreference(); 9239b467482d1bf256a111c757e9b7621c6f523271Jason Monk } 9339b467482d1bf256a111c757e9b7621c6f523271Jason Monk 9439b467482d1bf256a111c757e9b7621c6f523271Jason Monk @Override 9539b467482d1bf256a111c757e9b7621c6f523271Jason Monk protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { 9639b467482d1bf256a111c757e9b7621c6f523271Jason Monk super.onPrepareDialogBuilder(builder); 979cbf3255895cfd4c6be8b6cca61207740331cd97Jason Monk mClickedDialogEntryIndex = getCustomizablePreference() 989cbf3255895cfd4c6be8b6cca61207740331cd97Jason Monk .findIndexOfValue(getCustomizablePreference().getValue()); 99550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka getCustomizablePreference().onPrepareDialogBuilder(builder, getOnItemClickListener()); 100d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos if (!getCustomizablePreference().isAutoClosePreference()) { 101d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos builder.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() { 102d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos @Override 103d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos public void onClick(DialogInterface dialog, int which) { 1044a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey onItemChosen(); 105d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos } 106d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos }); 107d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos } 108d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos } 109d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos 110d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos @Override 111d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos public Dialog onCreateDialog(Bundle savedInstanceState) { 112d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos Dialog dialog = super.onCreateDialog(savedInstanceState); 1134bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos if (savedInstanceState != null) { 1144bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos mClickedDialogEntryIndex = savedInstanceState.getInt(KEY_CLICKED_ENTRY_INDEX, 1154bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos mClickedDialogEntryIndex); 1164bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos } 117d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos getCustomizablePreference().onDialogCreated(dialog); 118d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos return dialog; 119550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka } 120550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka 1214bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos @Override 1224bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos public void onSaveInstanceState(Bundle outState) { 1234bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos super.onSaveInstanceState(outState); 1244bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos outState.putInt(KEY_CLICKED_ENTRY_INDEX, mClickedDialogEntryIndex); 1254bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos } 1264bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos 1274bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos @Override 1284bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos public void onActivityCreated(Bundle savedInstanceState) { 1294bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos super.onActivityCreated(savedInstanceState); 1304bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos getCustomizablePreference().onDialogStateRestored(getDialog(), savedInstanceState); 1314bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos } 1324bd42073d4b373db2951e86fbc8daa3afc8f40afAdrian Roos 133550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka protected DialogInterface.OnClickListener getOnItemClickListener() { 134550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka return new DialogInterface.OnClickListener() { 1354a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey @Override 136550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka public void onClick(DialogInterface dialog, int which) { 137550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka setClickedDialogEntryIndex(which); 138d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos if (getCustomizablePreference().isAutoClosePreference()) { 1394a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey onItemChosen(); 140d553f4f9a94a16bb19463fb42294212dbc21c09aAdrian Roos } 141550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka } 142550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka }; 143550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka } 144550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka 145550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka protected void setClickedDialogEntryIndex(int which) { 146550d068abd5a38e77507eab704ecdf1be70695cbSudheer Shanka mClickedDialogEntryIndex = which; 14739b467482d1bf256a111c757e9b7621c6f523271Jason Monk } 14839b467482d1bf256a111c757e9b7621c6f523271Jason Monk 1494a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey private String getValue() { 1504a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey final ListPreference preference = getCustomizablePreference(); 1514a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey if (mClickedDialogEntryIndex >= 0 && preference.getEntryValues() != null) { 1524a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey return preference.getEntryValues()[mClickedDialogEntryIndex].toString(); 1534a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } else { 1544a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey return null; 1554a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 1564a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 1574a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey 1584a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey /** 1594a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * Called when user has made a concrete item choice, but we might need 1604a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * to make a quick detour to confirm that choice with a second dialog. 1614a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey */ 1624a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey protected void onItemChosen() { 1634a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey final CharSequence message = getCustomizablePreference() 1644a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey .getConfirmationMessage(getValue()); 1654a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey if (message != null) { 1664a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey final Fragment f = new ConfirmDialogFragment(); 1674a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey final Bundle args = new Bundle(); 1684a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey args.putCharSequence(Intent.EXTRA_TEXT, message); 1694a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey f.setArguments(args); 1704a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey f.setTargetFragment(CustomListPreferenceDialogFragment.this, 0); 1714a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey final FragmentTransaction ft = getFragmentManager().beginTransaction(); 1724a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey ft.add(f, getTag() + "-Confirm"); 1734a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey ft.commitAllowingStateLoss(); 1744a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } else { 1754a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey onItemConfirmed(); 1764a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 1774a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 1784a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey 1794a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey /** 1804a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * Called when user has made a concrete item choice and we've fully 1814a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey * confirmed they want to move forward (if we took a detour above). 1824a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey */ 1834a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey protected void onItemConfirmed() { 1844a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey onClick(getDialog(), DialogInterface.BUTTON_POSITIVE); 1854a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey getDialog().dismiss(); 1864a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 1874a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey 18839b467482d1bf256a111c757e9b7621c6f523271Jason Monk @Override 18939b467482d1bf256a111c757e9b7621c6f523271Jason Monk public void onDialogClosed(boolean positiveResult) { 19039b467482d1bf256a111c757e9b7621c6f523271Jason Monk getCustomizablePreference().onDialogClosed(positiveResult); 1919cbf3255895cfd4c6be8b6cca61207740331cd97Jason Monk final ListPreference preference = getCustomizablePreference(); 1924a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey final String value = getValue(); 1934a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey if (positiveResult && value != null) { 1949cbf3255895cfd4c6be8b6cca61207740331cd97Jason Monk if (preference.callChangeListener(value)) { 1959cbf3255895cfd4c6be8b6cca61207740331cd97Jason Monk preference.setValue(value); 1969cbf3255895cfd4c6be8b6cca61207740331cd97Jason Monk } 1979cbf3255895cfd4c6be8b6cca61207740331cd97Jason Monk } 19839b467482d1bf256a111c757e9b7621c6f523271Jason Monk } 19939b467482d1bf256a111c757e9b7621c6f523271Jason Monk } 2004a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey 201ac5e5932233eb4b485bd76087987182009be2c2fFan Zhang public static class ConfirmDialogFragment extends InstrumentedDialogFragment { 2024a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey @Override 2034a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey public Dialog onCreateDialog(Bundle savedInstanceState) { 2044a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey return new AlertDialog.Builder(getActivity()) 2054a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey .setMessage(getArguments().getCharSequence(Intent.EXTRA_TEXT)) 2064a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey .setPositiveButton(android.R.string.ok, new OnClickListener() { 2074a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey @Override 2084a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey public void onClick(DialogInterface dialog, int which) { 2094a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey final Fragment f = getTargetFragment(); 2104a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey if (f != null) { 2114a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey ((CustomListPreferenceDialogFragment) f).onItemConfirmed(); 2124a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 2134a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 2144a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey }) 2154a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey .setNegativeButton(android.R.string.cancel, null) 2164a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey .create(); 2174a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 218ac5e5932233eb4b485bd76087987182009be2c2fFan Zhang 219ac5e5932233eb4b485bd76087987182009be2c2fFan Zhang @Override 220ac5e5932233eb4b485bd76087987182009be2c2fFan Zhang public int getMetricsCategory() { 221ac5e5932233eb4b485bd76087987182009be2c2fFan Zhang return MetricsProto.MetricsEvent.DIALOG_CUSTOM_LIST_CONFIRMATION; 222ac5e5932233eb4b485bd76087987182009be2c2fFan Zhang } 2234a8136b51b746961aac6f5ce2459effef8c22680Jeff Sharkey } 22439b467482d1bf256a111c757e9b7621c6f523271Jason Monk} 225