1 /* 2 * Copyright (C) 2013 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; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.app.Fragment; 22 import android.app.FragmentTransaction; 23 import android.content.Context; 24 import android.content.DialogInterface; 25 import android.content.DialogInterface.OnClickListener; 26 import android.content.Intent; 27 import android.os.Bundle; 28 import android.support.v14.preference.ListPreferenceDialogFragment; 29 import android.support.v7.preference.ListPreference; 30 import android.util.AttributeSet; 31 32 import com.android.internal.logging.nano.MetricsProto; 33 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 34 35 public class CustomListPreference extends ListPreference { 36 CustomListPreference(Context context, AttributeSet attrs)37 public CustomListPreference(Context context, AttributeSet attrs) { 38 super(context, attrs); 39 } 40 CustomListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)41 public CustomListPreference(Context context, AttributeSet attrs, int defStyleAttr, 42 int defStyleRes) { 43 super(context, attrs, defStyleAttr, defStyleRes); 44 } 45 onPrepareDialogBuilder(AlertDialog.Builder builder, DialogInterface.OnClickListener listener)46 protected void onPrepareDialogBuilder(AlertDialog.Builder builder, 47 DialogInterface.OnClickListener listener) { 48 } 49 onDialogClosed(boolean positiveResult)50 protected void onDialogClosed(boolean positiveResult) { 51 } 52 onDialogCreated(Dialog dialog)53 protected void onDialogCreated(Dialog dialog) { 54 } 55 isAutoClosePreference()56 protected boolean isAutoClosePreference() { 57 return true; 58 } 59 60 /** 61 * Called when a user is about to choose the given value, to determine if we 62 * should show a confirmation dialog. 63 * 64 * @param value the value the user is about to choose 65 * @return the message to show in a confirmation dialog, or {@code null} to 66 * not request confirmation 67 */ getConfirmationMessage(String value)68 protected CharSequence getConfirmationMessage(String value) { 69 return null; 70 } 71 onDialogStateRestored(Dialog dialog, Bundle savedInstanceState)72 protected void onDialogStateRestored(Dialog dialog, Bundle savedInstanceState) { 73 } 74 75 public static class CustomListPreferenceDialogFragment extends ListPreferenceDialogFragment { 76 77 private static final java.lang.String KEY_CLICKED_ENTRY_INDEX 78 = "settings.CustomListPrefDialog.KEY_CLICKED_ENTRY_INDEX"; 79 80 private int mClickedDialogEntryIndex; 81 newInstance(String key)82 public static ListPreferenceDialogFragment newInstance(String key) { 83 final ListPreferenceDialogFragment fragment = new CustomListPreferenceDialogFragment(); 84 final Bundle b = new Bundle(1); 85 b.putString(ARG_KEY, key); 86 fragment.setArguments(b); 87 return fragment; 88 } 89 getCustomizablePreference()90 private CustomListPreference getCustomizablePreference() { 91 return (CustomListPreference) getPreference(); 92 } 93 94 @Override onPrepareDialogBuilder(AlertDialog.Builder builder)95 protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { 96 super.onPrepareDialogBuilder(builder); 97 mClickedDialogEntryIndex = getCustomizablePreference() 98 .findIndexOfValue(getCustomizablePreference().getValue()); 99 getCustomizablePreference().onPrepareDialogBuilder(builder, getOnItemClickListener()); 100 if (!getCustomizablePreference().isAutoClosePreference()) { 101 builder.setPositiveButton(R.string.okay, new DialogInterface.OnClickListener() { 102 @Override 103 public void onClick(DialogInterface dialog, int which) { 104 onItemChosen(); 105 } 106 }); 107 } 108 } 109 110 @Override onCreateDialog(Bundle savedInstanceState)111 public Dialog onCreateDialog(Bundle savedInstanceState) { 112 Dialog dialog = super.onCreateDialog(savedInstanceState); 113 if (savedInstanceState != null) { 114 mClickedDialogEntryIndex = savedInstanceState.getInt(KEY_CLICKED_ENTRY_INDEX, 115 mClickedDialogEntryIndex); 116 } 117 getCustomizablePreference().onDialogCreated(dialog); 118 return dialog; 119 } 120 121 @Override onSaveInstanceState(Bundle outState)122 public void onSaveInstanceState(Bundle outState) { 123 super.onSaveInstanceState(outState); 124 outState.putInt(KEY_CLICKED_ENTRY_INDEX, mClickedDialogEntryIndex); 125 } 126 127 @Override onActivityCreated(Bundle savedInstanceState)128 public void onActivityCreated(Bundle savedInstanceState) { 129 super.onActivityCreated(savedInstanceState); 130 getCustomizablePreference().onDialogStateRestored(getDialog(), savedInstanceState); 131 } 132 getOnItemClickListener()133 protected DialogInterface.OnClickListener getOnItemClickListener() { 134 return new DialogInterface.OnClickListener() { 135 @Override 136 public void onClick(DialogInterface dialog, int which) { 137 setClickedDialogEntryIndex(which); 138 if (getCustomizablePreference().isAutoClosePreference()) { 139 onItemChosen(); 140 } 141 } 142 }; 143 } 144 setClickedDialogEntryIndex(int which)145 protected void setClickedDialogEntryIndex(int which) { 146 mClickedDialogEntryIndex = which; 147 } 148 getValue()149 private String getValue() { 150 final ListPreference preference = getCustomizablePreference(); 151 if (mClickedDialogEntryIndex >= 0 && preference.getEntryValues() != null) { 152 return preference.getEntryValues()[mClickedDialogEntryIndex].toString(); 153 } else { 154 return null; 155 } 156 } 157 158 /** 159 * Called when user has made a concrete item choice, but we might need 160 * to make a quick detour to confirm that choice with a second dialog. 161 */ onItemChosen()162 protected void onItemChosen() { 163 final CharSequence message = getCustomizablePreference() 164 .getConfirmationMessage(getValue()); 165 if (message != null) { 166 final Fragment f = new ConfirmDialogFragment(); 167 final Bundle args = new Bundle(); 168 args.putCharSequence(Intent.EXTRA_TEXT, message); 169 f.setArguments(args); 170 f.setTargetFragment(CustomListPreferenceDialogFragment.this, 0); 171 final FragmentTransaction ft = getFragmentManager().beginTransaction(); 172 ft.add(f, getTag() + "-Confirm"); 173 ft.commitAllowingStateLoss(); 174 } else { 175 onItemConfirmed(); 176 } 177 } 178 179 /** 180 * Called when user has made a concrete item choice and we've fully 181 * confirmed they want to move forward (if we took a detour above). 182 */ onItemConfirmed()183 protected void onItemConfirmed() { 184 onClick(getDialog(), DialogInterface.BUTTON_POSITIVE); 185 getDialog().dismiss(); 186 } 187 188 @Override onDialogClosed(boolean positiveResult)189 public void onDialogClosed(boolean positiveResult) { 190 getCustomizablePreference().onDialogClosed(positiveResult); 191 final ListPreference preference = getCustomizablePreference(); 192 final String value = getValue(); 193 if (positiveResult && value != null) { 194 if (preference.callChangeListener(value)) { 195 preference.setValue(value); 196 } 197 } 198 } 199 } 200 201 public static class ConfirmDialogFragment extends InstrumentedDialogFragment { 202 @Override 203 public Dialog onCreateDialog(Bundle savedInstanceState) { 204 return new AlertDialog.Builder(getActivity()) 205 .setMessage(getArguments().getCharSequence(Intent.EXTRA_TEXT)) 206 .setPositiveButton(android.R.string.ok, new OnClickListener() { 207 @Override 208 public void onClick(DialogInterface dialog, int which) { 209 final Fragment f = getTargetFragment(); 210 if (f != null) { 211 ((CustomListPreferenceDialogFragment) f).onItemConfirmed(); 212 } 213 } 214 }) 215 .setNegativeButton(android.R.string.cancel, null) 216 .create(); 217 } 218 219 @Override 220 public int getMetricsCategory() { 221 return MetricsProto.MetricsEvent.DIALOG_CUSTOM_LIST_CONFIRMATION; 222 } 223 } 224 } 225