• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.support.v17.preference;
18 
19 import android.os.Bundle;
20 import android.support.annotation.NonNull;
21 import android.support.annotation.Nullable;
22 import android.support.v14.preference.MultiSelectListPreference;
23 import android.support.v17.leanback.widget.VerticalGridView;
24 import android.support.v4.util.ArraySet;
25 import android.support.v7.preference.DialogPreference;
26 import android.support.v7.preference.ListPreference;
27 import android.support.v7.widget.RecyclerView;
28 import android.text.TextUtils;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.view.ViewGroup;
32 import android.widget.Checkable;
33 import android.widget.TextView;
34 
35 import java.util.Collections;
36 import java.util.HashSet;
37 import java.util.Set;
38 
39 public class LeanbackListPreferenceDialogFragment extends LeanbackPreferenceDialogFragment {
40 
41     private static final String SAVE_STATE_IS_MULTI =
42             "LeanbackListPreferenceDialogFragment.isMulti";
43     private static final String SAVE_STATE_ENTRIES = "LeanbackListPreferenceDialogFragment.entries";
44     private static final String SAVE_STATE_ENTRY_VALUES =
45             "LeanbackListPreferenceDialogFragment.entryValues";
46     private static final String SAVE_STATE_TITLE = "LeanbackListPreferenceDialogFragment.title";
47     private static final String SAVE_STATE_MESSAGE = "LeanbackListPreferenceDialogFragment.message";
48     private static final String SAVE_STATE_INITIAL_SELECTIONS =
49             "LeanbackListPreferenceDialogFragment.initialSelections";
50     private static final String SAVE_STATE_INITIAL_SELECTION =
51             "LeanbackListPreferenceDialogFragment.initialSelection";
52 
53     private boolean mMulti;
54     private CharSequence[] mEntries;
55     private CharSequence[] mEntryValues;
56     private CharSequence mDialogTitle;
57     private CharSequence mDialogMessage;
58     private Set<String> mInitialSelections;
59     private String mInitialSelection;
60 
newInstanceSingle(String key)61     public static LeanbackListPreferenceDialogFragment newInstanceSingle(String key) {
62         final Bundle args = new Bundle(1);
63         args.putString(ARG_KEY, key);
64 
65         final LeanbackListPreferenceDialogFragment
66                 fragment = new LeanbackListPreferenceDialogFragment();
67         fragment.setArguments(args);
68 
69         return fragment;
70     }
71 
newInstanceMulti(String key)72     public static LeanbackListPreferenceDialogFragment newInstanceMulti(String key) {
73         final Bundle args = new Bundle(1);
74         args.putString(ARG_KEY, key);
75 
76         final LeanbackListPreferenceDialogFragment
77                 fragment = new LeanbackListPreferenceDialogFragment();
78         fragment.setArguments(args);
79 
80         return fragment;
81     }
82 
83     @Override
onCreate(Bundle savedInstanceState)84     public void onCreate(Bundle savedInstanceState) {
85         super.onCreate(savedInstanceState);
86 
87         if (savedInstanceState == null) {
88             final DialogPreference preference = getPreference();
89             mDialogTitle = preference.getDialogTitle();
90             mDialogMessage = preference.getDialogMessage();
91 
92             if (preference instanceof ListPreference) {
93                 mMulti = false;
94                 mEntries = ((ListPreference) preference).getEntries();
95                 mEntryValues = ((ListPreference) preference).getEntryValues();
96                 mInitialSelection = ((ListPreference) preference).getValue();
97             } else if (preference instanceof MultiSelectListPreference) {
98                 mMulti = true;
99                 mEntries = ((MultiSelectListPreference) preference).getEntries();
100                 mEntryValues = ((MultiSelectListPreference) preference).getEntryValues();
101                 mInitialSelections = ((MultiSelectListPreference) preference).getValues();
102             } else {
103                 throw new IllegalArgumentException("Preference must be a ListPreference or "
104                         + "MultiSelectListPreference");
105             }
106         } else {
107             mDialogTitle = savedInstanceState.getCharSequence(SAVE_STATE_TITLE);
108             mDialogMessage = savedInstanceState.getCharSequence(SAVE_STATE_MESSAGE);
109             mMulti = savedInstanceState.getBoolean(SAVE_STATE_IS_MULTI);
110             mEntries = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRIES);
111             mEntryValues = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES);
112             if (mMulti) {
113                 final String[] initialSelections = savedInstanceState.getStringArray(
114                         SAVE_STATE_INITIAL_SELECTIONS);
115                 mInitialSelections = new ArraySet<>(
116                         initialSelections != null ? initialSelections.length : 0);
117                 if (initialSelections != null) {
118                     Collections.addAll(mInitialSelections, initialSelections);
119                 }
120             } else {
121                 mInitialSelection = savedInstanceState.getString(SAVE_STATE_INITIAL_SELECTION);
122             }
123         }
124     }
125 
126     @Override
onSaveInstanceState(Bundle outState)127     public void onSaveInstanceState(Bundle outState) {
128         super.onSaveInstanceState(outState);
129         outState.putCharSequence(SAVE_STATE_TITLE, mDialogTitle);
130         outState.putCharSequence(SAVE_STATE_MESSAGE, mDialogMessage);
131         outState.putBoolean(SAVE_STATE_IS_MULTI, mMulti);
132         outState.putCharSequenceArray(SAVE_STATE_ENTRIES, mEntries);
133         outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, mEntryValues);
134         if (mMulti) {
135             outState.putStringArray(SAVE_STATE_INITIAL_SELECTIONS,
136                     mInitialSelections.toArray(new String[mInitialSelections.size()]));
137         } else {
138             outState.putString(SAVE_STATE_INITIAL_SELECTION, mInitialSelection);
139         }
140     }
141 
142     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)143     public @Nullable View onCreateView(LayoutInflater inflater, ViewGroup container,
144             Bundle savedInstanceState) {
145         final View view = inflater.inflate(R.layout.leanback_list_preference_fragment, container,
146                 false);
147         final VerticalGridView verticalGridView =
148                 (VerticalGridView) view.findViewById(android.R.id.list);
149 
150         verticalGridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
151         verticalGridView.setFocusScrollStrategy(VerticalGridView.FOCUS_SCROLL_ALIGNED);
152         verticalGridView.setAdapter(onCreateAdapter());
153         verticalGridView.requestFocus();
154 
155         final CharSequence title = mDialogTitle;
156         if (!TextUtils.isEmpty(title)) {
157             final TextView titleView = (TextView) view.findViewById(R.id.decor_title);
158             titleView.setText(title);
159         }
160 
161         final CharSequence message = mDialogMessage;
162         if (!TextUtils.isEmpty(message)) {
163             final TextView messageView = (TextView) view.findViewById(android.R.id.message);
164             messageView.setVisibility(View.VISIBLE);
165             messageView.setText(message);
166         }
167 
168         return view;
169     }
170 
onCreateAdapter()171     public RecyclerView.Adapter onCreateAdapter() {
172         //final DialogPreference preference = getPreference();
173         if (mMulti) {
174             return new AdapterMulti(mEntries, mEntryValues, mInitialSelections);
175         } else {
176             return new AdapterSingle(mEntries, mEntryValues, mInitialSelection);
177         }
178     }
179 
180     public class AdapterSingle extends RecyclerView.Adapter<ViewHolder>
181             implements ViewHolder.OnItemClickListener {
182 
183         private final CharSequence[] mEntries;
184         private final CharSequence[] mEntryValues;
185         private CharSequence mSelectedValue;
186 
AdapterSingle(CharSequence[] entries, CharSequence[] entryValues, CharSequence selectedValue)187         public AdapterSingle(CharSequence[] entries, CharSequence[] entryValues,
188                 CharSequence selectedValue) {
189             mEntries = entries;
190             mEntryValues = entryValues;
191             mSelectedValue = selectedValue;
192         }
193 
194         @Override
onCreateViewHolder(ViewGroup parent, int viewType)195         public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
196             final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
197             final View view = inflater.inflate(R.layout.leanback_list_preference_item_single,
198                     parent, false);
199             return new ViewHolder(view, this);
200         }
201 
202         @Override
onBindViewHolder(ViewHolder holder, int position)203         public void onBindViewHolder(ViewHolder holder, int position) {
204             holder.getWidgetView().setChecked(mEntryValues[position].equals(mSelectedValue));
205             holder.getTitleView().setText(mEntries[position]);
206         }
207 
208         @Override
getItemCount()209         public int getItemCount() {
210             return mEntries.length;
211         }
212 
213         @Override
onItemClick(ViewHolder viewHolder)214         public void onItemClick(ViewHolder viewHolder) {
215             final int index = viewHolder.getAdapterPosition();
216             if (index == RecyclerView.NO_POSITION) {
217                 return;
218             }
219             final CharSequence entry = mEntryValues[index];
220             final ListPreference preference = (ListPreference) getPreference();
221             if (index >= 0) {
222                 String value = mEntryValues[index].toString();
223                 if (preference.callChangeListener(value)) {
224                     preference.setValue(value);
225                     mSelectedValue = entry;
226                 }
227             }
228 
229             getFragmentManager().popBackStack();
230             notifyDataSetChanged();
231         }
232     }
233 
234     public class AdapterMulti extends RecyclerView.Adapter<ViewHolder>
235             implements ViewHolder.OnItemClickListener {
236 
237         private final CharSequence[] mEntries;
238         private final CharSequence[] mEntryValues;
239         private final Set<String> mSelections;
240 
AdapterMulti(CharSequence[] entries, CharSequence[] entryValues, Set<String> initialSelections)241         public AdapterMulti(CharSequence[] entries, CharSequence[] entryValues,
242                 Set<String> initialSelections) {
243             mEntries = entries;
244             mEntryValues = entryValues;
245             mSelections = new HashSet<>(initialSelections);
246         }
247 
248         @Override
onCreateViewHolder(ViewGroup parent, int viewType)249         public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
250             final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
251             final View view = inflater.inflate(R.layout.leanback_list_preference_item_multi, parent,
252                     false);
253             return new ViewHolder(view, this);
254         }
255 
256         @Override
onBindViewHolder(ViewHolder holder, int position)257         public void onBindViewHolder(ViewHolder holder, int position) {
258             holder.getWidgetView().setChecked(
259                     mSelections.contains(mEntryValues[position].toString()));
260             holder.getTitleView().setText(mEntries[position]);
261         }
262 
263         @Override
getItemCount()264         public int getItemCount() {
265             return mEntries.length;
266         }
267 
268         @Override
onItemClick(ViewHolder viewHolder)269         public void onItemClick(ViewHolder viewHolder) {
270             final int index = viewHolder.getAdapterPosition();
271             if (index == RecyclerView.NO_POSITION) {
272                 return;
273             }
274             final String entry = mEntryValues[index].toString();
275             if (mSelections.contains(entry)) {
276                 mSelections.remove(entry);
277             } else {
278                 mSelections.add(entry);
279             }
280             final MultiSelectListPreference multiSelectListPreference
281                     = (MultiSelectListPreference) getPreference();
282             // Pass copies of the set to callChangeListener and setValues to avoid mutations
283             if (multiSelectListPreference.callChangeListener(new HashSet<>(mSelections))) {
284                 multiSelectListPreference.setValues(new HashSet<>(mSelections));
285                 mInitialSelections = mSelections;
286             } else {
287                 // Change refused, back it out
288                 if (mSelections.contains(entry)) {
289                     mSelections.remove(entry);
290                 } else {
291                     mSelections.add(entry);
292                 }
293             }
294 
295             notifyDataSetChanged();
296         }
297     }
298 
299     public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
300 
301         public interface OnItemClickListener {
onItemClick(ViewHolder viewHolder)302             void onItemClick(ViewHolder viewHolder);
303         }
304 
305         private final Checkable mWidgetView;
306         private final TextView mTitleView;
307         private final ViewGroup mContainer;
308         private final OnItemClickListener mListener;
309 
ViewHolder(@onNull View view, @NonNull OnItemClickListener listener)310         public ViewHolder(@NonNull View view, @NonNull OnItemClickListener listener) {
311             super(view);
312             mWidgetView = (Checkable) view.findViewById(R.id.button);
313             mContainer = (ViewGroup) view.findViewById(R.id.container);
314             mTitleView = (TextView) view.findViewById(android.R.id.title);
315             mContainer.setOnClickListener(this);
316             mListener = listener;
317         }
318 
getWidgetView()319         public Checkable getWidgetView() {
320             return mWidgetView;
321         }
322 
getTitleView()323         public TextView getTitleView() {
324             return mTitleView;
325         }
326 
getContainer()327         public ViewGroup getContainer() {
328             return mContainer;
329         }
330 
331         @Override
onClick(View v)332         public void onClick(View v) {
333             mListener.onItemClick(this);
334         }
335     }
336 }
337