RestrictedDropDownPreference.java revision 38e4e5dca62fabaf20ea3c72a23a8e784d4aa186
1/*
2 * Copyright (C) 2016 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
17package com.android.settings.notification;
18
19import android.content.Context;
20import android.graphics.drawable.Drawable;
21import android.support.v7.preference.DropDownPreference;
22import android.support.v7.preference.PreferenceViewHolder;
23import android.util.AttributeSet;
24import android.view.View;
25import android.view.ViewGroup;
26import android.widget.AdapterView;
27import android.widget.AdapterView.OnItemSelectedListener;
28import android.widget.ArrayAdapter;
29import android.widget.Spinner;
30import android.widget.TextView;
31
32import com.android.settings.R;
33import com.android.settingslib.RestrictedLockUtils;
34import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
35import com.android.settingslib.RestrictedPreferenceHelper;
36
37import java.util.ArrayList;
38import java.util.List;
39
40public class RestrictedDropDownPreference extends DropDownPreference {
41    private final RestrictedPreferenceHelper mHelper;
42    private ReselectionSpinner mSpinner;
43    private List<RestrictedItem> mRestrictedItems = new ArrayList<>();
44    private boolean mUserClicked = false;
45    private OnPreferenceClickListener mPreClickListener;
46
47    public RestrictedDropDownPreference(Context context, AttributeSet attrs) {
48        super(context, attrs);
49        setLayoutResource(R.layout.restricted_preference_dropdown);
50        setWidgetLayoutResource(R.layout.restricted_icon);
51        mHelper = new RestrictedPreferenceHelper(context, this, attrs);
52    }
53
54    @Override
55    protected ArrayAdapter createAdapter() {
56        return new RestrictedArrayItemAdapter(getContext());
57    }
58
59    @Override
60    public void setValue(String value) {
61        if (getRestrictedItemForEntryValue(value) != null) {
62            return;
63        }
64        super.setValue(value);
65    }
66
67    @Override
68    public void onBindViewHolder(PreferenceViewHolder view) {
69        mSpinner = (ReselectionSpinner) view.itemView.findViewById(R.id.spinner);
70        mSpinner.setPreference(this);
71        super.onBindViewHolder(view);
72        mHelper.onBindViewHolder(view);
73        mSpinner.setOnItemSelectedListener(mItemSelectedListener);
74        final View restrictedIcon = view.findViewById(R.id.restricted_icon);
75        if (restrictedIcon != null) {
76            restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
77        }
78    }
79
80    private boolean isRestrictedForEntry(CharSequence entry) {
81        if (entry == null) {
82            return false;
83        }
84        for (RestrictedItem item : mRestrictedItems) {
85            if (entry.equals(item.entry)) {
86                return true;
87            }
88        }
89        return false;
90    }
91
92    private RestrictedItem getRestrictedItemForEntryValue(CharSequence entryValue) {
93        if (entryValue == null) {
94            return null;
95        }
96        for (RestrictedItem item : mRestrictedItems) {
97            if (entryValue.equals(item.entryValue)) {
98                return item;
99            }
100        }
101        return null;
102    }
103
104    private RestrictedItem getRestrictedItemForPosition(int position) {
105        if (position < 0 || position >= getEntryValues().length) {
106            return null;
107        }
108        CharSequence entryValue = getEntryValues()[position];
109        return getRestrictedItemForEntryValue(entryValue);
110    }
111
112    public void addRestrictedItem(RestrictedItem item) {
113        mRestrictedItems.add(item);
114    }
115
116    public void clearRestrictedItems() {
117        mRestrictedItems.clear();
118    }
119
120    @Override
121    public void performClick() {
122        if (mPreClickListener != null && mPreClickListener.onPreferenceClick(this)) {
123            return;
124        }
125        if (!mHelper.performClick()) {
126            mUserClicked = true;
127            super.performClick();
128        }
129    }
130
131    @Override
132    public void setEnabled(boolean enabled) {
133        if (enabled && isDisabledByAdmin()) {
134            mHelper.setDisabledByAdmin(null);
135            return;
136        }
137        super.setEnabled(enabled);
138    }
139
140    public void setDisabledByAdmin(EnforcedAdmin admin) {
141        if (mHelper.setDisabledByAdmin(admin)) {
142            notifyChanged();
143        }
144    }
145
146    /**
147     * Similar to {@link #setOnPreferenceClickListener(OnPreferenceClickListener)}, but can
148     * preempt {@link #onClick()}.
149     */
150    public void setOnPreClickListener(OnPreferenceClickListener l) {
151        mPreClickListener = l;
152    }
153
154    public boolean isDisabledByAdmin() {
155        return mHelper.isDisabledByAdmin();
156    }
157
158    private void setUserClicked(boolean userClicked) {
159        mUserClicked = userClicked;
160    }
161
162    private boolean isUserClicked() {
163        return mUserClicked;
164    }
165
166    private final OnItemSelectedListener mItemSelectedListener = new OnItemSelectedListener() {
167        @Override
168        public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
169            if (mUserClicked) {
170                mUserClicked = false;
171            } else {
172                return;
173            }
174            if (position >= 0 && position < getEntryValues().length) {
175                String value = getEntryValues()[position].toString();
176                RestrictedItem item = getRestrictedItemForEntryValue(value);
177                if (item != null) {
178                    RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
179                            item.enforcedAdmin);
180                    mSpinner.setSelection(findIndexOfValue(getValue()));
181                } else if (!value.equals(getValue()) && callChangeListener(value)) {
182                    setValue(value);
183                }
184            }
185        }
186
187        @Override
188        public void onNothingSelected(AdapterView<?> parent) {
189            // noop
190        }
191    };
192
193    /**
194     * Extension of {@link ArrayAdapter} which updates the state of the dropdown item
195     * depending on whether it is restricted by the admin.
196     */
197    private class RestrictedArrayItemAdapter extends ArrayAdapter<String> {
198        private static final int TEXT_RES_ID = android.R.id.text1;
199        public RestrictedArrayItemAdapter(Context context) {
200            super(context, R.layout.spinner_dropdown_restricted_item, TEXT_RES_ID);
201        }
202
203        @Override
204        public View getDropDownView(int position, View convertView, ViewGroup parent) {
205            View rootView = super.getView(position, convertView, parent);
206            CharSequence entry = getItem(position);
207            boolean isEntryRestricted = isRestrictedForEntry(entry);
208            TextView text = (TextView) rootView.findViewById(TEXT_RES_ID);
209            if (text != null) {
210                text.setEnabled(!isEntryRestricted);
211            }
212            View restrictedIcon = rootView.findViewById(R.id.restricted_icon);
213            if (restrictedIcon != null) {
214                restrictedIcon.setVisibility(isEntryRestricted ? View.VISIBLE : View.GONE);
215            }
216            return rootView;
217        }
218    }
219
220    /**
221     * Extension of {@link Spinner} which triggers the admin support dialog on user clicking a
222     * restricted item even if was already selected.
223     */
224    public static class ReselectionSpinner extends Spinner {
225        private RestrictedDropDownPreference pref;
226
227        public ReselectionSpinner(Context context, AttributeSet attrs) {
228            super(context, attrs);
229        }
230
231        public void setPreference(RestrictedDropDownPreference pref) {
232            this.pref = pref;
233        }
234
235        @Override
236        public void setSelection(int position) {
237            int previousSelectedPosition = getSelectedItemPosition();
238            super.setSelection(position);
239            if (position == previousSelectedPosition && pref.isUserClicked()) {
240                pref.setUserClicked(false);
241                RestrictedItem item = pref.getRestrictedItemForPosition(position);
242                if (item != null) {
243                    RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(),
244                            item.enforcedAdmin);
245                }
246            }
247        }
248    }
249
250    public static class RestrictedItem {
251        public final CharSequence entry;
252        public final CharSequence entryValue;
253        public final EnforcedAdmin enforcedAdmin;
254
255        public RestrictedItem(CharSequence entry, CharSequence entryValue,
256                EnforcedAdmin enforcedAdmin) {
257            this.entry = entry;
258            this.entryValue = entryValue;
259            this.enforcedAdmin = enforcedAdmin;
260        }
261    }
262}