1/* 2 * Copyright (C) 2017 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 17package com.android.settings.widget; 18 19import android.content.Context; 20import android.graphics.drawable.Drawable; 21import android.os.Bundle; 22import android.os.UserHandle; 23import android.os.UserManager; 24import android.support.annotation.VisibleForTesting; 25import android.support.v7.preference.Preference; 26import android.support.v7.preference.PreferenceScreen; 27import android.text.TextUtils; 28import android.util.ArrayMap; 29import android.view.LayoutInflater; 30import android.view.View; 31import android.view.ViewGroup; 32 33import com.android.settings.R; 34import com.android.settings.Utils; 35import com.android.settings.core.InstrumentedPreferenceFragment; 36 37import java.util.List; 38import java.util.Map; 39 40public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFragment implements 41 RadioButtonPreference.OnClickListener { 42 43 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 44 static final String EXTRA_FOR_WORK = "for_work"; 45 46 private final Map<String, CandidateInfo> mCandidates = new ArrayMap<>(); 47 48 protected UserManager mUserManager; 49 protected int mUserId; 50 51 @Override 52 public void onAttach(Context context) { 53 super.onAttach(context); 54 mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); 55 final Bundle arguments = getArguments(); 56 57 boolean mForWork = false; 58 if (arguments != null) { 59 mForWork = arguments.getBoolean(EXTRA_FOR_WORK); 60 } 61 final UserHandle managedProfile = Utils.getManagedProfile(mUserManager); 62 mUserId = mForWork && managedProfile != null 63 ? managedProfile.getIdentifier() 64 : UserHandle.myUserId(); 65 } 66 67 @Override 68 public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 69 super.onCreatePreferences(savedInstanceState, rootKey); 70 addPreferencesFromResource(R.xml.placeholder_prefs); 71 updateCandidates(); 72 } 73 74 @Override 75 public View onCreateView(LayoutInflater inflater, ViewGroup container, 76 Bundle savedInstanceState) { 77 final View view = super.onCreateView(inflater, container, savedInstanceState); 78 setHasOptionsMenu(true); 79 return view; 80 } 81 82 @Override 83 public void onRadioButtonClicked(RadioButtonPreference selected) { 84 final String selectedKey = selected.getKey(); 85 onRadioButtonConfirmed(selectedKey); 86 } 87 88 /** 89 * Called after the user tries to select an item. 90 */ 91 protected void onSelectionPerformed(boolean success) { 92 } 93 94 /** 95 * Whether the UI should show a "None" item selection. 96 */ 97 protected boolean shouldShowItemNone() { 98 return false; 99 } 100 101 protected CandidateInfo getCandidate(String key) { 102 return mCandidates.get(key); 103 } 104 105 protected void onRadioButtonConfirmed(String selectedKey) { 106 final boolean success = setDefaultKey(selectedKey); 107 if (success) { 108 updateCheckedState(selectedKey); 109 } 110 onSelectionPerformed(success); 111 } 112 113 /** 114 * A chance for subclasses to bind additional things to the preference. 115 */ 116 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 117 public void bindPreferenceExtra(RadioButtonPreference pref, 118 String key, CandidateInfo info, String defaultKey, String systemDefaultKey) { 119 } 120 121 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 122 public void updateCandidates() { 123 mCandidates.clear(); 124 final List<? extends CandidateInfo> candidateList = getCandidates(); 125 if (candidateList != null) { 126 for (CandidateInfo info : candidateList) { 127 mCandidates.put(info.getKey(), info); 128 } 129 } 130 final String defaultKey = getDefaultKey(); 131 final String systemDefaultKey = getSystemDefaultKey(); 132 final PreferenceScreen screen = getPreferenceScreen(); 133 screen.removeAll(); 134 if (shouldShowItemNone()) { 135 final RadioButtonPreference nonePref = new RadioButtonPreference(getPrefContext()); 136 nonePref.setIcon(R.drawable.ic_remove_circle); 137 nonePref.setTitle(R.string.app_list_preference_none); 138 nonePref.setChecked(TextUtils.isEmpty(defaultKey)); 139 nonePref.setOnClickListener(this); 140 screen.addPreference(nonePref); 141 } 142 for (Map.Entry<String, CandidateInfo> app : mCandidates.entrySet()) { 143 RadioButtonPreference pref = new RadioButtonPreference(getPrefContext()); 144 bindPreference(pref, app.getKey(), app.getValue(), defaultKey); 145 bindPreferenceExtra(pref, app.getKey(), app.getValue(), defaultKey, systemDefaultKey); 146 screen.addPreference(pref); 147 } 148 mayCheckOnlyRadioButton(); 149 } 150 151 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 152 public RadioButtonPreference bindPreference(RadioButtonPreference pref, 153 String key, CandidateInfo info, String defaultKey) { 154 pref.setTitle(info.loadLabel()); 155 pref.setIcon(info.loadIcon()); 156 pref.setKey(key); 157 if (TextUtils.equals(defaultKey, key)) { 158 pref.setChecked(true); 159 } 160 pref.setEnabled(info.enabled); 161 pref.setOnClickListener(this); 162 return pref; 163 } 164 165 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 166 public void updateCheckedState(String selectedKey) { 167 final PreferenceScreen screen = getPreferenceScreen(); 168 if (screen != null) { 169 final int count = screen.getPreferenceCount(); 170 for (int i = 0; i < count; i++) { 171 final Preference pref = screen.getPreference(i); 172 if (pref instanceof RadioButtonPreference) { 173 final RadioButtonPreference radioPref = (RadioButtonPreference) pref; 174 final boolean newCheckedState = TextUtils.equals(pref.getKey(), selectedKey); 175 if (radioPref.isChecked() != newCheckedState) { 176 radioPref.setChecked(TextUtils.equals(pref.getKey(), selectedKey)); 177 } 178 } 179 } 180 } 181 } 182 183 @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) 184 public void mayCheckOnlyRadioButton() { 185 final PreferenceScreen screen = getPreferenceScreen(); 186 // If there is only 1 thing on screen, select it. 187 if (screen != null && screen.getPreferenceCount() == 1) { 188 final Preference onlyPref = screen.getPreference(0); 189 if (onlyPref instanceof RadioButtonPreference) { 190 ((RadioButtonPreference) onlyPref).setChecked(true); 191 } 192 } 193 } 194 195 protected abstract List<? extends CandidateInfo> getCandidates(); 196 197 protected abstract String getDefaultKey(); 198 199 protected abstract boolean setDefaultKey(String key); 200 201 protected String getSystemDefaultKey() { 202 return null; 203 } 204 205 public static abstract class CandidateInfo { 206 207 public final boolean enabled; 208 209 public CandidateInfo(boolean enabled) { 210 this.enabled = enabled; 211 } 212 213 public abstract CharSequence loadLabel(); 214 215 public abstract Drawable loadIcon(); 216 217 public abstract String getKey(); 218 } 219 220} 221