1 /* 2 * Copyright (C) 2012 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 android.preference; 18 19 import android.annotation.ArrayRes; 20 import android.app.AlertDialog.Builder; 21 import android.content.Context; 22 import android.content.DialogInterface; 23 import android.content.res.TypedArray; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.util.AttributeSet; 27 28 import java.util.Arrays; 29 30 /** 31 * @hide 32 * A {@link Preference} that displays a list of entries as 33 * a dialog which allow the user to toggle each individually on and off. 34 * 35 * @attr ref android.R.styleable#ListPreference_entries 36 * @attr ref android.R.styleable#ListPreference_entryValues 37 * 38 * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> 39 * <a href="{@docRoot}reference/androidx/preference/package-summary.html"> 40 * Preference Library</a> for consistent behavior across all devices. For more information on 41 * using the AndroidX Preference Library see 42 * <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>. 43 */ 44 @Deprecated 45 public class MultiCheckPreference extends DialogPreference { 46 private CharSequence[] mEntries; 47 private String[] mEntryValues; 48 private boolean[] mSetValues; 49 private boolean[] mOrigValues; 50 private String mSummary; 51 52 public MultiCheckPreference( 53 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 54 super(context, attrs, defStyleAttr, defStyleRes); 55 56 TypedArray a = context.obtainStyledAttributes( 57 attrs, com.android.internal.R.styleable.ListPreference, defStyleAttr, defStyleRes); 58 mEntries = a.getTextArray(com.android.internal.R.styleable.ListPreference_entries); 59 if (mEntries != null) { 60 setEntries(mEntries); 61 } 62 setEntryValuesCS(a.getTextArray( 63 com.android.internal.R.styleable.ListPreference_entryValues)); 64 a.recycle(); 65 66 /* Retrieve the Preference summary attribute since it's private 67 * in the Preference class. 68 */ 69 a = context.obtainStyledAttributes(attrs, 70 com.android.internal.R.styleable.Preference, 0, 0); 71 mSummary = a.getString(com.android.internal.R.styleable.Preference_summary); 72 a.recycle(); 73 } 74 75 public MultiCheckPreference(Context context, AttributeSet attrs, int defStyleAttr) { 76 this(context, attrs, defStyleAttr, 0); 77 } 78 79 public MultiCheckPreference(Context context, AttributeSet attrs) { 80 this(context, attrs, com.android.internal.R.attr.dialogPreferenceStyle); 81 } 82 83 public MultiCheckPreference(Context context) { 84 this(context, null); 85 } 86 87 /** 88 * Sets the human-readable entries to be shown in the list. This will be 89 * shown in subsequent dialogs. 90 * <p> 91 * Each entry must have a corresponding index in 92 * {@link #setEntryValues(CharSequence[])}. 93 * 94 * @param entries The entries. 95 * @see #setEntryValues(CharSequence[]) 96 */ 97 public void setEntries(CharSequence[] entries) { 98 mEntries = entries; 99 mSetValues = new boolean[entries.length]; 100 mOrigValues = new boolean[entries.length]; 101 } 102 103 /** 104 * @see #setEntries(CharSequence[]) 105 * @param entriesResId The entries array as a resource. 106 */ 107 public void setEntries(@ArrayRes int entriesResId) { 108 setEntries(getContext().getResources().getTextArray(entriesResId)); 109 } 110 111 /** 112 * The list of entries to be shown in the list in subsequent dialogs. 113 * 114 * @return The list as an array. 115 */ 116 public CharSequence[] getEntries() { 117 return mEntries; 118 } 119 120 /** 121 * The array to find the value to save for a preference when an entry from 122 * entries is selected. If a user clicks on the second item in entries, the 123 * second item in this array will be saved to the preference. 124 * 125 * @param entryValues The array to be used as values to save for the preference. 126 */ 127 public void setEntryValues(String[] entryValues) { 128 mEntryValues = entryValues; 129 Arrays.fill(mSetValues, false); 130 Arrays.fill(mOrigValues, false); 131 } 132 133 /** 134 * @see #setEntryValues(CharSequence[]) 135 * @param entryValuesResId The entry values array as a resource. 136 */ 137 public void setEntryValues(@ArrayRes int entryValuesResId) { 138 setEntryValuesCS(getContext().getResources().getTextArray(entryValuesResId)); 139 } 140 141 private void setEntryValuesCS(CharSequence[] values) { 142 setValues(null); 143 if (values != null) { 144 mEntryValues = new String[values.length]; 145 for (int i=0; i<values.length; i++) { 146 mEntryValues[i] = values[i].toString(); 147 } 148 } 149 } 150 151 /** 152 * Returns the array of values to be saved for the preference. 153 * 154 * @return The array of values. 155 */ 156 public String[] getEntryValues() { 157 return mEntryValues; 158 } 159 160 /** 161 * Get the boolean state of a given value. 162 */ 163 public boolean getValue(int index) { 164 return mSetValues[index]; 165 } 166 167 /** 168 * Set the boolean state of a given value. 169 */ 170 public void setValue(int index, boolean state) { 171 mSetValues[index] = state; 172 } 173 174 /** 175 * Sets the current values. 176 */ 177 public void setValues(boolean[] values) { 178 if (mSetValues != null) { 179 Arrays.fill(mSetValues, false); 180 Arrays.fill(mOrigValues, false); 181 if (values != null) { 182 System.arraycopy(values, 0, mSetValues, 0, 183 values.length < mSetValues.length ? values.length : mSetValues.length); 184 } 185 } 186 } 187 188 /** 189 * Returns the summary of this ListPreference. If the summary 190 * has a {@linkplain java.lang.String#format String formatting} 191 * marker in it (i.e. "%s" or "%1$s"), then the current entry 192 * value will be substituted in its place. 193 * 194 * @return the summary with appropriate string substitution 195 */ 196 @Override 197 public CharSequence getSummary() { 198 if (mSummary == null) { 199 return super.getSummary(); 200 } else { 201 return mSummary; 202 } 203 } 204 205 /** 206 * Sets the summary for this Preference with a CharSequence. 207 * If the summary has a 208 * {@linkplain java.lang.String#format String formatting} 209 * marker in it (i.e. "%s" or "%1$s"), then the current entry 210 * value will be substituted in its place when it's retrieved. 211 * 212 * @param summary The summary for the preference. 213 */ 214 @Override 215 public void setSummary(CharSequence summary) { 216 super.setSummary(summary); 217 if (summary == null && mSummary != null) { 218 mSummary = null; 219 } else if (summary != null && !summary.equals(mSummary)) { 220 mSummary = summary.toString(); 221 } 222 } 223 224 /** 225 * Returns the currently selected values. 226 */ 227 public boolean[] getValues() { 228 return mSetValues; 229 } 230 231 /** 232 * Returns the index of the given value (in the entry values array). 233 * 234 * @param value The value whose index should be returned. 235 * @return The index of the value, or -1 if not found. 236 */ 237 public int findIndexOfValue(String value) { 238 if (value != null && mEntryValues != null) { 239 for (int i = mEntryValues.length - 1; i >= 0; i--) { 240 if (mEntryValues[i].equals(value)) { 241 return i; 242 } 243 } 244 } 245 return -1; 246 } 247 248 @Override 249 protected void onPrepareDialogBuilder(Builder builder) { 250 super.onPrepareDialogBuilder(builder); 251 252 if (mEntries == null || mEntryValues == null) { 253 throw new IllegalStateException( 254 "ListPreference requires an entries array and an entryValues array."); 255 } 256 257 mOrigValues = Arrays.copyOf(mSetValues, mSetValues.length); 258 builder.setMultiChoiceItems(mEntries, mSetValues, 259 new DialogInterface.OnMultiChoiceClickListener() { 260 @Override 261 public void onClick(DialogInterface dialog, int which, boolean isChecked) { 262 mSetValues[which] = isChecked; 263 } 264 }); 265 } 266 267 @Override 268 protected void onDialogClosed(boolean positiveResult) { 269 super.onDialogClosed(positiveResult); 270 271 if (positiveResult) { 272 if (callChangeListener(getValues())) { 273 return; 274 } 275 } 276 System.arraycopy(mOrigValues, 0, mSetValues, 0, mSetValues.length); 277 } 278 279 @Override 280 protected Object onGetDefaultValue(TypedArray a, int index) { 281 return a.getString(index); 282 } 283 284 @Override 285 protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { 286 } 287 288 @Override 289 protected Parcelable onSaveInstanceState() { 290 final Parcelable superState = super.onSaveInstanceState(); 291 if (isPersistent()) { 292 // No need to save instance state since it's persistent 293 return superState; 294 } 295 296 final SavedState myState = new SavedState(superState); 297 myState.values = getValues(); 298 return myState; 299 } 300 301 @Override 302 protected void onRestoreInstanceState(Parcelable state) { 303 if (state == null || !state.getClass().equals(SavedState.class)) { 304 // Didn't save state for us in onSaveInstanceState 305 super.onRestoreInstanceState(state); 306 return; 307 } 308 309 SavedState myState = (SavedState) state; 310 super.onRestoreInstanceState(myState.getSuperState()); 311 setValues(myState.values); 312 } 313 314 private static class SavedState extends BaseSavedState { 315 boolean[] values; 316 317 public SavedState(Parcel source) { 318 super(source); 319 values = source.createBooleanArray(); 320 } 321 322 @Override 323 public void writeToParcel(Parcel dest, int flags) { 324 super.writeToParcel(dest, flags); 325 dest.writeBooleanArray(values); 326 } 327 328 public SavedState(Parcelable superState) { 329 super(superState); 330 } 331 332 public static final @android.annotation.NonNull Parcelable.Creator<SavedState> CREATOR = 333 new Parcelable.Creator<SavedState>() { 334 public SavedState createFromParcel(Parcel in) { 335 return new SavedState(in); 336 } 337 338 public SavedState[] newArray(int size) { 339 return new SavedState[size]; 340 } 341 }; 342 } 343 344 } 345