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