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.settingslib.widget;
18 
19 import android.content.Context;
20 import android.util.AttributeSet;
21 import android.view.View;
22 import android.widget.AdapterView;
23 
24 import androidx.preference.Preference;
25 import androidx.preference.Preference.OnPreferenceClickListener;
26 import androidx.preference.PreferenceViewHolder;
27 
28 import com.android.settingslib.widget.settingsspinner.SettingsSpinner;
29 import com.android.settingslib.widget.settingsspinner.SettingsSpinnerAdapter;
30 
31 /**
32  * This preference uses SettingsSpinner & SettingsSpinnerAdapter which provide default layouts for
33  * both view and drop down view of the Spinner.
34  */
35 public class SettingsSpinnerPreference extends Preference implements OnPreferenceClickListener {
36 
37     private SettingsSpinnerAdapter mAdapter;
38     private AdapterView.OnItemSelectedListener mListener;
39     private int mPosition;
40     private boolean mShouldPerformClick;
41 
42     /**
43      * Perform inflation from XML and apply a class-specific base style.
44      *
45      * @param context  The {@link Context} this is associated with, through which it can
46      *                 access the current theme, resources, {@link SharedPreferences}, etc.
47      * @param attrs    The attributes of the XML tag that is inflating the preference
48      * @param defStyle An attribute in the current theme that contains a reference to a style
49      *                 resource that supplies default values for the view. Can be 0 to not
50      *                 look for defaults.
51      */
SettingsSpinnerPreference(Context context, AttributeSet attrs, int defStyle)52     public SettingsSpinnerPreference(Context context, AttributeSet attrs, int defStyle) {
53         super(context, attrs, defStyle);
54         setLayoutResource(R.layout.settings_spinner_preference);
55         setOnPreferenceClickListener(this);
56     }
57 
58     /**
59      * Perform inflation from XML and apply a class-specific base style.
60      *
61      * @param context The {@link Context} this is associated with, through which it can
62      *                access the current theme, resources, {@link SharedPreferences}, etc.
63      * @param attrs   The attributes of the XML tag that is inflating the preference
64      */
SettingsSpinnerPreference(Context context, AttributeSet attrs)65     public SettingsSpinnerPreference(Context context, AttributeSet attrs) {
66         super(context, attrs);
67         setLayoutResource(R.layout.settings_spinner_preference);
68         setOnPreferenceClickListener(this);
69     }
70 
71     /**
72      * Constructor to create a preference.
73      *
74      * @param context The Context this is associated with.
75      */
SettingsSpinnerPreference(Context context)76     public SettingsSpinnerPreference(Context context) {
77         this(context, null);
78     }
79 
80     @Override
onPreferenceClick(Preference preference)81     public boolean onPreferenceClick(Preference preference) {
82         mShouldPerformClick = true;
83         notifyChanged();
84         return true;
85     }
86 
87     /** Sets adapter of the spinner. */
setAdapter(T adapter)88     public <T extends SettingsSpinnerAdapter> void setAdapter(T adapter) {
89         mAdapter = adapter;
90         notifyChanged();
91     }
92 
93     /** Sets item selection listener of the spinner. */
setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener)94     public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) {
95         mListener = listener;
96     }
97 
98     /** Gets selected item of the spinner. */
getSelectedItem()99     public Object getSelectedItem() {
100         return mAdapter == null ? null : mAdapter.getItem(mPosition);
101     }
102 
103     /** Gets selection position of the spinner */
setSelection(int position)104     public void setSelection(int position) {
105         if (mPosition == position) {
106             return;
107         }
108         mPosition = position;
109         notifyChanged();
110     }
111 
112 
113     @Override
onBindViewHolder(PreferenceViewHolder holder)114     public void onBindViewHolder(PreferenceViewHolder holder) {
115         super.onBindViewHolder(holder);
116         final SettingsSpinner spinner = (SettingsSpinner) holder.findViewById(R.id.spinner);
117         spinner.setAdapter(mAdapter);
118         spinner.setSelection(mPosition);
119         spinner.setOnItemSelectedListener(mOnSelectedListener);
120         if (mShouldPerformClick) {
121             mShouldPerformClick = false;
122             // To show dropdown view.
123             spinner.performClick();
124         }
125     }
126 
127     private final AdapterView.OnItemSelectedListener mOnSelectedListener =
128             new AdapterView.OnItemSelectedListener() {
129         @Override
130         public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
131             if (mPosition == position) return;
132             mPosition = position;
133             if (mListener != null) {
134                 mListener.onItemSelected(parent, view, position, id);
135             }
136         }
137 
138         @Override
139         public void onNothingSelected(AdapterView<?> parent) {
140             if (mListener != null) {
141                 mListener.onNothingSelected(parent);
142             }
143         }
144     };
145 }
146