• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.os.Bundle;
21 import android.os.UserHandle;
22 import android.os.UserManager;
23 import android.support.annotation.LayoutRes;
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 import com.android.settingslib.widget.CandidateInfo;
37 
38 import java.util.List;
39 import java.util.Map;
40 
41 public abstract class RadioButtonPickerFragment extends InstrumentedPreferenceFragment implements
42         RadioButtonPreference.OnClickListener {
43 
44     @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
45     static final String EXTRA_FOR_WORK = "for_work";
46 
47     private final Map<String, CandidateInfo> mCandidates = new ArrayMap<>();
48 
49     protected UserManager mUserManager;
50     protected int mUserId;
51 
52     @Override
onAttach(Context context)53     public void onAttach(Context context) {
54         super.onAttach(context);
55         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
56         final Bundle arguments = getArguments();
57 
58         boolean mForWork = false;
59         if (arguments != null) {
60             mForWork = arguments.getBoolean(EXTRA_FOR_WORK);
61         }
62         final UserHandle managedProfile = Utils.getManagedProfile(mUserManager);
63         mUserId = mForWork && managedProfile != null
64                 ? managedProfile.getIdentifier()
65                 : UserHandle.myUserId();
66     }
67 
68     @Override
onCreatePreferences(Bundle savedInstanceState, String rootKey)69     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
70         super.onCreatePreferences(savedInstanceState, rootKey);
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
getPreferenceScreenResId()83     protected abstract int getPreferenceScreenResId();
84 
85     @Override
onRadioButtonClicked(RadioButtonPreference selected)86     public void onRadioButtonClicked(RadioButtonPreference selected) {
87         final String selectedKey = selected.getKey();
88         onRadioButtonConfirmed(selectedKey);
89     }
90 
91     /**
92      * Called after the user tries to select an item.
93      */
onSelectionPerformed(boolean success)94     protected void onSelectionPerformed(boolean success) {
95     }
96 
97     /**
98      * Whether the UI should show a "None" item selection.
99      */
shouldShowItemNone()100     protected boolean shouldShowItemNone() {
101         return false;
102     }
103 
104     /**
105      * Populate any static preferences, independent of the radio buttons.
106      * These might be used to provide extra information about the choices.
107      **/
addStaticPreferences(PreferenceScreen screen)108     protected void addStaticPreferences(PreferenceScreen screen) {
109     }
110 
getCandidate(String key)111     protected CandidateInfo getCandidate(String key) {
112         return mCandidates.get(key);
113     }
114 
onRadioButtonConfirmed(String selectedKey)115     protected void onRadioButtonConfirmed(String selectedKey) {
116         final boolean success = setDefaultKey(selectedKey);
117         if (success) {
118             updateCheckedState(selectedKey);
119         }
120         onSelectionPerformed(success);
121     }
122 
123     /**
124      * A chance for subclasses to bind additional things to the preference.
125      */
126     @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
bindPreferenceExtra(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey, String systemDefaultKey)127     public void bindPreferenceExtra(RadioButtonPreference pref,
128             String key, CandidateInfo info, String defaultKey, String systemDefaultKey) {
129     }
130 
131     @VisibleForTesting
updateCandidates()132     public void updateCandidates() {
133         mCandidates.clear();
134         final List<? extends CandidateInfo> candidateList = getCandidates();
135         if (candidateList != null) {
136             for (CandidateInfo info : candidateList) {
137                 mCandidates.put(info.getKey(), info);
138             }
139         }
140         final String defaultKey = getDefaultKey();
141         final String systemDefaultKey = getSystemDefaultKey();
142         final PreferenceScreen screen = getPreferenceScreen();
143         screen.removeAll();
144         addStaticPreferences(screen);
145 
146         final int customLayoutResId = getRadioButtonPreferenceCustomLayoutResId();
147         if (shouldShowItemNone()) {
148             final RadioButtonPreference nonePref = new RadioButtonPreference(getPrefContext());
149             if (customLayoutResId > 0) {
150                 nonePref.setLayoutResource(customLayoutResId);
151             }
152             nonePref.setIcon(R.drawable.ic_remove_circle);
153             nonePref.setTitle(R.string.app_list_preference_none);
154             nonePref.setChecked(TextUtils.isEmpty(defaultKey));
155             nonePref.setOnClickListener(this);
156             screen.addPreference(nonePref);
157         }
158         if (candidateList != null) {
159             for (CandidateInfo info : candidateList) {
160                 RadioButtonPreference pref = new RadioButtonPreference(getPrefContext());
161                 if (customLayoutResId > 0) {
162                     pref.setLayoutResource(customLayoutResId);
163                 }
164                 bindPreference(pref, info.getKey(), info, defaultKey);
165                 bindPreferenceExtra(pref, info.getKey(), info, defaultKey, systemDefaultKey);
166                 screen.addPreference(pref);
167             }
168         }
169         mayCheckOnlyRadioButton();
170     }
171 
172     @VisibleForTesting
bindPreference(RadioButtonPreference pref, String key, CandidateInfo info, String defaultKey)173     public RadioButtonPreference bindPreference(RadioButtonPreference pref,
174             String key, CandidateInfo info, String defaultKey) {
175         pref.setTitle(info.loadLabel());
176         Utils.setSafeIcon(pref, info.loadIcon());
177         pref.setKey(key);
178         if (TextUtils.equals(defaultKey, key)) {
179             pref.setChecked(true);
180         }
181         pref.setEnabled(info.enabled);
182         pref.setOnClickListener(this);
183         return pref;
184     }
185 
186     @VisibleForTesting
updateCheckedState(String selectedKey)187     public void updateCheckedState(String selectedKey) {
188         final PreferenceScreen screen = getPreferenceScreen();
189         if (screen != null) {
190             final int count = screen.getPreferenceCount();
191             for (int i = 0; i < count; i++) {
192                 final Preference pref = screen.getPreference(i);
193                 if (pref instanceof RadioButtonPreference) {
194                     final RadioButtonPreference radioPref = (RadioButtonPreference) pref;
195                     final boolean newCheckedState = TextUtils.equals(pref.getKey(), selectedKey);
196                     if (radioPref.isChecked() != newCheckedState) {
197                         radioPref.setChecked(TextUtils.equals(pref.getKey(), selectedKey));
198                     }
199                 }
200             }
201         }
202     }
203 
204     @VisibleForTesting
mayCheckOnlyRadioButton()205     public void mayCheckOnlyRadioButton() {
206         final PreferenceScreen screen = getPreferenceScreen();
207         // If there is only 1 thing on screen, select it.
208         if (screen != null && screen.getPreferenceCount() == 1) {
209             final Preference onlyPref = screen.getPreference(0);
210             if (onlyPref instanceof RadioButtonPreference) {
211                 ((RadioButtonPreference) onlyPref).setChecked(true);
212             }
213         }
214     }
215 
getCandidates()216     protected abstract List<? extends CandidateInfo> getCandidates();
217 
getDefaultKey()218     protected abstract String getDefaultKey();
219 
setDefaultKey(String key)220     protected abstract boolean setDefaultKey(String key);
221 
getSystemDefaultKey()222     protected String getSystemDefaultKey() {
223         return null;
224     }
225 
226     /**
227      * Provides a custom layout for each candidate row.
228      */
229     @LayoutRes
getRadioButtonPreferenceCustomLayoutResId()230     protected int getRadioButtonPreferenceCustomLayoutResId() {
231         return 0;
232     }
233 
234 }
235