1 /* 2 * Copyright (C) 2010 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.StringRes; 20 import android.compat.annotation.UnsupportedAppUsage; 21 import android.content.Context; 22 import android.content.SharedPreferences; 23 import android.content.res.TypedArray; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.text.TextUtils; 27 import android.util.AttributeSet; 28 import android.view.View; 29 import android.widget.TextView; 30 31 /** 32 * Common base class for preferences that have two selectable states, persist a 33 * boolean value in SharedPreferences, and may have dependent preferences that are 34 * enabled/disabled based on the current state. 35 * 36 * @deprecated Use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a> 37 * <a href="{@docRoot}reference/androidx/preference/package-summary.html"> 38 * Preference Library</a> for consistent behavior across all devices. For more information on 39 * using the AndroidX Preference Library see 40 * <a href="{@docRoot}guide/topics/ui/settings.html">Settings</a>. 41 */ 42 @Deprecated 43 public abstract class TwoStatePreference extends Preference { 44 45 private CharSequence mSummaryOn; 46 private CharSequence mSummaryOff; 47 boolean mChecked; 48 private boolean mCheckedSet; 49 private boolean mDisableDependentsState; 50 TwoStatePreference( Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)51 public TwoStatePreference( 52 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 53 super(context, attrs, defStyleAttr, defStyleRes); 54 } 55 TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr)56 public TwoStatePreference(Context context, AttributeSet attrs, int defStyleAttr) { 57 this(context, attrs, defStyleAttr, 0); 58 } 59 TwoStatePreference(Context context, AttributeSet attrs)60 public TwoStatePreference(Context context, AttributeSet attrs) { 61 this(context, attrs, 0); 62 } 63 TwoStatePreference(Context context)64 public TwoStatePreference(Context context) { 65 this(context, null); 66 } 67 68 @Override onClick()69 protected void onClick() { 70 super.onClick(); 71 72 final boolean newValue = !isChecked(); 73 if (callChangeListener(newValue)) { 74 setChecked(newValue); 75 } 76 } 77 78 /** 79 * Sets the checked state and saves it to the {@link SharedPreferences}. 80 * 81 * @param checked The checked state. 82 */ setChecked(boolean checked)83 public void setChecked(boolean checked) { 84 // Always persist/notify the first time; don't assume the field's default of false. 85 final boolean changed = mChecked != checked; 86 if (changed || !mCheckedSet) { 87 mChecked = checked; 88 mCheckedSet = true; 89 persistBoolean(checked); 90 if (changed) { 91 notifyDependencyChange(shouldDisableDependents()); 92 notifyChanged(); 93 } 94 } 95 } 96 97 /** 98 * Returns the checked state. 99 * 100 * @return The checked state. 101 */ isChecked()102 public boolean isChecked() { 103 return mChecked; 104 } 105 106 @Override shouldDisableDependents()107 public boolean shouldDisableDependents() { 108 boolean shouldDisable = mDisableDependentsState ? mChecked : !mChecked; 109 return shouldDisable || super.shouldDisableDependents(); 110 } 111 112 /** 113 * Sets the summary to be shown when checked. 114 * 115 * @param summary The summary to be shown when checked. 116 */ setSummaryOn(CharSequence summary)117 public void setSummaryOn(CharSequence summary) { 118 mSummaryOn = summary; 119 if (isChecked()) { 120 notifyChanged(); 121 } 122 } 123 124 /** 125 * @see #setSummaryOn(CharSequence) 126 * @param summaryResId The summary as a resource. 127 */ setSummaryOn(@tringRes int summaryResId)128 public void setSummaryOn(@StringRes int summaryResId) { 129 setSummaryOn(getContext().getString(summaryResId)); 130 } 131 132 /** 133 * Returns the summary to be shown when checked. 134 * @return The summary. 135 */ getSummaryOn()136 public CharSequence getSummaryOn() { 137 return mSummaryOn; 138 } 139 140 /** 141 * Sets the summary to be shown when unchecked. 142 * 143 * @param summary The summary to be shown when unchecked. 144 */ setSummaryOff(CharSequence summary)145 public void setSummaryOff(CharSequence summary) { 146 mSummaryOff = summary; 147 if (!isChecked()) { 148 notifyChanged(); 149 } 150 } 151 152 /** 153 * @see #setSummaryOff(CharSequence) 154 * @param summaryResId The summary as a resource. 155 */ setSummaryOff(@tringRes int summaryResId)156 public void setSummaryOff(@StringRes int summaryResId) { 157 setSummaryOff(getContext().getString(summaryResId)); 158 } 159 160 /** 161 * Returns the summary to be shown when unchecked. 162 * @return The summary. 163 */ getSummaryOff()164 public CharSequence getSummaryOff() { 165 return mSummaryOff; 166 } 167 168 /** 169 * Returns whether dependents are disabled when this preference is on ({@code true}) 170 * or when this preference is off ({@code false}). 171 * 172 * @return Whether dependents are disabled when this preference is on ({@code true}) 173 * or when this preference is off ({@code false}). 174 */ getDisableDependentsState()175 public boolean getDisableDependentsState() { 176 return mDisableDependentsState; 177 } 178 179 /** 180 * Sets whether dependents are disabled when this preference is on ({@code true}) 181 * or when this preference is off ({@code false}). 182 * 183 * @param disableDependentsState The preference state that should disable dependents. 184 */ setDisableDependentsState(boolean disableDependentsState)185 public void setDisableDependentsState(boolean disableDependentsState) { 186 mDisableDependentsState = disableDependentsState; 187 } 188 189 @Override onGetDefaultValue(TypedArray a, int index)190 protected Object onGetDefaultValue(TypedArray a, int index) { 191 return a.getBoolean(index, false); 192 } 193 194 @Override onSetInitialValue(boolean restoreValue, Object defaultValue)195 protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { 196 setChecked(restoreValue ? getPersistedBoolean(mChecked) 197 : (Boolean) defaultValue); 198 } 199 200 /** 201 * Sync a summary view contained within view's subhierarchy with the correct summary text. 202 * @param view View where a summary should be located 203 */ 204 @UnsupportedAppUsage syncSummaryView(View view)205 void syncSummaryView(View view) { 206 // Sync the summary view 207 TextView summaryView = (TextView) view.findViewById(com.android.internal.R.id.summary); 208 if (summaryView != null) { 209 boolean useDefaultSummary = true; 210 if (mChecked && !TextUtils.isEmpty(mSummaryOn)) { 211 summaryView.setText(mSummaryOn); 212 useDefaultSummary = false; 213 } else if (!mChecked && !TextUtils.isEmpty(mSummaryOff)) { 214 summaryView.setText(mSummaryOff); 215 useDefaultSummary = false; 216 } 217 218 if (useDefaultSummary) { 219 final CharSequence summary = getSummary(); 220 if (!TextUtils.isEmpty(summary)) { 221 summaryView.setText(summary); 222 useDefaultSummary = false; 223 } 224 } 225 226 int newVisibility = View.GONE; 227 if (!useDefaultSummary) { 228 // Someone has written to it 229 newVisibility = View.VISIBLE; 230 } 231 if (newVisibility != summaryView.getVisibility()) { 232 summaryView.setVisibility(newVisibility); 233 } 234 } 235 } 236 237 @Override onSaveInstanceState()238 protected Parcelable onSaveInstanceState() { 239 final Parcelable superState = super.onSaveInstanceState(); 240 if (isPersistent()) { 241 // No need to save instance state since it's persistent 242 return superState; 243 } 244 245 final SavedState myState = new SavedState(superState); 246 myState.checked = isChecked(); 247 return myState; 248 } 249 250 @Override onRestoreInstanceState(Parcelable state)251 protected void onRestoreInstanceState(Parcelable state) { 252 if (state == null || !state.getClass().equals(SavedState.class)) { 253 // Didn't save state for us in onSaveInstanceState 254 super.onRestoreInstanceState(state); 255 return; 256 } 257 258 SavedState myState = (SavedState) state; 259 super.onRestoreInstanceState(myState.getSuperState()); 260 setChecked(myState.checked); 261 } 262 263 static class SavedState extends BaseSavedState { 264 boolean checked; 265 SavedState(Parcel source)266 public SavedState(Parcel source) { 267 super(source); 268 checked = source.readInt() == 1; 269 } 270 271 @Override writeToParcel(Parcel dest, int flags)272 public void writeToParcel(Parcel dest, int flags) { 273 super.writeToParcel(dest, flags); 274 dest.writeInt(checked ? 1 : 0); 275 } 276 SavedState(Parcelable superState)277 public SavedState(Parcelable superState) { 278 super(superState); 279 } 280 281 public static final @android.annotation.NonNull Parcelable.Creator<SavedState> CREATOR = 282 new Parcelable.Creator<SavedState>() { 283 public SavedState createFromParcel(Parcel in) { 284 return new SavedState(in); 285 } 286 287 public SavedState[] newArray(int size) { 288 return new SavedState[size]; 289 } 290 }; 291 } 292 } 293