1 /* 2 * Copyright 2018 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 package com.android.settings.widget; 17 18 import android.app.AlertDialog; 19 import android.content.res.TypedArray; 20 import android.os.Bundle; 21 import android.support.annotation.VisibleForTesting; 22 import android.support.v14.preference.PreferenceDialogFragment; 23 import android.support.v7.preference.ListPreference; 24 import android.widget.ArrayAdapter; 25 import com.android.settingslib.core.instrumentation.Instrumentable; 26 27 import java.util.ArrayList; 28 29 /** 30 * {@link PreferenceDialogFragment} that updates the available options 31 * when {@code onListPreferenceUpdated} is called." 32 */ 33 public class UpdatableListPreferenceDialogFragment extends PreferenceDialogFragment implements 34 Instrumentable { 35 36 private static final String SAVE_STATE_INDEX = "UpdatableListPreferenceDialogFragment.index"; 37 private static final String SAVE_STATE_ENTRIES = 38 "UpdatableListPreferenceDialogFragment.entries"; 39 private static final String SAVE_STATE_ENTRY_VALUES = 40 "UpdatableListPreferenceDialogFragment.entryValues"; 41 private static final String METRICS_CATEGORY_KEY = "metrics_category_key"; 42 private ArrayAdapter mAdapter; 43 private int mClickedDialogEntryIndex; 44 private ArrayList<CharSequence> mEntries; 45 private CharSequence[] mEntryValues; 46 private int mMetricsCategory = Instrumentable.METRICS_CATEGORY_UNKNOWN; 47 48 public static UpdatableListPreferenceDialogFragment newInstance( 49 String key, int metricsCategory) { 50 UpdatableListPreferenceDialogFragment fragment = 51 new UpdatableListPreferenceDialogFragment(); 52 Bundle args = new Bundle(1); 53 args.putString(ARG_KEY, key); 54 args.putInt(METRICS_CATEGORY_KEY, metricsCategory); 55 fragment.setArguments(args); 56 return fragment; 57 } 58 59 public void onCreate(Bundle savedInstanceState) { 60 super.onCreate(savedInstanceState); 61 final Bundle bundle = getArguments(); 62 mMetricsCategory = 63 bundle.getInt(METRICS_CATEGORY_KEY, Instrumentable.METRICS_CATEGORY_UNKNOWN); 64 if (savedInstanceState == null) { 65 mEntries = new ArrayList<>(); 66 setPreferenceData(getListPreference()); 67 } else { 68 mClickedDialogEntryIndex = savedInstanceState.getInt(SAVE_STATE_INDEX, 0); 69 mEntries = savedInstanceState.getCharSequenceArrayList(SAVE_STATE_ENTRIES); 70 mEntryValues = 71 savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES); 72 } 73 } 74 75 @Override 76 public void onSaveInstanceState(Bundle outState) { 77 super.onSaveInstanceState(outState); 78 outState.putInt(SAVE_STATE_INDEX, mClickedDialogEntryIndex); 79 outState.putCharSequenceArrayList(SAVE_STATE_ENTRIES, mEntries); 80 outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues); 81 } 82 83 @Override 84 public void onDialogClosed(boolean positiveResult) { 85 final ListPreference preference = getListPreference(); 86 if (positiveResult && mClickedDialogEntryIndex >= 0) { 87 final String value = mEntryValues[mClickedDialogEntryIndex].toString(); 88 if (preference.callChangeListener(value)) { 89 preference.setValue(value); 90 } 91 } 92 } 93 94 @VisibleForTesting 95 void setAdapter(ArrayAdapter adapter) { 96 mAdapter = adapter; 97 } 98 99 @VisibleForTesting 100 void setEntries(ArrayList<CharSequence> entries) { 101 mEntries = entries; 102 } 103 104 @VisibleForTesting 105 ArrayAdapter getAdapter() { 106 return mAdapter; 107 } 108 109 @VisibleForTesting 110 void setMetricsCategory(Bundle bundle) { 111 mMetricsCategory = 112 bundle.getInt(METRICS_CATEGORY_KEY, Instrumentable.METRICS_CATEGORY_UNKNOWN); 113 } 114 115 @Override 116 protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { 117 super.onPrepareDialogBuilder(builder); 118 final TypedArray a = getContext().obtainStyledAttributes( 119 null, 120 com.android.internal.R.styleable.AlertDialog, 121 com.android.internal.R.attr.alertDialogStyle, 0); 122 123 mAdapter = new ArrayAdapter<>( 124 getContext(), 125 a.getResourceId( 126 com.android.internal.R.styleable.AlertDialog_singleChoiceItemLayout, 127 com.android.internal.R.layout.select_dialog_singlechoice), 128 mEntries); 129 130 builder.setSingleChoiceItems(mAdapter, mClickedDialogEntryIndex, 131 (dialog, which) -> { 132 mClickedDialogEntryIndex = which; 133 onClick(dialog, -1); 134 dialog.dismiss(); 135 }); 136 builder.setPositiveButton(null, null); 137 a.recycle(); 138 } 139 140 @Override 141 public int getMetricsCategory() { 142 return mMetricsCategory; 143 } 144 145 private ListPreference getListPreference() { 146 return (ListPreference) getPreference(); 147 } 148 149 private void setPreferenceData(ListPreference preference) { 150 mEntries.clear(); 151 mClickedDialogEntryIndex = preference.findIndexOfValue(preference.getValue()); 152 for (CharSequence entry : preference.getEntries()) { 153 mEntries.add(entry); 154 } 155 mEntryValues = preference.getEntryValues(); 156 } 157 158 public void onListPreferenceUpdated(ListPreference preference) { 159 if (mAdapter != null) { 160 setPreferenceData(preference); 161 mAdapter.notifyDataSetChanged(); 162 } 163 } 164 } 165