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