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