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 17 package com.android.settings.widget; 18 19 import android.content.Context; 20 import android.graphics.drawable.Drawable; 21 import android.os.Bundle; 22 import android.os.UserHandle; 23 import android.os.UserManager; 24 import android.support.annotation.VisibleForTesting; 25 import android.support.v7.preference.Preference; 26 import android.support.v7.preference.PreferenceScreen; 27 import android.text.TextUtils; 28 import android.util.ArrayMap; 29 import android.view.LayoutInflater; 30 import android.view.View; 31 import android.view.ViewGroup; 32 33 import com.android.settings.R; 34 import com.android.settings.Utils; 35 import com.android.settings.core.InstrumentedPreferenceFragment; 36 37 import java.util.List; 38 import java.util.Map; 39 40 public 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 onAttach(Context context)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 onCreatePreferences(Bundle savedInstanceState, String rootKey)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 onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)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 onRadioButtonClicked(RadioButtonPreference selected)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 */ onSelectionPerformed(boolean success)91 protected void onSelectionPerformed(boolean success) { 92 } 93 94 /** 95 * Whether the UI should show a "None" item selection. 96 */ shouldShowItemNone()97 protected boolean shouldShowItemNone() { 98 return false; 99 } 100 getCandidate(String key)101 protected CandidateInfo getCandidate(String key) { 102 return mCandidates.get(key); 103 } 104 onRadioButtonConfirmed(String selectedKey)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) bindPreferenceExtra(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey, String systemDefaultKey)117 public void bindPreferenceExtra(RadioButtonPreference pref, 118 String key, CandidateInfo info, String defaultKey, String systemDefaultKey) { 119 } 120 121 @VisibleForTesting updateCandidates()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 if (candidateList != null) { 143 for (CandidateInfo info : candidateList) { 144 RadioButtonPreference pref = new RadioButtonPreference(getPrefContext()); 145 bindPreference(pref, info.getKey(), info, defaultKey); 146 bindPreferenceExtra(pref, info.getKey(), info, defaultKey, systemDefaultKey); 147 screen.addPreference(pref); 148 } 149 } 150 mayCheckOnlyRadioButton(); 151 } 152 153 @VisibleForTesting bindPreference(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey)154 public RadioButtonPreference bindPreference(RadioButtonPreference pref, 155 String key, CandidateInfo info, String defaultKey) { 156 pref.setTitle(info.loadLabel()); 157 pref.setIcon(info.loadIcon()); 158 pref.setKey(key); 159 if (TextUtils.equals(defaultKey, key)) { 160 pref.setChecked(true); 161 } 162 pref.setEnabled(info.enabled); 163 pref.setOnClickListener(this); 164 return pref; 165 } 166 167 @VisibleForTesting updateCheckedState(String selectedKey)168 public void updateCheckedState(String selectedKey) { 169 final PreferenceScreen screen = getPreferenceScreen(); 170 if (screen != null) { 171 final int count = screen.getPreferenceCount(); 172 for (int i = 0; i < count; i++) { 173 final Preference pref = screen.getPreference(i); 174 if (pref instanceof RadioButtonPreference) { 175 final RadioButtonPreference radioPref = (RadioButtonPreference) pref; 176 final boolean newCheckedState = TextUtils.equals(pref.getKey(), selectedKey); 177 if (radioPref.isChecked() != newCheckedState) { 178 radioPref.setChecked(TextUtils.equals(pref.getKey(), selectedKey)); 179 } 180 } 181 } 182 } 183 } 184 185 @VisibleForTesting mayCheckOnlyRadioButton()186 public void mayCheckOnlyRadioButton() { 187 final PreferenceScreen screen = getPreferenceScreen(); 188 // If there is only 1 thing on screen, select it. 189 if (screen != null && screen.getPreferenceCount() == 1) { 190 final Preference onlyPref = screen.getPreference(0); 191 if (onlyPref instanceof RadioButtonPreference) { 192 ((RadioButtonPreference) onlyPref).setChecked(true); 193 } 194 } 195 } 196 getCandidates()197 protected abstract List<? extends CandidateInfo> getCandidates(); 198 getDefaultKey()199 protected abstract String getDefaultKey(); 200 setDefaultKey(String key)201 protected abstract boolean setDefaultKey(String key); 202 getSystemDefaultKey()203 protected String getSystemDefaultKey() { 204 return null; 205 } 206 207 public static abstract class CandidateInfo { 208 209 public final boolean enabled; 210 CandidateInfo(boolean enabled)211 public CandidateInfo(boolean enabled) { 212 this.enabled = enabled; 213 } 214 loadLabel()215 public abstract CharSequence loadLabel(); 216 loadIcon()217 public abstract Drawable loadIcon(); 218 getKey()219 public abstract String getKey(); 220 } 221 222 } 223